我在堆栈上分配了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