调用堆栈中的参数在局部变量之上而不是在 return 地址之下?

Arguments in call stack above locals instead of below return address?

我正在尝试通过一些实际示例了解函数的调用堆栈。在解释这一点的所有图表中,它的布局类似于 [Local variables][Return Address][Arguments](左侧的低内存)。但是当我在 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

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

编辑:示例 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 变量、局部变量和 return 地址的地址。

Why are the arguments of the function at lower memory addresses than both the local variables and the return pointer? All literature on the subject (...) imply that the arguments should be at higher memory address than the return address?

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

Passing Once arguments are classified, the registers get assigned (in left-to-right order) for passing as follows:

  1. If the class is MEMORY, pass the argument on the stack.
  2. If the class is INTEGER, the next available register of the sequence %rdi, %rsi, %rdx, %rcx, %r8 and %r9 is used.

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

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

参数 arg1arg2arg3 被传递到寄存器 rdirsirdx 中的 func1 .