I'm learning (and re-learning) C and assembly, and I came across a difference between what I've been taught and the actual result I have.
Some code:
int test(int a, int b){
return a + b;
}
int main(){
test(1,2);
}
As you can see, it's a really simple example in which I try to understand how values are passed around function.
I've been taught that to pass variable to functions, the values must be pushed to the stack, in reverse order, to be accessible then with the base pointer, something like (simplified writing):
-- main
...
mov [esp+8] 0x02
mov [esp] 0x01
call 0x... <test>
...
And then you can get back those values directly from the stack using:
-- test
...
mov esi [esp+8]
add esi [esp]
mov eax esi
...
I'm perfectly OK with this (although I may not have understood everything), but what is strange to me is the practical result I get when playing with it in 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.
Here, instead of using the stack directly, the two values I'm passing to the function test
are stored in the registers esi
and edi
(corresponding lines marked with ->
).
Here's my setup:
$ 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".
...
My two questions are:
- Is this behavior related to my setup?
- Is it documented anywhere?