gpt4 book ai didi

c - 为什么函数堆栈帧中的参数、变量和帧指针之间存在间隙?

转载 作者:太空宇宙 更新时间:2023-11-03 23:58:59 26 4
gpt4 key购买 nike

我有以下 C 程序:

void function(int a, int b, int c) {
char buffer1[]="aaaaa";
char buffer2[]="bbbbbbbbbb";
}
int main() {
function(1,2,3);
return 0;

当我在执行函数时打印帧信息时,我得到以下 gdb 输出:

(gdb) info frame
Stack level 0, frame at 0x7fffffffe1c0:
rip = 0x40119b in function (ss1.c:4); saved rip = 0x4011ca
called by frame at 0x7fffffffe1d0
source language c.
Arglist at 0x7fffffffe1b0, args: a=1, b=2, c=3
Locals at 0x7fffffffe1b0, Previous frame's sp is 0x7fffffffe1c0
Saved registers:
rbp at 0x7fffffffe1b0, rip at 0x7fffffffe1b8
(gdb)

当打印函数参数和局部变量的地址时,我得到:

(gdb) p/x &c
$65 = 0x7fffffffe184
(gdb) p/x &b
$66 = 0x7fffffffe188
(gdb) p/x &a
$67 = 0x7fffffffe18c
(gdb) p/x &buffer1
$68 = 0x7fffffffe197
(gdb) p/x &buffer2
$69 = 0x7fffffffe19d
  1. 为什么 arg a 的地址和 var buffer1 的地址之间有 11 个字节的间隙 - 而不仅仅是 a 大小的 4 个字节的间隙?

  2. 为什么 buffer2 的地址和帧指针 (0x7fffffffe1b0) 之间有 19 个字节的间隙 - 而不仅仅是 buffer2 大小的 11 个字节的间隙?

谢谢

最佳答案

这应该让您走上正确的道路,但没有回答实际的差距:

  • 堆栈向下增长,你正试图向上阅读它
  • 您看到的 &a&b&c 不是传递的参数,而是可以使用的本地存储(例如) 你在 function() 中说 a=1。我相信如果你不这样做,这些会得到优化 -O0
  • abc 是通过寄存器而不是堆栈传递给函数的,因此您不会在其中找到它们两次。 IE。调用者不会将它们压入堆栈。
  • buffer1buffer2 在堆栈中未对齐,并作为字符串打包在一起。

例如在 buffer2 之后(之前),您可以找到保存的 RBP 值,然后是返回地址。对我来说:

(gdb) p &buffer1
$102 = (char (*)[6]) 0x7fffffffde82
(gdb) p &buffer2
$103 = (char (*)[11]) 0x7fffffffde77

(buffer1 结束于 0x7fffffffde87)

然后是保存的RBP:

(gdb) p/x (char [8]) *0x7fffffffde88
$104 = {0xb0, 0xde, 0xff, 0xff, 0xff, 0x7f, 0x0, 0x0}

然后是返回地址:

(gdb) p/x (char [8]) *0x7fffffffde90
$105 = {0x80, 0x51, 0x55, 0x55, 0x55, 0x55, 0x0, 0x0}

你也可以从 gdb 中看到:

(gdb) info frame
Stack level 0, frame at 0x7fffffffde98:
rip = 0x55555555513f in function (c.c:3); saved rip = 0x555555555180
^^^^^^^^^^^^^^
called by frame at 0x7fffffffdec0
source language c.
Arglist at 0x7fffffffde88, args: a=1, b=2, c=3
Locals at 0x7fffffffde88, Previous frame's sp is 0x7fffffffde98
Saved registers:
rbp at 0x7fffffffde88, rip at 0x7fffffffde90
^^^^^^^^^^^^^^^^^^^^^^

你也可以通过查看汇编代码看到这一点:

gcc -S c.c -o c.s

或者如果你更喜欢英特尔:

gcc -masm=intel -S c.c -o c.s

我不知道为什么 gcc 会留下这个空白:

    mov     DWORD PTR -36[rbp], edi
mov DWORD PTR -40[rbp], esi
mov DWORD PTR -44[rbp], edx
mov DWORD PTR -6[rbp], 1633771873 <-- aaaa
mov WORD PTR -2[rbp], 97 <-- a\0
movabs rax, 7089336938131513954 <-- bbbbbbbb
mov QWORD PTR -17[rbp], rax
mov WORD PTR -9[rbp], 25186 <-- bb
mov BYTE PTR -7[rbp], 0 <-- \0

关于c - 为什么函数堆栈帧中的参数、变量和帧指针之间存在间隙?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52598795/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com