了解以下程序的程序集转储

时间:2012-10-01 18:57:26

标签: c memory x86 arguments

我写了一个用于打印参数的程序

#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个参数,也会采用这种情况..(这会告诉我它所在的内存地址吗?)

2 个答案:

答案 0 :(得分: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并了解它意味着什么是不必要的,与你的目标无关。

答案 1 :(得分:1)

由于您使用gdb进行调试,我想您可能会使用Linux。然后,使用gcc -S -Wall -fverbose-asm foo.c(可能包含-O2等优化标记)来获取更易理解的foo.s程序集文件,假设您的文件为foo.c(如果它是hello.c } foo)替换hello。然后使用编辑器(例如foo.sgedit)查看emacs内部。

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

您可能需要阅读Linux Assembly Howto,例如x86-64 ABIx86 calling convention wikipage。

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