【问题标题】:Why this Code causing infinte loop in assembly为什么此代码在汇编中导致无限循环
【发布时间】:2013-06-11 12:17:01
【问题描述】:

我在 Assemby 中有一小段代码,它基本上是通过循环运行并以相反的顺序打印值,但是当我运行时,它进入无限循环。下面是代码。

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

【问题讨论】:

  • 有推送但没有弹出?
  • eax 是 cdecl 中的 caller-save,printf 可能正在扼杀它的价值
  • @kerrek 我可以知道为什么在这种特殊情况下需要 pop 。
  • 我不知道——我不是声称自己理解它,我只是注意到不对称。
  • 无论如何你都无法从中恢复它,一个函数可能会修改它的参数——这不是很常见,但你不能真正依赖它。你可以push eax 两次(显然在调用后弹出),或者使用像ebx这样的被调用者保存寄存器

标签: assembly x86


【解决方案1】:

由于评论太长,我就放在这里:我的意思是使用被调用者保存寄存器是这样的

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(嗯,在大多数情况下)”,我相信在调用 printf 的地方首先它会推送返回堆栈但不改变 esp,这是 Peter Wright 在“stackoverflow.com/questions/16960337/…”中对这个问题的回答中告诉我的。你想同样说些什么吗?
  • 哦,返回地址,是的,call 推动它然后跳转。 ret 弹出地址* 并跳转到它。 * 它弹出一些东西并将其解释为一个地址,不管它是否实际上是一个有效的地址。
  • 改变 ESP 怎么样??调用推送会改变 esp 吗?最后一点,为什么在你的代码中添加 esp,8 是必需的,无论如何 ebx 的值为 10,我们可以在不将 esp 指向正确位置的情况下使用它。
  • callret 更改 esp 是的。需要add esp, 8 才能摆脱您给printf 的参数(与stdcall 不同,在cdecl 中调用者会清理堆栈)。你可以暂时不清理堆栈,但最后一个ret 会弹出错误的东西并可能崩溃。如果循环更长,堆栈溢出也可能成为问题。
  • 再次感谢 Harold 的热心投入,它将对我的前进有很大帮助。
【解决方案2】:

当你调用一个函数时,你必须确定使用了哪些寄存器。如果你调用一个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

【讨论】:

    【解决方案3】:

    感谢大家的帮助。这就是我按照哈罗德的建议所做的。谢谢哈罗德

    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
    

    【讨论】:

    • 无论如何@Devolus 使用 register eax 对我来说也可以正常工作,用 eax 替换 ebx 没有区别。
    • 这实际上不是我想要的,我的意思是使用ebx然后不恢复它,你不必恢复它printf本身必须恢复ebx
    • @AmitSinghTomar,是的,我知道。我不知道存在这样的被调用者保存约定。
    猜你喜欢
    • 2023-03-24
    • 2020-07-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多