我在堆栈上分配12个字符串,或者相当于它是12个字节.
使用gdb(在Linux下)进行分解表明,为了在堆栈上为字符串分配空间,esp会被-24(向下移动)移动.
push %ebp
mov %esp,%ebp
sub $0x18,%esp
Run Code Online (Sandbox Code Playgroud)
为什么它移动了24(0x18)?
如果您的函数调用其他参数,其中一些可能是传出参数的空间; 其中一些可能是从寄存器中溢出的价值的临时空间; 其中一些可能是填充.它将非常依赖于编译器版本和优化标志.
这里有一些简单的无意义代码用于说明:
extern int foo(int a, int b);
int bar(int c)
{
char s[12];
s[0] = foo(c, 123);
return 456;
}
Run Code Online (Sandbox Code Playgroud)
这里使用gcc 4.3.2在Debian Lenny机器上编译时没有进行优化:
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
Run Code Online (Sandbox Code Playgroud)
与您的代码一样,它分配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[]会先提前一个字节(at -13(%ebp)) - 最多16个字节,其中实际使用所有分配的堆栈.如果s声明为s[17],则编译器将分配40个字节的堆栈而不是24个.
这是因为编译器保持堆栈帧的总大小(上图中左侧的所有内容,除了传入参数,实际上位于调用者堆栈帧的底部)四舍五入为16个字节的倍数.(有关该-mpreferred-stack-boundary选项,请参阅gcc文档.)