反汇编分析递归和自己汇编实现
汇编递归
这次通过简单的递归来分析递归对应的汇编
递归求前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
代码段的详细注释已在上面给出,这里不再赘述
总结
递归函数和普通函数的反汇编其实并没用什么特别大的出入,只不过在函数内部调用的函数是自身
函数调用的优先级较其它运算更高(调用函数也可以看作是一种运算),在汇编语句中可以看到是先调用了函数然后再进行的加法
递归函数如果没有正确返回就会不断向堆栈中压入参数,就会导致所谓的递归栈溢出