调用堆栈中的参数高于本地而不是低于返回地址? [复制]
Posted
技术标签:
【中文标题】调用堆栈中的参数高于本地而不是低于返回地址? [复制]【英文标题】: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 源代码更新了帖子 【参考方案1】:为什么函数的参数位于比局部变量和返回指针低的内存地址?所有关于该主题的文献 (...) 都暗示参数应该位于比返回地址更高的内存地址?
由于您使用的是 x86_64 ABI,前 6 个参数通常会在寄存器中传递。以下是来自System V Application Binary Interface AMD64 Architecture Processor Supplement 的相关引用(第 20 页,重点是我的,感谢@KamilCuk 提供链接):
传递 一旦参数被分类,寄存器被分配(从左到右 order) 传递如下:
如果类是 MEMORY,则在堆栈上传递参数。 如果类是 INTEGER,则使用序列 %rdi、%rsi、%rdx、%rcx、%r8 和 %r9 的下一个可用寄存器。
所以,最有可能发生的情况是您在 func1
和 main
之间混合堆栈帧。看看这段代码:
https://godbolt.org/z/88rPebqYj
参数 arg1
、arg2
和 arg3
在寄存器 rdi
、rsi
和 rdx
中传递给 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。以上是关于调用堆栈中的参数高于本地而不是低于返回地址? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
glibc backtrace() 如何确定哪些堆栈内存是返回地址?