常见的有 eax 传递,也有和 edx 联合返回 如果要返回一个大家伙呢? 首先调用方在栈上开辟一段空间,将这个空间的一部分作为传递返回值的临时对象,这里称为 tmp 将 tmp 对象的地址作为隐藏参数传递给函数 函数将数据拷贝给 tmp 对象,并将对象的地址用 eax 传出 返回之后,调用方将 eax 指向的 tmp 对象的内容拷贝给真正要赋值的对象 (可以优化成直接在函数内赋值了) #include <string.h> typedef struct big_thing { char buf[128]; } big_thing; big_thing return_test() { big_thing b; memcpy(b.buf, "Hello, World!", 13); return b; } int main() { big_thing b = return_test(); return 0; } _QWORD *__fastcall return_test(_QWORD *a1) { __int64 v1; // rbx __int64 v2; // rbx __int64 v3; // rbx __int64 v4; // rbx __int64 v5; // rbx __int64 v6; // rbx __int64 v7; // rbx __int64 v8; // rbx char dest[128]; // [rsp+10h] [rbp-90h] BYREF memcpy(dest, "Hello, World!", 0xDuLL); v1 = *(_QWORD *)&dest[8]; *a1 = *(_QWORD *)dest; a1[1] = v1; v2 = *(_QWORD *)&dest[24]; a1[2] = *(_QWORD *)&dest[16]; a1[3] = v2; v3 = *(_QWORD *)&dest[40]; a1[4] = *(_QWORD *)&dest[32]; a1[5] = v3; v4 = *(_QWORD *)&dest[56]; a1[6] = *(_QWORD *)&dest[48]; a1[7] = v4; v5 = *(_QWORD *)&dest[72]; a1[8] = *(_QWORD *)&dest[64]; a1[9] = v5; v6 = *(_QWORD *)&dest[88]; a1[10] = *(_QWORD *)&dest[80]; a1[11] = v6; v7 = *(_QWORD *)&dest[104]; a1[12] = *(_QWORD *)&dest[96]; a1[13] = v7; v8 = *(_QWORD *)&dest[120]; a1[14] = *(_QWORD *)&dest[112]; a1[15] = v8; return a1; } int __cdecl main(int argc, const char **argv, const char **envp) { char v4[128]; // [rsp+0h] [rbp-80h] BYREF return_test(v4); return 0; } 细究的话就要涉及到 move 了