In all of the calling conventions explained, the return value is stored in a 32-bit register (EAX). What happens when the return value does not fit in a 32-bit register? Write a program to experiment and evaluate your answer. Does the mechanism change from compiler to compiler?
Here is a C function which returns a value that is a 128-bit struct:
struct toolong {
int a;
int b;
int c;
int d;
};
struct toolong get_toolong()
{
struct toolong t;
t.a = 0xDABBAD00;
t.b = 0xDEADBEEF;
t.c = 0xBADF00D;
t.d = 0xBA5EBA11;
return t;
}
Here is what happens when it is compiled with: gcc -O3 -m32
; GCC 4.8.2
get_toolong:
mov eax, dword ptr [esp+0x4]
mov dword ptr [eax], 0xdabbad00
mov dword ptr [eax+0x4], 0xdeadbeef
mov dword ptr [eax+0x8], 0xbadf00d
mov dword ptr [eax+0xc], 0xba5eba11
ret 0x4
It is obvious that the return value of EAX is actually a pointer. The returned struct is stored on the stack.
The compiler for Microsoft Visual Studio 2013 produced essentially the same assembly, but with a full function frame. It was compiled with: /GS- /Gd /Gy /Ox
; MSVC 17.00.60610.1
get_toolong:
push ebp
mov ebp, esp
mov eax, [ebp + 8]
mov dword ptr [eax], 0DABBAD00h
mov dword ptr [eax + 4], 0DEADBEEFh
mov dword ptr [eax + 8], 0BADF00Dh
mov dword ptr [eax + 0Ch], 0BA5EBA11h
pop ebp
retn
Notice that the GCC compiler stores the struct at [ESP + 4] and MSVC at [EBP + 8]. This means space needs to be pre-allocated by the caller for each.
No comments :
Post a Comment