【发布时间】:2020-06-14 20:05:41
【问题描述】:
我对汇编很陌生,我想知道 ret 的行为。如果我在代码期间从不使用调用,而是在末尾添加一个 ret,则代码只是回到开头。这是不使用呼叫时的默认行为吗?如果我使用了 jmp,如果仍然没有使用调用,那会影响 ret 的行为吗?
【问题讨论】:
我对汇编很陌生,我想知道 ret 的行为。如果我在代码期间从不使用调用,而是在末尾添加一个 ret,则代码只是回到开头。这是不使用呼叫时的默认行为吗?如果我使用了 jmp,如果仍然没有使用调用,那会影响 ret 的行为吗?
【问题讨论】:
call将下一条指令的地址放入调用栈,然后跳转到目标地址。
ret 从调用栈中弹出最后一个地址,然后跳转到这里。好像如果栈是空的,就返回0x00000000,然后跳转到程序的开头。 至少在某些系统中。由于地址空间违规,您不应该使用它。
jmp 对调用堆栈没有影响,所以它不会修改ret 的行为。
编辑:正如@PeterCordes 所写;如果您使用push 或pop,它们可以写入堆栈内存,而ret 会弹出它。
【讨论】:
ret 之前使用了其他指令,例如push,它会弹出您推送的任何内容。 call 不是唯一可以写入堆栈内存的指令。 ret 基本上只是弹出指令指针。
在许多系统中,启动/启动代码实际上调用 main() 函数(或其等效函数),例如使用https://www.nongnu.org/avr-libc/ 的裸机AVR 程序(这样做的好处是编译器可以像其他函数一样将main() 编译为函数,不需要任何特殊处理)。
因此,当您在 main() 中的用户代码执行 ret 时(即使您的用户代码本身从未真正调用 anthing),您的用户代码将从该隐式调用返回,并且启动/启动代码将继续运行。
现在的问题是main() 返回后启动/启动代码的作用。它可能会进入无休止的繁忙循环、停止系统、关闭电源、重新启动等。
【讨论】: