我正在尝试编写一个调用自身的简单循环,并跟踪它循环的次数。当我单步执行时,ECX
在recursive PROC
内点击0后,它会跳转到RET
内的L1
- 我认为在0之后会返回main PROC
< / p>
我的理解是,当一个过程被调用时,它会将指令指针推到堆栈上,然后当调用RET
时,它会将其弹出并返回到该点。
; Calls a recursive procedure
;
INCLUDE Irvine32.inc
.data
constant DWORD 5
count DWORD ?
.code
main PROC
mov eax, 0
mov ecx, constant
CALL recursive
main ENDP
recursive PROC
add eax, 1
loop L1
ret
L1:
CALL recursive
ret
recursive ENDP
END main
当我从RET
中取出L1
时,我会在Visual S 2013中找到“无可用源代码”页面。
答案 0 :(得分:0)
如果我在eax
main
之后立即在CALL recursive
打印5
的值,那么我的代码会返回{ {1}}。问题是您的main
缺少main
。也就是说,它应该改为:
ret
由于这是你的程序应该结束的地方,你也可以使用Win32函数main PROC
mov eax, 0
mov ecx, constant
CALL recursive
ret
main ENDP
而不是invoke ExitProcess,0
。
答案 1 :(得分:0)
最初答案的问题是,在递归调用函数之后,返回地址已被递归函数压入堆栈而被掩埋。每次执行调用时,将包含过程的返回地址压入堆栈,并使ESP递减。如果我们不递归地继续递归调用函数,则堆栈将包含所有这些重复的地址,并且ESP指向最后一次调用。
您将需要从堆栈中弹出所有这些递归函数调用,以使ret指令有效。您可以使用调试器验证此行为:
.386
.model flat,stdcall
.stack 4096
includelib Irvine32.lib
includelib User32.lib
include Irvine32.inc
.code
main PROC
mov eax,0
mov ecx,5 ; # calls to perform
call recurs
call WriteInt
INVOKE ExitProcess,0
main ENDP
; input - ecx, parameter for # function calls to perform
; uses ebx as workspace to dump junk from the stack
recurs PROC
loop L1
mov ecx,eax ; we need to keep track of recursive call count.
L2: pop ebx
loop L2
inc eax ; add 1 for the initial call to made to recurs
ret ; ret pops the address currently pointed to by
L1: inc eax ; by ESP into EIP.
call recurs
recurs ENDP
END main