Assembly 为什么此代码会导致程序集中出现infinte循环
我在Assemby中有一小段代码,它基本上是通过循环运行的,并以相反的顺序打印值,但当我运行时,它会转到infinte循环。下面是代码Assembly 为什么此代码会导致程序集中出现infinte循环,assembly,x86,Assembly,X86,我在Assemby中有一小段代码,它基本上是通过循环运行的,并以相反的顺序打印值,但当我运行时,它会转到infinte循环。下面是代码 section .data x db "value=%d" section .text global main extern printf main: mov eax, 10 well_done: push eax push x call printf add esp,8 dec eax cmp eax ,0 jnz well_done ret 调用函数时,
section .data
x db "value=%d"
section .text
global main
extern printf
main:
mov eax, 10
well_done:
push eax
push x
call printf
add esp,8
dec eax
cmp eax ,0
jnz well_done
ret
调用函数时,必须确定使用了哪些寄存器。如果调用C函数,
eax
可以用于函数需要的任何功能,因此在执行函数之前必须push eax
,在函数返回后,可以pop
执行它
section .data
x db "value=%d"
section .text
global main
extern printf
main:
mov eax, 10
well_done:
push eax <- save the counter
push eax <- argument for printf
push x
call printf
add esp,8 <- clears the stack with the arguments for printf
pop eax <- restore the counter
dec eax
cmp eax ,0
jnz well_done
ret
section.data
x db“值=%d”
第节.案文
全球主要
外部打印
主要内容:
mov-eax,10
干得好:
推eax谢谢大家的帮助。这就是我按照哈罗德的建议所做的。谢谢哈罗德
section .data
x db "value=%d"
section .text
global main
extern printf
main:
mov ebx, 10
well_done:
push ebx
push x
call printf
add esp,4
pop ebx
dec ebx
cmp ebx ,0
jnz well_done
ret
由于注释太长,我只想把它放在这里:我使用被叫保存寄存器的意思是这样的
section .data
x db "value=%d"
section .text
global main
extern printf
main:
mov ebx, 10
well_done:
push ebx
push x
call printf
add esp, 8
dec ebx
jnz well_done
ret
请注意,通常使用ebx
意味着您应该在进入时保存ebx
,并在退出时将其还原,但由于这是main
,因此我们可以不这样做。有推送但没有弹出?eax
是调用方保存在cdecl中,printf
可能正在扼杀它的生命value@kerrek我想知道为什么在这种特殊情况下需要pop。我不知道-我不是说我理解它,我只是注意到了不对称性。无论如何,你不能从中恢复它,一个函数可能会修改它的参数-这不太常见,但你不能真正依赖它。您可以两次按下eax(显然在调用后弹出),或者使用被调用方保存寄存器,如ebx
,总之@Devolus使用寄存器eax对我来说也很好,用eax替换ebx没有什么区别。这实际上不是我想要的,我的意思是使用ebx
,然后不恢复它,你不必还原它,printf本身必须还原ebx,是的,我知道。我不知道有这样的被调用方保存约定存在。就“返回值不会被推送,而是在eax中执行(在大多数情况下是这样)”,我相信在执行任何调用printf的地方,它要做的第一件事就是将返回推送到堆栈,而不是改变esp,这是Peter Wright在年告诉我的在这个问题的答案中。你想说些同样的话吗。哦,回信地址,是的,一个呼叫
按下按钮,然后跳转。一个ret
弹出地址*并跳转到它。*它弹出某个内容并将其解释为一个地址,而不管它是否实际是一个有效的地址。那么更改ESP呢?将调用push来更改ESP吗?最后一点,为什么在代码中添加esp,8是必需的,无论如何ebx的值为10,我们可以使用它,而无需将esp指向正确的位置。call
和ret
changeesp
yesadd esp,8
是清除您给出的参数printf
(与stdcall不同,在cdecl中,调用者清除堆栈)。您可以暂时不清理堆栈,但是最后一个ret
将弹出错误的东西,可能会崩溃。如果循环更长,堆栈溢出也可能成为一个问题。再次感谢Harold的友好输入,这将对我今后的工作有很大帮助。