2010-11-24 97 views
1

我在堆栈上分配了12个字符串,或者等价地是12个字节。堆栈上字符串的分配

与gdb混合(在Linux下)显示为了为堆栈中的字符串分配空间,esp被-24(向下堆栈)移动。

push %ebp 
mov %esp,%ebp 
sub $0x18,%esp 

为什么它移动了24(0x18)?

+0

如果您显示C代码 – 2010-11-24 19:34:56

+0

,如果没有看到您的输入代码,我很难说,这会更容易回答。 – 2010-11-24 19:35:39

回答

6

如果您的函数调用其他函数,其中一部分可能是传出参数的空间;其中一些可能是从寄存器溢出的价值的临时空间;其中一些可能是填充。它将非常依赖于编译器版本和优化标志。

这里是为了说明一些简单的废话代码:

extern int foo(int a, int b); 

int bar(int c) 
{ 
    char s[12]; 

    s[0] = foo(c, 123); 
    return 456; 
} 

这与使用gcc 4.3.2在Debian莱尼机上没有优化编译:

bar: 
    pushl %ebp 
    movl %esp, %ebp 
    subl $24, %esp 
    movl $123, 4(%esp) 
    movl 8(%ebp), %eax 
    movl %eax, (%esp) 
    call foo 
    movb %al, -12(%ebp) 
    movl $456, %eax 
    leave 
    ret 

就像你的代码,它的分配24个字节。下面是他们使用什么:

 
    Stack while running bar() 
    :       : 
    +-------------------------+ 
    | incoming parameter: c | 8(%ebp) 
    +-------------------------+   --- 
    | return address   | 4(%ebp) ^
    +-------------------------+    | 
    | old %ebp    | (%ebp)  | 
    +-------------------------+    | bar()'s stack 
    | s[8]..s[11]    | -4(%ebp) | frame: 32 bytes 
    +-------------------------+    | 
    | s[4]..s[7]    | -8(%ebp) | 
    +-------------------------+    | 
    | s[0]..s[3]    | -12(%ebp) | 
    +-------------------------+    |  Stack while running foo() 
    | (unused)    | 8(%esp)  | :       : 
    +-------------------------+    | +-------------------------+ 
    | outgoing parameter: 123 | 4(%esp)  | | incoming parameter: b | 
    +-------------------------+    | +-------------------------+ 
    | outgoing parameter: c | (%esp)  v | incoming parameter: a | 
    +-------------------------+   --- +-------------------------+ 
               | return address   | 
               +-------------------------+ 
               | old %ebp    | 
               +-------------------------+ 
               : locals for foo()  : 

实验的位将表明,如果s[]增加时,它会吃入未使用的空间;例如如果它是13个字节,则堆栈帧大小相同,但s[]将从前一个字节开始(在-13(%ebp)) - 最多16个字节,其中所有分配的堆栈将被实际使用。如果s被声明为s[17],编译器将分配40个字节堆栈代替24.

这是因为编译器是保持堆栈帧的上述图的左边的总大小(一切,除了输入参数,它真的在调用者的栈帧的底部)四舍五入为16个字节的倍数。 (请参阅-mpreferred-stack-boundary选项的gcc文档。)

2

因为除了你的字符串以外的其他东西都被存储在堆栈上,比如其他局部变量或临时对象。当你有复杂的表达式时,编译器存储有时会将这些表达式的中间结果存储在堆栈的内存中(特别是禁用优化时),即使它们不对应于显式局部变量。