如何在堆栈中指定返回地址?

时间:2010-03-30 04:59:21

标签: assembly stack calling-convention

这是我通过反汇编看到的function(1,2,3);声明:

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

似乎 ret地址根本没有被推入堆栈,那么ret如何运作?

4 个答案:

答案 0 :(得分:6)

在x86处理器上(与汇编语言示例一样),call指令将堆栈上的返回地址推送并将控制转移到函数。

并非所有处理器体系结构都将返回地址放在堆栈上 - 通常有一组一个或多个寄存器用于保存返回地址。在ARM处理器上,BL指令将返回地址放在特定寄存器(LR或“链接寄存器”)中,并将控制转移到该函数。 ia64处理器执行类似的操作,但有几个可能的寄存器(b0 - b7)可以接收返回地址,一个将在指令中指定(b0是默认)。

答案 1 :(得分:5)

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

答案 2 :(得分:3)

这取决于ABI和体系结构,但如果返回地址确实在堆栈上结束,那么call指令就会产生副作用。

答案 3 :(得分:1)

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

GNU / Linux盒子上的示例:函数f调用函数g,让我们看一下g的框架。

低地址

...&lt; - RSP(堆栈指针显示堆栈顶部)寄存器点在此地址
g当地的vars f的基址指针(旧RBP值)&lt; - RBP(基址指针)寄存器指向此地址
f的转发地址(旧的RIP值)(这是调用(来自f)推送的内容,以及 ret (来自g)将弹出的内容)<登记/> 那个叫做g并且不适合寄存器的args(我认为在Windows上这是不同的)
......

高级地址

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

希望有所帮助