1. 程式人生 > 其它 >反彙編分析遞迴和自己彙編實現

反彙編分析遞迴和自己彙編實現

彙編遞迴

這次通過簡單的遞迴來分析遞迴對應的彙編

遞迴求前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段:對應n
1後執行的程式碼段
_else段:對應else的程式碼段
_ret段:對應返回後的程式碼段,這裡為空,採用了c和asm混編的寫法,後面直接就是return result
程式碼段的詳細註釋已在上面給出,這裡不再贅述

總結

遞迴函式和普通函式的反彙編其實並沒用什麼特別大的出入,只不過在函式內部呼叫的函式是自身

函式呼叫的優先順序較其它運算更高(呼叫函式也可以看作是一種運算),在彙編語句中可以看到是先呼叫了函式然後再進行的加法

遞迴函式如果沒有正確返回就會不斷向堆疊中壓入引數,就會導致所謂的遞迴棧溢位