首页 > 代码库 > 函数堆栈平衡
函数堆栈平衡
int func(int a,int b,int c, int d) { 01243CE0 push ebp 01243CE1 mov ebp,esp 01243CE3 sub esp,0CCh 01243CE9 push ebx 01243CEA push esi 01243CEB push edi 01243CEC lea edi,[ebp-0CCh] 01243CF2 mov ecx,33h 01243CF7 mov eax,0CCCCCCCCh 01243CFC rep stos dword ptr es:[edi] int v; v=a+b+c+d; 01243CFE mov eax,dword ptr [a] 01243D01 add eax,dword ptr [b] 01243D04 add eax,dword ptr [c] 01243D07 add eax,dword ptr [d] 01243D0A mov dword ptr [v],eax return v; 01243D0D mov eax,dword ptr [v] } 01243D10 pop edi 01243D11 pop esi 01243D12 pop ebx 01243D13 mov esp,ebp 01243D15 pop ebp 01243D16 ret int main() { 01241B50 push ebp 01241B51 mov ebp,esp 01241B53 sub esp,0CCh 01241B59 push ebx 01241B5A push esi 01241B5B push edi 01241B5C lea edi,[ebp-0CCh] 01241B62 mov ecx,33h 01241B67 mov eax,0CCCCCCCCh 01241B6C rep stos dword ptr es:[edi] int x; x=func(1,2,3,4); 01241B6E push 4 01241B70 push 3 01241B72 push 2 01241B74 push 1 01241B76 call func (012411EFh) 01241B7B add esp,10h 01241B7E mov dword ptr [x],eax return 0; 01241B81 xor eax,eax } 01241B83 pop edi 01241B84 pop esi 01241B85 pop ebx 01241B86 add esp,0CCh 01241B8C cmp ebp,esp 01241B8E call __RTC_CheckEsp (01241140h) 01241B93 mov esp,ebp 01241B95 pop ebp 01241B96 ret
看上面划线部分,很明显是 _cdecl 调用方式,调用方平衡堆栈。
下面来看看 _stdcall 调用方式,这是被调用方平衡堆栈。
int _stdcall func(int a,int b,int c, int d) { 010C3CE0 push ebp 010C3CE1 mov ebp,esp 010C3CE3 sub esp,0CCh 010C3CE9 push ebx 010C3CEA push esi 010C3CEB push edi 010C3CEC lea edi,[ebp-0CCh] 010C3CF2 mov ecx,33h 010C3CF7 mov eax,0CCCCCCCCh 010C3CFC rep stos dword ptr es:[edi] int v; v=a+b+c+d; 010C3CFE mov eax,dword ptr [a] 010C3D01 add eax,dword ptr [b] 010C3D04 add eax,dword ptr [c] 010C3D07 add eax,dword ptr [d] 010C3D0A mov dword ptr [v],eax return v; 010C3D0D mov eax,dword ptr [v] } 010C3D10 pop edi 010C3D11 pop esi 010C3D12 pop ebx 010C3D13 mov esp,ebp 010C3D15 pop ebp 010C3D16 ret 10h int main() { 010C1B50 push ebp 010C1B51 mov ebp,esp 010C1B53 sub esp,0CCh 010C1B59 push ebx 010C1B5A push esi 010C1B5B push edi 010C1B5C lea edi,[ebp-0CCh] 010C1B62 mov ecx,33h 010C1B67 mov eax,0CCCCCCCCh 010C1B6C rep stos dword ptr es:[edi] int x; x=func(1,2,3,4); 010C1B6E push 4 010C1B70 push 3 010C1B72 push 2 010C1B74 push 1 010C1B76 call func (010C11F4h) 010C1B7B mov dword ptr [x],eax return 0; 010C1B7E xor eax,eax } 010C1B80 pop edi 010C1B81 pop esi 010C1B82 pop ebx 010C1B83 add esp,0CCh 010C1B89 cmp ebp,esp 010C1B8B call __RTC_CheckEsp (010C1140h) 010C1B90 mov esp,ebp 010C1B92 pop ebp 010C1B93 ret
下面看看win下x64(Linux与此不同):
在x64下函数调用的前4个参数总是放在寄存器中传递,剩余的参数则压入堆栈中。
而x86上则是全部压入堆栈中(除了fastcall方式)。这4个用于存放参数的寄存器分别是:
存放整数参数的RCX,RDX,R8,R9。存放浮点数参数的XMM0,XMM1,XMM2,XMM3。
double func3(double a,double b,double c, double d) { 000000013FD83240 movsd mmword ptr [rsp+20h],xmm3 000000013FD83246 movsd mmword ptr [rsp+18h],xmm2 000000013FD8324C movsd mmword ptr [v],xmm1 000000013FD83252 movsd mmword ptr [rsp+8],xmm0 000000013FD83258 push rdi 000000013FD83259 sub rsp,20h 000000013FD8325D mov rdi,rsp 000000013FD83260 mov ecx,8 000000013FD83265 mov eax,0CCCCCCCCh 000000013FD8326A rep stos dword ptr [rdi] double v; v=a+b+c+d; 000000013FD8326C movsd xmm0,mmword ptr [a] 000000013FD83272 addsd xmm0,mmword ptr [b] 000000013FD83278 addsd xmm0,mmword ptr [c] 000000013FD8327E addsd xmm0,mmword ptr [d] 000000013FD83284 movsd mmword ptr [v],xmm0 return v; 000000013FD8328A movsd xmm0,mmword ptr [v] } 000000013FD83290 add rsp,20h 000000013FD83294 pop rdi 000000013FD83295 ret int func2(int a,int b,int c, int d,int e,int f) { 000000013FD832A0 mov dword ptr [a],r9d 000000013FD832A5 mov dword ptr [rsp+18h],r8d 000000013FD832AA mov dword ptr [rsp+10h],edx 000000013FD832AE mov dword ptr [rsp+8],ecx 000000013FD832B2 push rdi 000000013FD832B3 sub rsp,10h 000000013FD832B7 mov rdi,rsp 000000013FD832BA mov ecx,4 000000013FD832BF mov eax,0CCCCCCCCh 000000013FD832C4 rep stos dword ptr [rdi] 000000013FD832C6 mov ecx,dword ptr [a] int v; v=a+b+c+d+e+f; 000000013FD832CA mov eax,dword ptr [b] 000000013FD832CE mov ecx,dword ptr [a] 000000013FD832D2 add ecx,eax 000000013FD832D4 mov eax,ecx 000000013FD832D6 add eax,dword ptr [c] 000000013FD832DA add eax,dword ptr [d] 000000013FD832DE add eax,dword ptr [e] 000000013FD832E2 add eax,dword ptr [f] 000000013FD832E6 mov dword ptr [rsp],eax return v; 000000013FD832E9 mov eax,dword ptr [rsp] } 000000013FD832EC add rsp,10h 000000013FD832F0 pop rdi 000000013FD832F1 ret int func(int a,int b,int c, int d) { 000000013FD83300 mov dword ptr [a],r9d 000000013FD83305 mov dword ptr [rsp+18h],r8d 000000013FD8330A mov dword ptr [rsp+10h],edx 000000013FD8330E mov dword ptr [rsp+8],ecx 000000013FD83312 push rdi 000000013FD83313 sub rsp,10h 000000013FD83317 mov rdi,rsp 000000013FD8331A mov ecx,4 000000013FD8331F mov eax,0CCCCCCCCh 000000013FD83324 rep stos dword ptr [rdi] 000000013FD83326 mov ecx,dword ptr [a] int v; v=a+b+c+d; 000000013FD8332A mov eax,dword ptr [b] 000000013FD8332E mov ecx,dword ptr [a] 000000013FD83332 add ecx,eax 000000013FD83334 mov eax,ecx 000000013FD83336 add eax,dword ptr [c] 000000013FD8333A add eax,dword ptr [d] 000000013FD8333E mov dword ptr [rsp],eax return v; 000000013FD83341 mov eax,dword ptr [rsp] } 000000013FD83344 add rsp,10h 000000013FD83348 pop rdi 000000013FD83349 ret int main() { 000000013FD83350 push rdi 000000013FD83352 sub rsp,40h 000000013FD83356 mov rdi,rsp 000000013FD83359 mov ecx,10h 000000013FD8335E mov eax,0CCCCCCCCh 000000013FD83363 rep stos dword ptr [rdi] int x,y; double z; //4个参数,用RCX、RDX、R8、R9传参 x=func(1,2,3,4); 000000013FD83365 mov r9d,4 000000013FD8336B mov r8d,3 000000013FD83371 mov edx,2 000000013FD83376 mov ecx,1 000000013FD8337B call func (013FD8100Ah) 000000013FD83380 mov dword ptr [x],eax //用4个寄存器+堆栈传参 y=func2(1,2,3,4,5,6); 000000013FD83384 mov dword ptr [rsp+28h],6 000000013FD8338C mov dword ptr [rsp+20h],5 000000013FD83394 mov r9d,4 000000013FD8339A mov r8d,3 000000013FD833A0 mov edx,2 000000013FD833A5 mov ecx,1 000000013FD833AA call func2 (013FD81014h) 000000013FD833AF mov dword ptr [y],eax //XMM0、XMM1、XMM2、XMM3 传参 z=func3(1.0,2.0,3.0,4.0); 000000013FD833B3 movsd xmm3,mmword ptr [__real@4010000000000000 (013FD86CB8h)] 000000013FD833BB movsd xmm2,mmword ptr [__real@4008000000000000 (013FD86A88h)] 000000013FD833C3 movsd xmm1,mmword ptr [__real@4000000000000000 (013FD86918h)] 000000013FD833CB movsd xmm0,mmword ptr [__real@3ff0000000000000 (013FD868B8h)] 000000013FD833D3 call func2 (013FD81019h) 000000013FD833D8 movsd mmword ptr [z],xmm0 return 0; 000000013FD833DE xor eax,eax } 000000013FD833E0 add rsp,40h 000000013FD833E4 pop rdi 000000013FD833E5 ret
下面摘自:http://openwares.net/misc/windows_x64_function_call_convention.html
- 调用函数为前四个参数在调用栈上保留相应的空间,称作shadow space或spill slot。即使被调用方没有或小于4个参数,调用函数仍然保留那么多的栈空间,这有助于在某些特殊情况下简化调用约定。
- 除前四个参数以外的任何其他参数通过栈来传递,从右至左依次入栈。
- 由调用函数负责清理调用栈。
- 小于等于64位的整型或指针类型返回值由RAX传递。
- 浮点返回值由XMM0传递。
- 更大的返回值(比如结构体),由调用方在栈上分配空间,并有RCX持有该空间的指针并传递给被调用函数,因此整型参数使用的寄存器依次右移一格,实际只可以利用3个寄存器,其余参数入栈。函数调用结束后,RAX返回该空间的指针。
- 除RCX,RDX,R8,R9以外,RAX、R10、R11、XMM4 和 XMM5也是易变化的(volatile)寄存器。
- RBX, RBP, RDI, RSI, R12, R14, R14, and R15寄存器则必须在使用时进行保护。
- 在寄存器中,所有参数都是右对齐的。小于64位的参数并不进行高位零扩展,也就是高位是无法预测的垃圾数据。
; int __cdecl main() main proc near var_28= dword ptr -28h ;40 var_20= dword ptr -20h ;32 var_18= dword ptr -18h ;24 x var_14= dword ptr -14h ;20 y var_10= qword ptr -10h ;16 z push rdi sub rsp, 40h ;64 mov rdi, rsp mov ecx, 10h mov eax, 0CCCCCCCCh rep stosd mov r9d, 4 ; d mov r8d, 3 ; c mov edx, 2 ; b mov ecx, 1 ; a call j_?func@@YAHHHHH@Z ; func(int,int,int,int) mov [rsp+48h+var_18], eax ; x mov [rsp+48h+var_20], 6 mov [rsp+48h+var_28], 5 mov r9d, 4 ; d mov r8d, 3 ; c mov edx, 2 ; b mov ecx, 1 ; a call j_?func2@@YAHHHHHHH@Z ; func2(int,int,int,int,int,int) mov [rsp+48h+var_14], eax ; y movsd xmm3, cs:__real@4010000000000000 movsd xmm2, cs:__real@4008000000000000 movsd xmm1, cs:__real@4000000000000000 movsd xmm0, cs:__real@3ff0000000000000 call j_?func2@@YANNNNN@Z ; func2(double,double,double,double) movsd [rsp+48h+var_10], xmm0 ;z xor eax, eax add rsp, 40h pop rdi retn main endp
func2:
int __cdecl func2(int a, int b, int c, int d, int e, int f)
?func2@@YAHHHHHHH@Z proc near
var_18= dword ptr -18h arg_0= dword ptr 8 arg_8= dword ptr 10h arg_10= dword ptr 18h arg_18= dword ptr 20h e= dword ptr 28h f= dword ptr 30h mov [rsp+arg_18], r9d mov [rsp+arg_10], r8d mov [rsp+arg_8], edx mov [rsp+arg_0], ecx push rdi sub rsp, 10h mov rdi, rsp mov ecx, 4 mov eax, 0CCCCCCCCh rep stosd mov ecx, [rsp+18h+arg_0] mov eax, [rsp+18h+arg_8] mov ecx, [rsp+18h+arg_0] add ecx, eax mov eax, ecx add eax, [rsp+18h+arg_10] add eax, [rsp+18h+arg_18] add eax, [rsp+18h+e] add eax, [rsp+18h+f] mov [rsp+18h+var_18], eax mov eax, [rsp+18h+var_18] add rsp, 10h pop rdi retn ?func2@@YAHHHHHHH@Z endp
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。