我在堆棧上分配了12個字符串,或者等價地是12個字節。堆棧上字符串的分配
與gdb混合(在Linux下)顯示爲了爲堆棧中的字符串分配空間,esp被-24(向下堆棧)移動。
push %ebp
mov %esp,%ebp
sub $0x18,%esp
爲什麼它移動了24(0x18)?
我在堆棧上分配了12個字符串,或者等價地是12個字節。堆棧上字符串的分配
與gdb混合(在Linux下)顯示爲了爲堆棧中的字符串分配空間,esp被-24(向下堆棧)移動。
push %ebp
mov %esp,%ebp
sub $0x18,%esp
爲什麼它移動了24(0x18)?
如果您的函數調用其他函數,其中一部分可能是傳出參數的空間;其中一些可能是從寄存器溢出的價值的臨時空間;其中一些可能是填充。它將非常依賴於編譯器版本和優化標誌。
這裏是爲了說明一些簡單的廢話代碼:
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文檔。)
因爲除了你的字符串以外的其他東西都被存儲在堆棧上,比如其他局部變量或臨時對象。當你有複雜的表達式時,編譯器存儲有時會將這些表達式的中間結果存儲在堆棧的內存中(特別是禁用優化時),即使它們不對應於顯式局部變量。
如果您顯示C代碼 – 2010-11-24 19:34:56
,如果沒有看到您的輸入代碼,我很難說,這會更容易回答。 – 2010-11-24 19:35:39