我正在学习(并重新学习)C 和汇编,我发现我所教的内容与我的实际结果之间存在差异。
一些代码:
int test(int a, int b){
return a + b;
}
int main(){
test(1,2);
}
如您所见,这是一个非常简单的示例,我试图在其中了解值是如何围绕函数传递的。
我被教导要将变量传递给函数,必须以相反的顺序将值推送到堆栈,然后才能使用基指针访问,例如(简化编写):
-- main
...
mov [esp+8] 0x02
mov [esp] 0x01
call 0x... <test>
...
然后您可以使用以下命令直接从堆栈中取回这些值:
-- test
...
mov esi [esp+8]
add esi [esp]
mov eax esi
...
我对此完全没问题(虽然我可能没有完全理解),但令我感到奇怪的是我在 gdb 中使用它时得到的实际结果:
$ gcc -g stack.c
$ gdb a.out
(gdb) disass main
Dump of assembler code for function main:
0x0000000100000f70 <+0>: push rbp
0x0000000100000f71 <+1>: mov rbp,rsp
0x0000000100000f74 <+4>: sub rsp,0x10
-> 0x0000000100000f78 <+8>: mov edi,0x1
-> 0x0000000100000f7d <+13>: mov esi,0x2
0x0000000100000f82 <+18>: call 0x100000f50 <test>
0x0000000100000f87 <+23>: xor esi,esi
0x0000000100000f89 <+25>: mov DWORD PTR [rbp-0x4],eax
0x0000000100000f8c <+28>: mov eax,esi
0x0000000100000f8e <+30>: add rsp,0x10
0x0000000100000f92 <+34>: pop rbp
0x0000000100000f93 <+35>: ret
End of assembler dump.
(gdb) disass test
Dump of assembler code for function test:
0x0000000100000f50 <+0>: push rbp
0x0000000100000f51 <+1>: mov rbp,rsp
-> 0x0000000100000f54 <+4>: mov DWORD PTR [rbp-0x4],edi
-> 0x0000000100000f57 <+7>: mov DWORD PTR [rbp-0x8],esi
0x0000000100000f5a <+10>: mov esi,DWORD PTR [rbp-0x4]
0x0000000100000f5d <+13>: add esi,DWORD PTR [rbp-0x8]
0x0000000100000f60 <+16>: mov eax,esi
0x0000000100000f62 <+18>: pop rbp
0x0000000100000f63 <+19>: ret
End of assembler dump.
在这里,不是直接使用堆栈,而是将我传递给函数的两个值test存储在寄存器esi和edi(用 标记的相应行->)中。
这是我的设置:
$ gcc -v
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin14.5.0
Thread model: posix
$ gdb --version
GNU gdb (GDB) 7.11.1
...
This GDB was configured as "x86_64-apple-darwin14.5.0".
...
我的两个问题是:
- 这种行为与我的设置有关吗?
- 它在任何地方都有记录吗?