因为昨天接女朋友,所以中间休息一天。下面继续学习。
1.函数调用
保存现场-->传递参数-->返回
调用函数时:
将被调用函数所需参数从右至左压入栈中。(具体调用还是有区别的,后面再详细说)
call指令调用函数,并将下一条指令当作返回值压入栈中(该操作含在call指令)
被调用函数会先保存调用函数的栈底地址(在高地址保存即push ebp),然后将调用函数的栈顶地址(mov ebp,esp)
被调函数的从ebp开始保存局部变量和临时变量(即先定义的变量先入栈)
执行完成后将返回地址弹出,ebp弹出恢复上一个函数状态。
2.函数调用
x86调用主要有三种:cdel(C规范调用),stdcall(win API调用),fastcall
cdel:函数从右到左调用,调用着实现栈平衡,返回值放入EAX (即将参数压入栈后进行堆栈平衡)
int cdecl_sum = cdecl_add(1, 2, 3, 4, 5, 6, 7);
00401138 push 7
0040113A push 6
0040113C push 5
0040113E push 4
00401140 push 3
00401142 push 2
00401144 push 1
00401146 call @ILT+5(_cdecl_add) (0040100a)
0040114B add esp,1Ch # 栈平衡
0040114E mov dword ptr [ebp-4],eax # 返回值
int __cdecl cdecl_add(int a, int b, int c, int d, int e, int f, int g)
4: {
00401030 push ebp
00401031 mov ebp,esp
00401033 sub esp,44h
00401036 push ebx
00401037 push esi
00401038 push edi
00401039 lea edi,[ebp-44h]
0040103C mov ecx,11h
00401041 mov eax,0CCCCCCCCh
00401046 rep stos dword ptr [edi]
5: int sum = a+b+c+d+e+f+g;
00401048 mov eax,dword ptr [ebp+8]
0040104B add eax,dword ptr [ebp+0Ch]
0040104E add eax,dword ptr [ebp+10h]
00401051 add eax,dword ptr [ebp+14h]
00401054 add eax,dword ptr [ebp+18h]
00401057 add eax,dword ptr [ebp+1Ch]
0040105A add eax,dword ptr [ebp+20h]
0040105D mov dword ptr [ebp-4],eax
dword ptr【ebp-4】,eax 把eax值赋给偏移ebp-4的双字
6: return sum;
00401060 mov eax,dword ptr [ebp-4] # 存放返回值
7: }
00401063 pop edi
00401064 pop esi
00401065 pop ebx
00401066 mov esp,ebp
00401068 pop ebp
00401069 ret
stdcall 参数从右至左入栈,被调用者平衡堆栈,返回值放入eax
int stdcall_sum = stdcall_add(1, 2, 3, 4, 5, 6, 7);
00401151 push 7
00401153 push 6
00401155 push 5
00401157 push 4
00401159 push 3
0040115B push 2
0040115D push 1
0040115F call @ILT+15(_stdcall_add@28) (00401014)
00401164 mov dword ptr [ebp-8],eax # 返回值
9: int __stdcall stdcall_add(int a, int b, int c, int d, int e, int f, int g)
10: {
00401080 push ebp
00401081 mov ebp,esp
00401083 sub esp,44h
00401086 push ebx
00401087 push esi
00401088 push edi
00401089 lea edi,[ebp-44h]
0040108C mov ecx,11h
00401091 mov eax,0CCCCCCCCh
00401096 rep stos dword ptr [edi]
11: int sum = a+b+c+d+e+f+g;
00401098 mov eax,dword ptr [ebp+8]
0040109B add eax,dword ptr [ebp+0Ch]
0040109E add eax,dword ptr [ebp+10h]
004010A1 add eax,dword ptr [ebp+14h]
004010A4 add eax,dword ptr [ebp+18h]
004010A7 add eax,dword ptr [ebp+1Ch]
004010AA add eax,dword ptr [ebp+20h]
004010AD mov dword ptr [ebp-4],eax
12: return sum;
004010B0 mov eax,dword ptr [ebp-4] # 存放返回值
13: }
004010B3 pop edi
004010B4 pop esi
004010B5 pop ebx
004010B6 mov esp,ebp
004010B8 pop ebp
004010B9 ret 1Ch # 栈平衡(等价于先 add esp, 1Ch 再 ret)
x64函数调用:
只使用fastcall调用
参数1,2,3,4,5,6分别保存在RDI,RSI,RCX,RDX,R8D,R9D之中。剩下的保存到栈,被调用者平衡堆栈。返回值放入RAX之中。
从右至左入栈,最后四个按R9D R8D顺序入栈
如有this指针存放如RCX
# 该代码是 msvc 2017 x64 生成的汇编代码
int sum = calc.thiscall_add(1, 2, 3, 4, 5, 6, 7);
00007FF602E6190F mov dword ptr [rsp+38h],7
00007FF602E61917 mov dword ptr [rsp+30h],6
00007FF602E6191F mov dword ptr [rsp+28h],5
00007FF602E61927 mov dword ptr [rsp+20h],4
00007FF602E6192F mov r9d,3
00007FF602E61935 mov r8d,2
00007FF602E6193B mov edx,1
00007FF602E61940 lea rcx,[calc] # this指针
00007FF602E61944 call Calc::thiscall_add (07FF602E610A0h)
00007FF602E61949 mov dword ptr [sum],eax # 返回值
int Calc::thiscall_add(int a, int b, int c, int d, int e, int f, int g)
{
00007FF602E61770 mov dword ptr [rsp+20h],r9d
00007FF602E61775 mov dword ptr [rsp+18h],r8d
00007FF602E6177A mov dword ptr [rsp+10h],edx
00007FF602E6177E mov qword ptr [rsp+8],rcx
00007FF602E61783 push rbp
00007FF602E61784 push rdi
00007FF602E61785 sub rsp,0E8h
00007FF602E6178C mov rbp,rsp
00007FF602E6178F mov rdi,rsp
00007FF602E61792 mov ecx,3Ah
00007FF602E61797 mov eax,0CCCCCCCCh
00007FF602E6179C rep stos dword ptr [rdi]
00007FF602E6179E mov rcx,qword ptr [rsp+108h]
int sum = a + b + c + d + e + f + g;
00007FF602E617A6 mov eax,dword ptr [b]
00007FF602E617AC mov ecx,dword ptr [a]
00007FF602E617B2 add ecx,eax
00007FF602E617B4 mov eax,ecx
00007FF602E617B6 add eax,dword ptr [c]
00007FF602E617BC add eax,dword ptr [d]
00007FF602E617C2 add eax,dword ptr [e]
00007FF602E617C8 add eax,dword ptr [f]
00007FF602E617CE add eax,dword ptr [g]
00007FF602E617D4 mov dword ptr [sum],eax
return sum;
00007FF602E617D7 mov eax,dword ptr [sum] # 存放返回值
}
00007FF602E617DA lea rsp,[rbp+0E8h]
00007FF602E617E1 pop rdi
00007FF602E617E2 pop rbp
00007FF602E617E3 ret # 没做栈平衡 (注意此处)
ARM:
参数1-4放入R0-R3,剩下参数从右至左依次入栈,被调用者平衡堆栈。返回值放入R0
ARM x64
(str 类似与mov)
参数1~参数8 分别保存到 X0~X7 寄存器中 ,剩下的参数从右往左依次入栈,被调用者实现栈平衡,返回值存放在 X0 中。