2010-11-24 127 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

因爲除了你的字符串以外的其他東西都被存儲在堆棧上,比如其他局部變量或臨時對象。當你有複雜的表達式時,編譯器存儲有時會將這些表達式的中間結果存儲在堆棧的內存中(特別是禁用優化時),即使它們不對應於顯式局部變量。