反彙編分析遞迴和自己彙編實現
阿新 • • 發佈:2021-11-13
彙編遞迴
這次通過簡單的遞迴來分析遞迴對應的彙編
遞迴求前n項和
描述
求序列的前n項和。輸入一個整數n,輸出1+2+3+4+...+n的前n項和。
輸入輸出示例
輸入
5
輸出
15(1+2+3+4+5)
c語言實現程式碼
#include "stdafx.h" int sum(int n) { if(n==1) { return n; } else { return n+sum(n-1); } } int main(int argc, char* argv[]) { int result; result = sum(5); printf("result = %d",result); return 0; }
實驗結果
sum函式的反彙編程式碼
sum函式的反彙編程式碼簡單分析
main函式的反彙編程式碼
main函式的反彙編程式碼的簡單分析
關鍵程式碼的提取
sum函授的關鍵程式碼提取
7: if(n==1) 00401038 cmp dword ptr [ebp+8],1 0040103C jne sum+23h (00401043) 8: { 9: return n; 0040103E mov eax,dword ptr [ebp+8] 00401041 jmp sum+37h (00401057) 10: } 11: else 12: { 13: return n+sum(n-1); 00401043 mov eax,dword ptr [ebp+8] 00401046 sub eax,1 00401049 push eax 0040104A call @ILT+5(sum) (0040100a) 0040104F add esp,4 00401052 mov ecx,dword ptr [ebp+8] 00401055 add eax,ecx
自己用匯編語言實現
#include "stdafx.h" int sum(int n){ int address=(int)sum; int result; __asm{ _if: cmp n,1 //比較引數n和1 jne _else //如果引數n不等於1則跳轉到_else段 _match: mov eax,1 //將1賦值給eax mov result,eax //將eax賦值給result,結合上面相當於mov result,1 jmp _ret //絕對跳轉到_ret段 _else: mov eax,n //將引數n賦值給eax dec eax //讓eax自減1,相當於eax=eax-1,結合上面相當於eax=引數n-1 push eax //將eax作為引數壓入堆疊 call address //呼叫函式自身 add esp,4 //堆疊外平衡 add eax,n //相當於eax=eax+n mov result,eax //將eax賦值給result _ret: } return result; } int main(int argc, char* argv[]) { int result=sum(5); printf("%d\n",result); return 0; }
程式碼分析
這次的自寫的函式沒有使用裸函式,而是直接在程式碼中插入彙編程式碼
1.獲取函式的地址
int address=(int)sum;
因為在彙編中需要呼叫函式本身,所以需要函式的地址
2.宣告一個變數用於儲存返回值
int result;
3.宣告四個程式碼段
_if段:對應if(n1)的程式碼段
_match段:對應n1後執行的程式碼段
_else段:對應else的程式碼段
_ret段:對應返回後的程式碼段,這裡為空,採用了c和asm混編的寫法,後面直接就是return result
程式碼段的詳細註釋已在上面給出,這裡不再贅述
總結
遞迴函式和普通函式的反彙編其實並沒用什麼特別大的出入,只不過在函式內部呼叫的函式是自身
函式呼叫的優先順序較其它運算更高(呼叫函式也可以看作是一種運算),在彙編語句中可以看到是先呼叫了函式然後再進行的加法
遞迴函式如果沒有正確返回就會不斷向堆疊中壓入引數,就會導致所謂的遞迴棧溢位