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

Assembly 如何在堆栈中指定返回地址?,assembly,x86,stack,calling-convention,Assembly,X86,Stack,Calling Convention,这就是我通过反汇编语句函数(1,2,3)看到的结果: movl$0x3,0x8(%esp) movl$0x2,0x4(%esp) movl$0x1,(%esp) 调用0x4012d0 看来ret地址根本没有被推入堆栈,那么ret是如何工作的呢?这取决于ABI和体系结构,但如果返回地址最终出现在堆栈上,则是将其放入堆栈的调用指令的副作用。理想情况下,调用语句应该考虑到这一点。程序计数器的下一个位置将被推入堆栈。当调用的函数(子程序)完成其工作时,当它遇到返回语句时,该控件现在转到推送到堆栈中的地

这就是我通过反汇编语句
函数(1,2,3)看到的结果

movl$0x3,0x8(%esp)
movl$0x2,0x4(%esp)
movl$0x1,(%esp)
调用0x4012d0

看来ret地址根本没有被推入堆栈,那么
ret
是如何工作的呢?

这取决于ABI和体系结构,但如果返回地址最终出现在堆栈上,则是将其放入堆栈的
调用
指令的副作用。

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

在x86处理器上(对于您的汇编语言示例),该指令将返回地址推送到堆栈上,并将控制转移到函数

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


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


ia64处理器执行类似的操作,只是有几个可能的寄存器(
b0
-
b7
)可以接收返回地址,并且指令中将指定一个(默认值为
b0
)。

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

GNU/Linux机器上的示例:函数f调用函数g,让我们看看g的框架

低位地址


。。。那么,
call
是如何处理的呢?我只想看看ret地址是在哪里指定的。您将把call方法分解为进一步的十六进制代码。为特定处理器指定的指令集备忘单将揭示这一点。例如,如果使用最简单的微处理器8085,则ADD X指令不会显示第二个值(假设Y与ADD X,Y类似)。相反,它会将值X添加到处理器内的某个保留寄存器(如H)中,并将值存储在H中。如果存在溢出位,则会将其存储在另一个寄存器中。这就是ADD指令的设计方式。CALL指令也将具有类似的预定义规则。CALL指令的任务之一是将返回地址推送到堆栈上。返回地址就是直接位于调用指令参数之后的地址。要查看上面示例中的返回地址,您必须在程序进入0x4012d0的过程后立即查看堆栈。@Mask,您可以认为返回地址是作为存储在IP/EIP寄存器中的调用指令的地址传递的。当处理器收到下一条指令及其调用指令(远/短等)时,它可以将指令的大小添加到IP并将其推送到堆栈(SP寄存器),这样做会将IP的值更改为与调用指令一起传递的适当地址参考(短为相对,远为绝对,基于寄存器等)。还有,这个问题还没有得到认可的答案吗?。。
movl   $0x3,0x8(%esp)
movl   $0x2,0x4(%esp)
movl   $0x1,(%esp)
call   0x4012d0 <_Z8functioniii>