如有以下code demo:
include
int max(int a,int b)
{
return a>b?a:b;
}
int main()
{
int c = max(3,4);
return 0;
}
函数调用和返回会分别用到call和ret两个汇编指令。
8: int c = max(3,4);
00401088 push 4
0040108A push 3
0040108C call @ILT+0(max) (00401005)
00401091 add esp,8
00401094 mov dword ptr [ebp-4],eax
……………………………………………………………………………………
@ILT+0(?max@@YAHHH@Z):
00401005 jmp max (00401020)
……………………………………………………………………………………
2: int max(int a,int b)
3: {
00401020 push ebp
00401021 mov ebp,esp
00401023 sub esp,44h
00401026 push ebx
00401027 push esi
00401028 push edi
00401029 lea edi,[ebp-44h]
0040102C mov ecx,11h
00401031 mov eax,0CCCCCCCCh
00401036 rep stos dword ptr [edi]
4: return a>b?a:b;
00401038 mov eax,dword ptr [ebp+8]
0040103B cmp eax,dword ptr [ebp+0Ch]
0040103E jle max+28h (00401048)
00401040 mov ecx,dword ptr [ebp+8]
00401043 mov dword ptr [ebp-4],ecx
00401046 jmp max+2Eh (0040104e)
00401048 mov edx,dword ptr [ebp+0Ch]
0040104B mov dword ptr [ebp-4],edx
0040104E mov eax,dword ptr [ebp-4]
5: }
00401051 pop edi
00401052 pop esi
00401053 pop ebx
00401054 mov esp,ebp
00401056 pop ebp
00401057 ret
1 call addr
Switches active frame to callee function. Equivalent to:
push %eip // eip保存指令目标地址
mov addr, %eip
//代码效果参考:http://www.zidongmutanji.com/bxxx/27882.html
2 ret
Restores active frame to caller function. Equivalent to:
pop %eip
(每执行一个指令,都会更新%eip的值。)
3 push S
Pushes a copy of S onto the top of the stack. Equivalent to:
sub $4, %esp
mov S, (%esp)
4 pop D
Pops the top element off the stack and places it in location D. Equivalent to:
mov (%esp), D
add $4, %esp
(push、pop、call、ret都会更新%esp的值,也就是栈指针偏移。)
5 递归函数
先看一个while循环:
int sumDown(int n) { // iterative version
int total = 0;
int i = n;
while (i > 0) {
total += i;
i--;
}
return total;
}
两个汇编跳转指令构成一个while循环:
6: while (i > 0) { // iterative version
00401045 cmp dword ptr [ebp-8],0
00401049 jle sumDown+3Fh (0040105f) // 条件跳转至return前
7: total += i;
0040104B mov ecx,dword ptr [ebp-4]
0040104E add ecx,dword ptr [ebp-8]
00401051 mov dword ptr [ebp-4],ecx
8: i--;
00401054 mov edx,dword ptr [ebp-8]
00401057 sub edx,1
0040105A mov dword ptr [ebp-8],edx
9: }
0040105D jmp sumDown+25h (00401045) // 无跳转跳转回while语句:
10: return total;
0040105F mov eax,dword ptr [ebp-4]
11: }
将while改写为goto版本:
int sumIf(int n){ // goto version
int total = 0;
int i = n;
restart:
if(i<=0)
goto end;
total +=i;
i--;
goto restart;
end:
return total;
}
对应的汇编同样由几个跳转汇编指令构成:
6: restart:
7: if(i<=0)
00401095 cmp dword ptr [ebp-8],0
00401099 jg restart+8 (0040109d)
8: goto end;
0040109B jmp end+5 (004010b6)
9: total +=i;
0040109D mov ecx,dword ptr [ebp-4]
004010A0 add ecx,dword ptr [ebp-8]
004010A3 mov dword ptr [ebp-4],ecx
10: i--;
004010A6 mov edx,dword ptr [ebp-8]
004010A9 sub edx,1
004010AC mov dword ptr [ebp-8],edx
11: goto restart;
004010AF jmp restart (00401095)
12: end:
13: return total;
004010B1 mov eax,dword ptr [ebp-4]
004010B4 jmp end+7 (004010b8)
14: }
004010B6 jmp end (004010b1)
004010B8 pop edi
递归版本:
int sumr(int n) {
if (n <= 0) {
return 0;
}
return n + sumr(n-1);
}
对应的汇编:
13: int c = sumr(36);
0040D4C8 push 24h
0040D4CA call @ILT+35(sumr) (00401028) // call启动
………………………………………………………………………………
4: if (n <= 0) {
00401088 cmp dword ptr [ebp+8],0
0040108C jg sumr+22h (00401092)
5: return 0;
0040108E xor eax,eax
00401090 jmp sumr+36h (004010a6) // call 结束,ret 开始
6: }
7: return n + sumr(n-1); // 按条件call,且参数构成迭代:n = n-1
00401092 mov eax,dword ptr [ebp+8]
00401095 sub eax,1
00401098 push eax
00401099 call @ILT+30(sumDownIf) (00401023)
0040109E add esp,4
004010A1 mov ecx,dword ptr [ebp+8]
004010A4 add eax,ecx
8: }
004010A6 pop edi
004010A7 pop esi
004010A8 pop ebx
004010A9 add esp,40h
004010AC cmp ebp,esp
004010AE call __chkesp (004010c0)
004010B3 mov esp,ebp
004010B5 pop ebp
004010B6 ret // ret
迭代版本同goto版本一样,通过条件判断不断构成跳转,形成循环:
call……call……call…………ret……ret……ret…………
在不断的call中,参数可以构成迭代:n = n-1
在不断的ret中,返回结果存储在%eax寄存器(在非递归版本中使用临时变量total保存)。