0

我已经编写了用于打印参数的 ac 程序

#include<stdio.h>
void main( int argc, char *argv[])
{
int i=0;
for(i=0;i<argc;i++)
printf("argument %d=%s\n",i,argv[i]);
}

我得到的使用 gdb 的上述程序的程序集转储是。

Dump of assembler code for function main:
0x00000000004004f4 <+0>:    push   %rbp
0x00000000004004f5 <+1>:    mov    %rsp,%rbp
0x00000000004004f8 <+4>:    sub    $0x20,%rsp
0x00000000004004fc <+8>:    mov    %edi,-0x14(%rbp)
0x00000000004004ff <+11>:   mov    %rsi,-0x20(%rbp)
0x0000000000400503 <+15>:   movl   $0x0,-0x4(%rbp)
0x000000000040050a <+22>:   movl   $0x0,-0x4(%rbp)
0x0000000000400511 <+29>:   jmp    0x40053e <main+74>
0x0000000000400513 <+31>:   mov    -0x4(%rbp),%eax
0x0000000000400516 <+34>:   cltq   
0x0000000000400518 <+36>:   shl    $0x3,%rax
0x000000000040051c <+40>:   add    -0x20(%rbp),%rax
0x0000000000400520 <+44>:   mov    (%rax),%rdx
0x0000000000400523 <+47>:   mov    $0x40063c,%eax
0x0000000000400528 <+52>:   mov    -0x4(%rbp),%ecx
0x000000000040052b <+55>:   mov    %ecx,%esi
0x000000000040052d <+57>:   mov    %rax,%rdi
0x0000000000400530 <+60>:   mov    $0x0,%eax
0x0000000000400535 <+65>:   callq  0x4003f0 <printf@plt>
0x000000000040053a <+70>:   addl   $0x1,-0x4(%rbp)
0x000000000040053e <+74>:   mov    -0x4(%rbp),%eax
0x0000000000400541 <+77>:   cmp    -0x14(%rbp),%eax
0x0000000000400544 <+80>:   jl     0x400513 <main+31>
0x0000000000400546 <+82>:   leaveq 
0x0000000000400547 <+83>:   retq   
End of assembler dump.

现在我想要的是“参数传递的内存位置(地址)。例如,如果我将程序作为“arg 1”运行,它会打印参数。现在我想知道它在哪条指令上提取这个参数,或者哪个寄存器保存参数(如果我传递超过 1 个参数,也采用这种情况。(这会告诉我它所在的内存地址吗?)

4

2 回答 2

2

我想知道它在哪条指令上提取这个参数,或者哪个寄存器保存参数

最好通过获取目标机器的汇编语言参考手册并研究它来回答这类问题。但是,您的具体问题很容易通过考试来回答,而无需非常熟悉汇编语言的细节:

0x0000000000400503 <+15>:   movl   $0x0,-0x4(%rbp)
0x000000000040050a <+22>:   movl   $0x0,-0x4(%rbp)

这是为冗余i = 0语句生成的代码。

0x0000000000400513 <+31>:   mov    -0x4(%rbp),%eax

的值i现在在 %eax 寄存器中。

0x0000000000400518 <+36>:   shl    $0x3,%rax
0x000000000040051c <+40>:   add    -0x20(%rbp),%rax

这将计算地址argv[i]并将其放入 %rax 寄存器中。

0x0000000000400520 <+44>:   mov    (%rax),%rdx

这会将 的值加载argv[i]到 %rdx 寄存器中。printf使用iargv[i]作为参数的调用后的代码。

现在我想要的是“参数传递的内存位置(地址)。

您无法通过查看 asm 来确定这一点,就像通过查看 asm 无法确定 argc 的值一样……这些值会有所不同,并且仅在实际运行程序时才确定。如果要在运行时确定地址,可以使用

printf("address of argv = %p\n", (void*)argv);

如果这就是你想要的,那么抛弃 asm 并了解它的含义是不必要的,并且与你的目标无关。

于 2012-10-01T19:52:16.403 回答
1

由于您gdb用于调试,我想您可能使用Linux。然后,假设您的文件是(如果它被替换为),使用gcc -S -Wall -fverbose-asm foo.c(可能与优化标志如 然后使用编辑器(如或)查看内部。-O2foo.sfoo.chello.cfoohellofoo.sgeditemacs

Andmain几乎是一个普通的函数(除了它的签名必须是标准允许的,例如int main(int argc, char**argv)......)并且它被调用crt0.o(编译gcc -v以了解哪个)。

您可能想阅读Linux Assembly Howto,例如x86-64 ABIx86 调用约定wikipage。

请注意,如果没有任何优化标志(例如-O1-O2),gcc编译器会生成非常幼稚的代码。

于 2012-10-01T19:00:05.883 回答