栈中的返回地址是如何指定的?

发布于 2024-08-27 01:18:04 字数 248 浏览 10 评论 0原文

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

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

看起来 ret 地址 根本没有压入堆栈,那么怎么办? ret 工作吗?

This is what I see by disassemble for the statement function(1,2,3);:

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

It seems the ret address is not pushed into stack at all,then how does ret work?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

浪漫之都 2024-09-03 01:18:04

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

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


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

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

On an x86 processor (as for your assembly language example), the call instruction pushes the return address on the stack and transfers control to the function.

So on entry to a function, the stack pointer is pointing at a return address, ready for ret to pop it into the program counter (EIP / RIP).


Not all processor architectures put the return address on the stack- often there's a set of one or more registers designed to hold return addresses. On ARM processors, the BL instruction places the return address in a specific register (LR, or the 'link register') and transfers control to the function.

The ia64 processor does something similar, except that there are several possible registers (b0-b7) that can receive the return address and one will be specified in the instruction (with b0 being the default).

∝单色的世界 2024-09-03 01:18:04

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

Ideally, the call statement should take care of that. The program counter's next location will be pushed into the stack. When the function (sub routine) that was called completes it work and when it encounters a return statement, the control now goes to the address that was pushed into the stack and it will get popped.

冷夜 2024-09-03 01:18:04

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

It depends on the ABI and the architecture, but if the return address does end up on the stack it's a side-effect of the call instruction that puts it there.

九歌凝 2024-09-03 01:18:04

调用将RIP寄存器的当前值(返回地址)压入堆栈+执行调用
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

希望它有帮助

call pushes the current value of the RIP register (return address) to the stack + does the call
ret pops the return address(that call pushed) from the top of the stack (RSP register points there) and writes it in the RIP register.

Example on a GNU/Linux box: function f calls function g and lets look at the frame of g.

LOW ADDRESS

... <- RSP (stack pointer shows top of stack) register points at this address
g's local vars
f's base pointer (old RBP value) <- RBP (base pointer) register points at this address
f's ret address (old RIP value) (this is what the call (from f) pushed, and what the ret (from g) will pop)
args that f called g with and didn't fit in the registers (I think on Windows this is different)
...

HIGH ADDRESS

g will free the local vars (movq %rsp, %rbp)
g will pop the "old RBP" and store it in RBP register (pop %rbp)
g will ret, which will modify RIP with the value that is stored where RSP points at

Hope it helps

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文