递归汇编代码规律的总结:
Dump of assembler code for function func4:
0x08048c4f <+0>: sub esp,0x1c %开辟栈空间
0x08048c52 <+3>: mov DWORD PTR [esp+0x10],ebx
0x08048c56 <+7>: mov DWORD PTR [esp+0x14],esi
0x08048c5a <+11>: mov DWORD PTR [esp+0x18],edi %edi初值是0,eax初值是外部传入
0x08048c5e <+15>: mov esi,DWORD PTR [esp+0x20] %传入第一个参数
0x08048c62 <+19>: mov ebx,DWORD PTR [esp+0x24] %传入第二个参数
0x08048c66 <+23>: test esi,esi
%如果esi非正数则跳转,return eax = ebx = 0
0x08048c68 <+25>: jle 0x8048c95 <func4+70>
0x08048c6a <+27>: cmp esi,0x1
%如果参数esi等于1跳转,return eax = ebx
0x08048c6d <+30>: je 0x8048c9a <func4+75>
0x08048c6f <+32>: mov DWORD PTR [esp+0x4],ebx
%传入参数ebx,这个值没有改变
0x08048c73 <+36>: lea eax,[esi-0x1]
0x08048c76 <+39>: mov DWORD PTR [esp],eax
%传入参数eax = esi - 1,调用函数func4(s-1,b)
0x08048c79 <+42>: call 0x8048c4f <func4>
0x08048c7e <+47>: lea edi,[eax+ebx*1]
%d = func4(s-1,b) + b
0x08048c81 <+50>: mov DWORD PTR [esp+0x4],ebx
%传入参数ebx,这个值没有改变
0x08048c85 <+54>: sub esi,0x2
0x08048c88 <+57>: mov DWORD PTR [esp],esi
%传入参数esi - 2,调用函数func(s-2,b)
0x08048c8b <+60>: call 0x8048c4f <func4>
0x08048c90 <+65>: lea ebx,[edi+eax*1]
%这里的计算其实就是在计算返回值eax,b = d + func4(s-2,b) = func4(s-1,b) + b + func4(s-2,b)
0x08048c93 <+68>: jmp 0x8048c9a <func4+75>
0x08048c95 <+70>: mov ebx,0x0
0x08048c9a <+75>: mov eax,ebx
%返回的eax的值其实就是ebx,a = b = func4(s-1,b) + b + func4(s-2,b)
0x08048c9c <+77>: mov ebx,DWORD PTR [esp+0x10]
0x08048ca0 <+81>: mov esi,DWORD PTR [esp+0x14]
0x08048ca4 <+85>: mov edi,DWORD PTR [esp+0x18]
0x08048ca8 <+89>: add esp,0x1c
0x08048cab <+92>: ret
递归的汇编代码的讨论:
递归分为以下四步:
- 传递参数
- 调用自身函数
- 对函数进行数学运算
- 返回
下面一个形象的例子以及本题的例子来展示:
0x08048c6f <+32>: mov DWORD PTR [esp+0x4],ebx
%传入参数ebx,这个值没有改变
0x08048c73 <+36>: lea eax,[esi-0x1]
0x08048c76 <+39>: mov DWORD PTR [esp],eax
%传入参数eax = esi - 1,调用函数func4(s-1,b)
0x08048c79 <+42>: call 0x8048c4f <func4>
%以上数传递参数以及函数自身调用
0x08048c7e <+47>: lea edi,[eax+ebx*1]
%d = func4(s-1,b) + b,有些数学运算不像前面的例子那么简单,通常可能多次调用,这里就是
以下是第二次调用,老套路先传递参数
0x08048c81 <+50>: mov DWORD PTR [esp+0x4],ebx
%传入参数ebx,这个值没有改变
0x08048c85 <+54>: sub esi,0x2
0x08048c88 <+57>: mov DWORD PTR [esp],esi
%传入参数esi - 2,调用函数func(s-2,b)
0x08048c8b <+60>: call 0x8048c4f <func4>
%第二次调用函数自身
0x08048c90 <+65>: lea ebx,[edi+eax*1]
%这里的计算其实就是在计算返回值eax,b = d + func4(s-2,b) = func4(s-1,b) + b + func4(s-2,b)
%最后一句是跳转到递归返回return的位置,所以就是直接return计算结果(如果func4+75没有其他对eax进行操作的时候)
0x08048c93 <+68>: jmp 0x8048c9a <func4+75>