9

这是我通过反汇编语句看到的function(1,2,3);

movl   $0x3,0x8(%esp)
movl   $0x2,0x4(%esp)
movl   $0x1,(%esp)
call   0x4012d0 <_Z8functioniii>

似乎ret地址根本没有压入堆栈,那么它是如何ret工作的?

4

4 回答 4

10

在 x86 处理器上(对于您的汇编语言示例),call指令将返回地址压入堆栈并将控制权转移给函数。

因此,在进入函数时,堆栈指针指向返回地址,准备将ret其弹出到程序计数器(EIP / RIP)中。


并非所有处理器架构都将返回地址放在堆栈上——通常有一组一个或多个寄存器设计用于保存返回地址。在 ARM 处理器上,该BL指令将返回地址放在特定寄存器(LR或“链接寄存器”)中,并将控制权转移给函数。

ia64 处理器做了类似的事情,除了有几个可能的寄存器(b0- b7)可以接收返回地址,并且将在指令中指定一个(b0默认)。

于 2010-03-30T05:35:43.310 回答
6

理想情况下,该call语句应该照顾到这一点。程序计数器的下一个位置将被压入堆栈。当被调用的函数(子例程)完成它的工作并且遇到返回语句时,控件现在转到被压入堆栈的地址,它将被弹出。

于 2010-03-30T05:02:34.507 回答
3

call这取决于 ABI 和体系结构,但如果返回地址确实最终在堆栈上,那是把它放在那里的指令的副作用。

于 2010-03-30T05:01:59.457 回答
1

call将 RIP 寄存器的当前值(返回地址)推送到堆栈 + call
ret是否从堆栈顶部(RSP 寄存器指向那里)弹出返回地址(被推送的调用)并将其写入 RIP 寄存器。

GNU/Linux 机器上的示例:函数 f 调用函数 g 并查看 g 的框架。

低地址

... <- RSP(堆栈指针显示堆栈顶部)寄存器指向此地址
g 的本地变量
f 的基指针(旧 RBP 值)<- RBP(基指针)寄存器指向此地址
f 的 ret 地址(旧 RIP 值) (这是调用(来自 f)推送的内容,以及ret(来自 g)将弹出的内容)
f 调用 g 并且不适合寄存器的参数(我认为在 Windows 上这是不同的)
...

高地址

g 将释放本地变量 (movq %rsp, %rbp)
g 将弹出“旧 RBP”并将其存储在 RBP 寄存器中 (pop %rbp)
g 将ret将使用存储在 RSP 指向的值修改 RIP在

希望能帮助到你

于 2014-06-05T12:45:56.270 回答