我写了一个用于打印参数的程序
#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个参数,也会采用这种情况..(这会告诉我它所在的内存地址吗?)
答案 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
并以i
和argv[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.s
或gedit
)查看emacs
内部。
并且main
几乎是一个普通的函数(除了它的签名必须是标准所允许的,例如int main(int argc, char**argv)
....)并且它由crt0.o
调用(用gcc -v
编译来学习哪一个。
您可能需要阅读Linux Assembly Howto,例如x86-64 ABI和x86 calling convention wikipage。
请注意,如果没有任何优化标志(例如-O1
或-O2
),gcc
编译器会生成非常简单的代码。