为什么我在栈中发起的变量之间有一个"gap"?

Why is there a "gap" beween the variables that I initiated in the stack?

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc, char **argv) {
    int modified;
    char buffer[64];

    modified = 0;
    gets(buffer);

    if(modified != 0)
        printf("Changed!");
    else
        printf("Not changed!");
}

我正在尝试解决缓冲区溢出问题。

当程序计数器到达if(modified != 0)时,基址指针为0x00007fffffffdfe0.

在基指针下方,我看到 4 个字节包含有意义的整数 0。

但是,缓冲区不在修改后的 int 正下方。

看起来堆栈中有 4 个字节的 0,然后是 0x00007fff,然后是我输入的 64 个字节的 As。

为什么char buffer[64]不是在int修改之后就来的?为什么会有 "gap"?

我用 gcc -g -fno-stack-protector test1.c -o test1

编译的

谢谢

首先,您应该了解 compiler/linker 可以自由地将 任何 地址分配给您在 'automatic' 范围内声明的变量(即局部于一个函数 - main 只是另一个函数,真的)。

至于 "why" 'zeros' 的 4 个字节在那里 - 这几乎可以肯定是因为,在您使用的平台上,编译器知道对内存的访问效率更高(即更快)当该内存的地址与 八字节 值对齐时 - 所以它 'adds in' 额外的四个字节适当地 'align' 你的地址 buffer数组。有关对齐和效率的讨论,请参阅 here

您已经有了一个大致的答案。专门针对您的平台 (GCC/Linux/x86_64),相关的 ABI (System V x86-64) 指定大小为 16 字节或更大的数组始终至少对齐 16 字节。正如@AdrianMole 在他的回答中所解释的那样,这是为了提高性能,特别是允许在数组上使用 SSE 指令。

参见链接的 System V x86-64 psABI 版本 1.0 的第 15 页 here

如果您使数组大小小于 16 字节,则不会发生这种情况。然而,还有一个 GCC 错误意外地将此规则应用于所有大于 16 位(即 2 字节)的数组。 GCC 7.1 已修复此问题。