c - Calling convention for function returning struct -


for following c code:

struct _astruct {     int a;     int b;     float c;     float d;     int e; };  typedef struct _astruct astruct;  astruct test_callee5(); void test_caller5();  void test_caller5() {     astruct g = test_callee5();     astruct h = test_callee5();     } 

i following disassembly win32:

_test_caller5:   00000000: lea         eax,[esp-14h]   00000004: sub         esp,14h   00000007: push        eax   00000008: call        _test_callee5   0000000d: lea         ecx,[esp+4]   00000011: push        ecx   00000012: call        _test_callee5   00000017: add         esp,1ch   0000001a: ret 

and linux32:

00000000 <test_caller5>:    0:  push   %ebp    1:  mov    %esp,%ebp    3:  sub    $0x38,%esp    6:  lea    0xffffffec(%ebp),%eax    9:  mov    %eax,(%esp)    c:  call   d <test_caller5+0xd>   11:  sub    $0x4,%esp  ;;;;;;;;;; note sub ;;;;;;;;;;;;   14:  lea    0xffffffd8(%ebp),%eax   17:  mov    %eax,(%esp)   1a:  call   1b <test_caller5+0x1b>   1f:  sub    $0x4,%esp   ;;;;;;;;;; note sub ;;;;;;;;;;;;   22:  leave   23:  ret 

i trying understand difference in how caller behaves after call. why caller in linux32 these subs?

i assume both targets follow cdecl calling convention. doesn't cdecl define calling convention function returning structure?!

edit:

i added implementation of callee. , sure enough, can see linux32 callee pops argument, while win32 callee not:

astruct test_callee5() {     astruct s={0};     return s; } 

win32 disassembly:

test_callee5:   00000000: mov         eax,dword ptr [esp+4]   00000004: xor         ecx,ecx   00000006: mov         dword ptr [eax],0   0000000c: mov         dword ptr [eax+4],ecx   0000000f: mov         dword ptr [eax+8],ecx   00000012: mov         dword ptr [eax+0ch],ecx   00000015: mov         dword ptr [eax+10h],ecx   00000018: ret 

linux32 disassembly:

00000000 <test_callee5>:    0:   push   %ebp    1:   mov    %esp,%ebp    3:   sub    $0x20,%esp    6:   mov    0x8(%ebp),%edx    9:   movl   $0x0,0xffffffec(%ebp)   10:   movl   $0x0,0xfffffff0(%ebp)   17:   movl   $0x0,0xfffffff4(%ebp)   1e:   movl   $0x0,0xfffffff8(%ebp)   25:   movl   $0x0,0xfffffffc(%ebp)   2c:   mov    0xffffffec(%ebp),%eax   2f:   mov    %eax,(%edx)   31:   mov    0xfffffff0(%ebp),%eax   34:   mov    %eax,0x4(%edx)   37:   mov    0xfffffff4(%ebp),%eax   3a:   mov    %eax,0x8(%edx)   3d:   mov    0xfffffff8(%ebp),%eax   40:   mov    %eax,0xc(%edx)   43:   mov    0xfffffffc(%ebp),%eax   46:   mov    %eax,0x10(%edx)   49:   mov    %edx,%eax   4b:   leave   4c:   ret    $0x4  ;;;;;;;;;;;;;; note ;;;;;;;;;;;;;; 

why caller in linux32 these subs?

the reason use of hidden pointer (named return value optimization), injected compiler, returning struct value. in systemv's abi, page 41, in section "function returning structures or unions", says:

the called function must remove address stack before returning.

that why ret $0x4 @ end of test_callee5(), compliance abi.

now presence of sub $0x4, %esp after each test_callee5() call sites, side-effect of above rule, combined optimized code generated c compiler. local storage stack space pre-reserved entirely by:

3:  sub    $0x38,%esp 

there no need push/pop hidden pointer, written @ bottom of pre-reserved space (pointed @ esp), using mov %eax,(%esp) @ lines 9 , 17. stack pointer not decremented, sub $0x4,%esp there negate effect of ret $0x4, , keep stack pointer unchanged.

on win32 (using msvc compiler guess), there no such abi rule, simple ret used (as expected in cdecl), hidden pointer pushed on stack @ line 7 , 11. though, slots not freed after calls, optimization, before callee exits, using add esp,1ch, freeing hidden pointer stack slots (2 * 0x4 bytes) , local astructstruct (0x14 bytes).

doesn't cdecl define calling convention function returning structure?!

unfortunately, not, varies c compilers , operating systems


Comments

Popular posts from this blog

javascript - Enclosure Memory Copies -

php - Replacing tags in braces, even nested tags, with regex -