Recursion 这个函数中LEA指令的用途是什么?整个递归是做什么的?
我一直在尝试解决以下递归函数的功能:Recursion 这个函数中LEA指令的用途是什么?整个递归是做什么的?,recursion,assembly,x86,Recursion,Assembly,X86,我一直在尝试解决以下递归函数的功能: func4: 0x08048cfa <+0>: push edi 0x08048cfb <+1>: push esi 0x08048cfc <+2>: push ebx 0x08048cfd <+3>: mov ebx,DWORD PTR [esp+0x10] // First arg 0x08048d01 <+7>: mov edi,DWORD
func4:
0x08048cfa <+0>: push edi
0x08048cfb <+1>: push esi
0x08048cfc <+2>: push ebx
0x08048cfd <+3>: mov ebx,DWORD PTR [esp+0x10] // First arg
0x08048d01 <+7>: mov edi,DWORD PTR [esp+0x14] // Second arg
0x08048d05 <+11>: test ebx,ebx // if (ebx == 0) { eax = 0; return ???;}
0x08048d07 <+13>: jle 0x8048d34 <func4+58>
0x08048d09 <+15>: mov eax,edi
0x08048d0b <+17>: cmp ebx,0x1 // if (ebx == 1) {return ???;}
0x08048d0e <+20>: je 0x8048d39 <func4+63>
0x08048d10 <+22>: sub esp,0x8
0x08048d13 <+25>: push edi
0x08048d14 <+26>: lea eax,[ebx-0x1]// eax = ebx-1
0x08048d17 <+29>: push eax
0x08048d18 <+30>: call 0x8048cfa <func4>
0x08048d1d <+35>: add esp,0x8 // esp += 8
0x08048d20 <+38>: lea esi,[edi+eax*1] // esi = edi + eax
0x08048d23 <+41>: push edi
0x08048d24 <+42>: sub ebx,0x2 // ebx -= 2
0x08048d27 <+45>: push ebx
0x08048d28 <+46>: call 0x8048cfa <func4>
0x08048d2d <+51>: add esp,0x10 // esp += 10
0x08048d30 <+54>: add eax,esi // eax += esi
0x08048d32 <+56>: jmp 0x8048d39 <func4+63>
0x08048d34 <+58>: mov eax,0x0 // eax = 0
0x08048d39 <+63>: pop ebx
0x08048d3a <+64>: pop esi
0x08048d3b <+65>: pop edi
0x08048d3c <+66>: ret
func4:
0x08048cfa:推式edi
0x08048cfb:推送esi
0x08048cfc:推动ebx
0x08048cfd:mov ebx,DWORD PTR[esp+0x10]//第一个参数
0x08048d01:mov edi,DWORD PTR[esp+0x14]//第二个参数
0x08048d05:测试ebx,ebx//if(ebx==0){eax=0;返回???;}
0x08048d07:jle 0x8048d34
0x08048d09:mov eax,edi
0x08048d0b:cmp-ebx,0x1//if(ebx==1){return???;}
0x08048d0e:je 0x8048d39
0x08048d10:子esp,0x8
0x08048d13:推式edi
0x08048d14:lea-eax[ebx-0x1]//eax=ebx-1
0x08048d17:推送eax
0x08048d18:调用0x8048cfa
0x08048d1d:添加esp,0x8//esp+=8
0x08048d20:lea esi[edi+eax*1]//esi=edi+eax
0x08048d23:推送edi
0x08048d24:子ebx,0x2//ebx-=2
0x08048d27:推送ebx
0x08048d28:调用0x8048cfa
0x08048d2d:添加esp,0x10//esp+=10
0x08048d30:添加eax,esi//eax+=esi
0x08048d32:jmp 0x8048d39
0x08048d34:mov-eax,0x0//eax=0
0x08048d39:pop ebx
0x08048d3a:pop esi
0x08048d3b:pop edi
0x08048d3c:ret
到目前为止,我已经发现它需要ebx,递减1,将其传递回自身并递归,直到它到达一个基本情况,然后继续递归的下一步。然而,我还没有完全理解递归的那个分支做了什么,或者esp
在这个上下文中做了什么
有关于如何进行的提示吗?我已经在gdb中使用过很多次了,但是没有真正注意到任何类型的模式可以帮助我确定发生了什么。您似乎不知道结果会在
eax
寄存器中返回。考虑到这一点,代码并不难理解。假设使用了cdecl调用约定(因为调用方清理了堆栈),它与此js函数相同:
function func4(a, b)
{
if (a <= 0) return 0;
if (a == 1) return b;
return b + func4(a-1, b) + func4(a-2, b);
}
函数func4(a,b)
{
如果(alea
在这里用于简单的算术。与.lea的名称相同,它来自于使用CPU对寻址模式进行解码的能力,而不是因为它仅用于有效指针。我们不知道8086的设计者是什么(斯蒂芬·莫尔斯)当他添加它时,他正在考虑;他可能打算公开将2个reg添加到不同的目的地以供任意使用的能力。@Petercords名称的基(加载有效地址),源必须是内存操作数的要求,以及它不影响标志的事实,并在“地址对象传输”中列出在8086手册的第节中,如果它的初衷不是为了计算地址,我会感到惊讶。当然,除了架构师之外,没有人能确定这一点。但是初衷对程序员来说意义不大;他们总是找到最有效的方法来做事情。xor eax、eax
和或eax,-1
就是一个很好的例子s、 有趣的是,关于它在8086手册中的位置这一部分对我来说是新的。其他因素是我在回答中提到的,我在上面链接了这些,请参见我关于这一点的详细论述。(有趣的一点是,不像其他ALU那样设置标志是设计意图的标志。除非这只是8086中使用地址解码逻辑的实现细节。)不管怎么说,我只是对历史有点感兴趣,主要是对当前指令的最有用的思考。你可以也应该把它看作是一个整数移位和加法,因为386标度索引。@PeterCordes我同意。反正我主要用它来加法。
func4:
0x08048cfa <+0>: push edi ; save non-volatile registers
0x08048cfb <+1>: push esi
0x08048cfc <+2>: push ebx
0x08048cfd <+3>: mov ebx, [esp+0x10] ; ebx <- a
0x08048d01 <+7>: mov edi, [esp+0x14] ; edi <- b
0x08048d05 <+11>: test ebx, ebx ; if (a <= 0)
0x08048d07 <+13>: jle 0x8048d34 ; return 0
0x08048d09 <+15>: mov eax, edi ; result <- 0
0x08048d0b <+17>: cmp ebx, 0x1 ; if (a == 1)
0x08048d0e <+20>: je 0x8048d39 ; return result;
0x08048d10 <+22>: sub esp, 0x8 ; this is useless
0x08048d13 <+25>: push edi ; passing 2nd arguments
0x08048d14 <+26>: lea eax, [ebx-0x1] ;
0x08048d17 <+29>: push eax ; passing 1st arguments
0x08048d18 <+30>: call 0x8048cfa<func4> ; ax = func4(a - 1, b)
0x08048d1d <+35>: add esp, 0x8 ; clean up the stak after calling
0x08048d20 <+38>: lea esi, [edi+eax*1] ; temp = b + func4(a - 1, b)
0x08048d23 <+41>: push edi ; passing 2nd arguments
0x08048d24 <+42>: sub ebx, 0x2 ;
0x08048d27 <+45>: push ebx ; passing 1st arguments
0x08048d28 <+46>: call 0x8048cfa<func4> ; ax = func4(a - 2, b)
0x08048d2d <+51>: add esp, 0x10 ; clean up the stak and the useless 8 bytes
0x08048d30 <+54>: add eax, esi ; result = func4(a - 2, b) + temp
0x08048d32 <+56>: jmp 0x8048d39 ;
0x08048d34 <+58>: mov eax, 0x0 ; jump to here when a <= 0
0x08048d39 <+63>: pop ebx
0x08048d3a <+64>: pop esi
0x08048d3b <+65>: pop edi
0x08048d3c <+66>: ret