我试图编程一个简单的循环,调用自己,并跟踪它的循环次数。 当我踏过它时,一旦 ECX
里面的点击率为0 recursive PROC
,它跳到 RET
里面 L1
- 我以为0之后会回到 main PROC
我的理解是,当一个过程被调用时,它会将指令指针推到堆栈上,然后当 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中得到 "无源代码可用 "的页面。
如果我打印出 eax
在 main
紧接着 CALL recursive
我得到 5
所以你的代码 是否 回归 main
. 问题是,你的 main
缺少一个 ret
. 也就是说,应该改成。
main PROC
mov eax, 0
mov ecx, constant
CALL recursive
ret
main ENDP
因为你的程序应该在这里结束 你也可以使用Win32函数 invoke ExitProcess,0
而不是 ret
.
你最初的回答的问题是,在递归调用你的函数后,返回地址已经被递归函数推送到堆栈上埋没了。每次调用时,包含过程的返回地址都会被推到栈上,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