了解堆栈分配和对齐

时间:2011-01-27 14:21:04

标签: c stack memory-management memory-alignment

我正在尝试理解堆栈对齐是如何工作的,如what is "stack alignment"?中所述,但我无法通过一个小例子来演示所述行为。我正在检查我的函数foo的堆栈分配:

void foo() {
    int a = 0;
    char b[16];
    b[0] = 'a';
}

我用gcc -ggdb example.c -o example.out编译了源文件(即没有任何编译器标志),gdb的汇编器转储读取:

(gdb) disassemble foo
Dump of assembler code for function foo:
0x08048394 <+0>:    push   %ebp
0x08048395 <+1>:    mov    %esp,%ebp
0x08048397 <+3>:    sub    $0x20,%esp
0x0804839a <+6>:    movl   $0x0,-0x4(%ebp)
0x080483a1 <+13>:   movb   $0x61,-0x14(%ebp)
0x080483a5 <+17>:   leave  
0x080483a6 <+18>:   ret    
End of assembler dump.

我的堆栈以16个字节的块分配(我在其他几个测试中验证了这一点)。根据汇编程序转储,这里分配了32个字节,因为(16 <4 + 16&lt; 32),但我希望在前16个字节上分配整数'a',然后在下一个字节上分配字符数组16个字节(中间留有12个字节的空格)。但似乎整数和字符数组都被分配了一个20字节的连续块,根据我上面提到的讨论,这是低效的。有人可以解释我在这里缺少的东西吗?

编辑:我得出结论,我的堆栈是以16字节的块分配的,程序如下:

void foo() {
    char a[1];
}

相应的汇编程序转储:

(gdb) disassemble foo
Dump of assembler code for function foo:
0x08048394 <+0>:    push   %ebp
0x08048395 <+1>:    mov    %esp,%ebp
0x08048397 <+3>:    sub    $0x10,%esp
0x0804839a <+6>:    leave  
0x0804839b <+7>:    ret    
End of assembler dump.

您可以看到,对于大小为1的字符数组(仅需要1个字节),已在堆栈上分配了16个字节。我可以将数组的大小增加到16并且汇编程序转储保持不变,但是当它为17时,它在堆栈上分配32个字节。我运行了很多这样的样本,结果是一样的;堆栈内存以16字节的块分配。在Stack allocation, padding, and alignment中已经讨论了类似的主题,但我更热衷于找出为什么对齐对我的例子没有影响。

5 个答案:

答案 0 :(得分:6)

我认为您错过了这样一个事实,即不需要将所有堆栈变量单独对齐到16字节边界。

答案 1 :(得分:0)

通常的规则是变量在32位边界上分配。我不确定为什么你认为16字节有任何特殊含义。

答案 2 :(得分:0)

我从未听说过特定堆栈对齐这样的事情。如果CPU存在对齐要求,则无论是存储在堆栈还是其他位置,都会对所有类型的数据存储器进行对齐。它从偶数地址开始,后面有16位,32位或64位数据。

16字节可能是某种片上高速缓冲存储器优化,虽然这对我来说似乎有点牵强。

答案 3 :(得分:0)

一个很好的例子是在结构上看到这一点。

struct a{
    int a;
    char b;
    int c;
} a;

在32位系统上,如果单独使用,则为4 + 1 + 4字节。

因为结构和它的成员是对齐的“char b”将是4个字节,将其取为12个字节。

struct b{
    int a;
    char b;
    int c;
} __attribute__((__packed__)) b;

使用packed属性可以强制它保持最小尺寸。因此,这个结构是9个字节。

您也可以查看http://sig9.com/articles/gcc-packed-structures

希望有所帮助。

答案 4 :(得分:0)

您可以使用名为pahole http://packages.debian.org/lenny/dwarves的工具检查为数据结构分配的额外内存。它向您显示程序的所有漏洞:如果总结数据的大小,以及卡住的实际大小