【问题标题】:Arguments in call stack above locals instead of below return address? [duplicate]调用堆栈中的参数高于本地而不是低于返回地址? [复制]
【发布时间】:2022-01-20 14:35:37
【问题描述】:

我试图通过一些实际示例来了解函数的调用堆栈。在所有解释这一点的图表中,它的布局类似于 [局部变量][返回地址][参数](左侧内存不足)。但是当我在 gdb 中并在函数中设置断点时,我会以不同的顺序获取它们:

(gdb) info args
arg1 = 0
arg2 = 0
arg3 = 32767
(gdb) p &arg1
0x7ffff3a4697ec
(gdb) p &arg2
0x7ffff3a4697e8
(gdb) p &arg3
0x7ffff3a4697e4
(gdb) info locals
local1 = 0
local2 = 0
local3 = 0
(gdb) p &local1
0x7ffff3a4697fc
(gdb) p &local2
0x7ffff3a4697f8
(gdb) p &local3
0x7ffff3a4697f4
(gdb) info frame
Stack level 0, frame at 0x7ffff3a469810:
...
Arglist at 0x7ffff3a469800, args: arg1=0, arg2=0, arg3=32767
Locals at 0x7ffff3a469800, Previous frame's sp is 0x7ffff3a469810
Saved registers:
 rbp at 0x7ffff3a469800, rip at 0x7ffff3a469808

为什么函数的参数位于比局部变量和返回指针低的内存地址?所有关于该主题的文献(例如像https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Call_stack_layout.svg/342px-Call_stack_layout.svg.png 这样的图表)都暗示参数应该位于比返回地址更高的内存地址?返回地址应该在本地和参数之间,而我在一个连续的块中有本地和参数,最后是返回地址。非常感谢 - 如果我完全误解了,我们深表歉意!

编辑:生成此代码的示例 C 程序:

#include <stdio.h>

void func1(int arg1, int arg2, int arg3) {
  int local1;
  int local2;
  int local3;
  local1 = 2;
  local2 = 3;
  local3 = 4;
}

int main(){
  int a;
  int b;
  int c;
  func1(a, b, c);
}

在 CentOS x86_64 上使用 gcc code.c -o code 编译此代码。使用 gdb 运行并在 func1 中放置一个断点。查看 arg 变量的地址、局部变量和返回地址。

【问题讨论】:

  • 您链接到的图片没有说明任何地址的值。
  • 栈顶通常表示低内存地址;如果你想要i.stack.imgur.com/Z5cSh.jpg,这里有另一张图片明确说明了这一点
  • Spectre... ;)
  • 这只是一个在 Centos x86 上用 gcc(无参数)编译的简单 c 程序
  • @InnocentBystander 用 C 源代码更新了帖子

标签: c assembly x86-64 callstack stack-memory


【解决方案1】:

为什么函数的参数位于比局部变量和返回指针低的内存地址?所有关于该主题的文献 (...) 都暗示参数应该位于比返回地址更高的内存地址?

由于您使用的是 x86_64 ABI,前 6 个参数通常会在寄存器中传递。以下是来自System V Application Binary Interface AMD64 Architecture Processor Supplement 的相关引用(第 20 页,重点是我的,感谢@KamilCuk 提供链接):

传递 一旦参数被分类,寄存器被分配(从左到右 order) 传递如下:

  1. 如果类是 MEMORY,则在堆栈上传递参数。
  2. 如果类是 INTEGER,则使用序列 %rdi、%rsi、%rdx、%rcx、%r8 和 %r9 的下一个可用寄存器。

所以,最有可能发生的情况是您在 func1main 之间混合堆栈帧。看看这段代码:

https://godbolt.org/z/88rPebqYj

参数 arg1arg2arg3 在寄存器 rdirsirdx 中传递给 func1

【讨论】:

  • 这是有道理的——没有意识到 x86_64 的情况如此不同!谢谢!
  • @Trimble52 你打赌。谢谢你让我弯曲我的耳间腺。 ;)
  • @Trimble52 如果您将-m32 添加到您的编译器,您将获得x86 代码和您期望的答案。见这里:godbolt.org/z/WK4hPPEW5
  • 这是一个调试版本 (-O0),因此编译器将传入的寄存器 args 溢出到堆栈中,并碰巧将它们放在本地变量之下。 @Trimble52 在比本地或 args 更高的地址处找到返回地址,因此他们没有查看 main 的堆栈帧。所以它是Why are parameters allocated below the frame pointer instead of above? 的副本。但是是的,关键是注册 args。
猜你喜欢
  • 2017-11-11
  • 1970-01-01
  • 2017-01-06
  • 2011-10-15
  • 2014-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多