首页 > 技术文章 > 反汇编分析递归和自己汇编实现

doubleconquer 2021-11-13 17: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段:对应n
1后执行的代码段
_else段:对应else的代码段
_ret段:对应返回后的代码段,这里为空,采用了c和asm混编的写法,后面直接就是return result
代码段的详细注释已在上面给出,这里不再赘述

总结

递归函数和普通函数的反汇编其实并没用什么特别大的出入,只不过在函数内部调用的函数是自身

函数调用的优先级较其它运算更高(调用函数也可以看作是一种运算),在汇编语句中可以看到是先调用了函数然后再进行的加法

递归函数如果没有正确返回就会不断向堆栈中压入参数,就会导致所谓的递归栈溢出

推荐阅读