32 位 cdecl 处理结构
填充
请记住,结构的成员通常是填充的,以确保它们在自然边界上对齐:
struct t
{
int a, b, c, d; // a is at offset 0, b at 4, c at 8, d at 0ch
char e; // e is at 10h
short f; // f is at 12h (naturally aligned)
long g; // g is at 14h
char h; // h is at 18h
long i; // i is at 1ch (naturally aligned)
};
作为参数(通过引用传递)
通过引用传递时,指向内存中结构的指针将作为堆栈上的第一个参数传递。这相当于传递一个自然大小(32 位)的整数值; 有关详细信息,请参阅 32 位 cdecl 。
作为参数(按值传递)
当通过值传递时,结构完全复制在堆栈上,遵循原始内存布局( 即,第一个成员将位于较低地址)。
int __attribute__((cdecl)) foo(struct t a);
struct t s = {0, -1, 2, -3, -4, 5, -6, 7, -8};
foo(s);
; Assembly call
push DWORD 0fffffff8h ; i (-8)
push DWORD 0badbad07h ; h (7), pushed as DWORD to naturally align i, upper bytes can be garbage
push DWORD 0fffffffah ; g (-6)
push WORD 5 ; f (5)
push WORD 033fch ; e (-4), pushed as WORD to naturally align f, upper byte can be garbage
push DWORD 0fffffffdh ; d (-3)
push DWORD 2 ; c (2)
push DWORD 0ffffffffh ; b (-1)
push DWORD 0 ; a (0)
call foo
add esp, 20h
作为返回值
除非它们是微不足道的 1 ,否则在返回之前将结构体复制到调用者提供的缓冲区中。这相当于隐藏了第一个参数 struct S *retval
(其中 struct S
是结构的类型)。
该函数必须返回此指针,指向 eax
中的返回值; 允许调用者依赖 eax
将指针指向返回值,该指针在 call
之前推动。
struct S
{
unsigned char a, b, c;
};
struct S foo(); // compiled as struct S* foo(struct S* _out)
出于堆栈清理的目的,隐藏参数不会添加到参数计数中,因为它必须由被调用者处理。
sub esp, 04h ; allocate space for the struct
; call to foo
push esp ; pointer to the output buffer
call foo
add esp, 00h ; still as no parameters have been passed
在上面的示例中,结构将保存在堆栈的顶部。
struct S foo()
{
struct S s;
s.a = 1; s.b = -2; s.c = 3;
return s;
}
; Assembly code
push ebx
mov eax, DWORD PTR [esp+08h] ; access hidden parameter, it is a pointer to a buffer
mov ebx, 03fe01h ; struct value, can be held in a register
mov DWORD [eax], ebx ; copy the structure into the output buffer
pop ebx
ret 04h ; remove the hidden parameter from the stack
; EAX = pointer to the output buffer
1 普通结构只包含一个非结构非数组类型的成员(最多 32 位)。对于这样的结构,该成员的值只是在 eax
寄存器中返回。 (在针对 Linux 的 GCC 中观察到此行为)
Windows 版本的 cdecl 与 System V ABI 的调用约定不同:允许普通结构包含最多两个非结构非数组类型的成员(最大为 32 位)。这些值在 eax
和 edx
中返回,就像 64 位整数一样。 (已针对 MSVC 和 Clang 定位 Win32 观察到此行为。)