Ubuntu 上的 System V ABI 是否将返回地址放在调用方函数的框架内或被调用方函数的框架内?

Does the System V ABI on Ubuntu place the return address within the caller function's frame or the callee function's frame?

提问人:alessio solari 提问时间:8/28/2023 最后编辑:Peter Cordesalessio solari 更新时间:8/29/2023 访问量:71

问:

我的系统:Ubuntu 22.04.3 在 x86_64上运行。GCC 版本 11.4.0

我之所以问这个问题,是因为就返回地址所在的帧(调用方或被调用方)而言,似乎有两种不同的表示形式。

这就是“计算机系统,程序员的视角”所展示的:

enter image description here

这就是“System V Application Binary Interface AMD64 Architecture Processor Supplement”所显示的内容:

enter image description here

正如您在System V ABI文档表示中看到的,我们在当前帧(called/callee函数)中具有返回地址,但是在book表示中,它在调用者帧(caller函数)中。

这是我的问题:

  1. 什么表述是正确的?

  2. 在特定帧(调用方或被调用方)内并置返回地址是否只是一件任意的愚蠢事情,并且没有被任何 ABI 指定?

程序集 x86-64 内存 abi 堆栈帧

评论

2赞 Eric Postpischil 8/28/2023
两个关系图都显示了指向上一帧指针的当前帧指针,以及位于该指针上方的下一个“地址大小”空间中的返回地址(32 位版本为 4 个字节,64 位版本为 8 个字节)。因此,对于帧指针指向的位置和返回地址的存储位置没有分歧。这些都是重要的事实,因为它们会影响机器(计算机)的行为方式。你是否调用返回地址是一帧或另一帧一部分的空间只是人类使用的名称问题,而不是影响机器的事实......
2赞 Eric Postpischil 8/28/2023
...因此,什么是“堆栈框架”可能没有明确定义。在某种程度上,ABI规范比教科书更具权威性。
2赞 Margaret Bloom 8/28/2023
我想说两者都是正确的。您可以看到,除了字数之外,布局是相同的,因此返回地址是当前帧还是上一帧的正式部分并不重要。就我个人而言,我更喜欢 SYS V 定义,因为调用方可能根本不使用帧,但被调用方仍然会有一个返回地址。
1赞 Bodo 8/28/2023
书中是否指定了该图是否与特定的 ABI 相关?有些架构不会将返回地址放在堆栈上。例如,ARM 使用链接寄存器作为最新的返回地址,想要调用其他函数的函数负责保存和恢复此寄存器。
0赞 alessio solari 8/28/2023
@EricPostpischil stackoverflow.com/questions/76993711/......

答:

3赞 Erik Eidt 8/29/2023 #1

返回地址由调用方推送,但在函数完成并返回给调用方时由被调用方弹出,因此堆栈上的返回地址仅在被调用方激活期间存在。

因为当被调用方返回时,该返回地址被删除,并且调用方看不到或使用它,我认为它不是调用方堆栈帧的一部分。因此,我必须将其视为被调用方框架的一部分

正如其他人所说,这只是语义。重要的是操作(例如,谁弹出)和值(地址指向的位置)。

但是,一般来说,要回答某些东西属于哪个框架的问题,我会问:该存储持续多长时间以及谁将其从堆栈中弹出(即谁真正负责该存储)?

当被调用方返回时,堆栈上剩余的内容属于调用方。

评论

1赞 500 - Internal Server Error 8/29/2023
我同意。这是语义上的,但我认为你不能争辩说被调用方删除的东西属于调用方的堆栈框架。
1赞 Peter Cordes 8/29/2023
@500-InternalServerError :我同意。还有堆栈参数:被调用者“拥有”它们,即可以用不同的值覆盖它们。(GCC 通常不会这样做,但会进行尾部调用。你可以说调用方在指令点将堆栈参数交给被调用方。在 caller-pops 约定中,被叫方交还空格,但不交还值。(无论如何,这是我对语义的最初看法。退货地址更简单;在从调用方跳转的指令之前,它不存在于堆栈上,因此任何调用方代码都无法引用它。call
0赞 Peter Cordes 8/29/2023
即使在具有红色区域的调用约定(如 x86-64 System V)中,调用方也不能假定 upon return 是他们推送的返回地址。一个低效的函数可能会把它弹出到寄存器中,在那里存储其他东西,然后用来返回。ABI 并没有禁止这样做,就像被调用者拥有堆栈参数一样。因此,调用方在ABI保证持有返回地址的情况下,永远不会拥有该堆栈槽的任何所有权。[rsp-8]jmp reg