为什么gcc反汇编程序为局部变量分配额外的空间?

我用C编写了简单的函数,

void GetInput() { char buffer[8]; gets(buffer); puts(buffer); } 

当我在gdb的反汇编程序中对它进行反汇编时,它会进行以下反汇编。

  0x08048464 : push %ebp 0x08048465 : mov %esp,%ebp 0x08048467 : sub $0x10,%esp 0x0804846a : mov %gs:0x14,%eax 0x08048470 : mov %eax,-0x4(%ebp) 0x08048473 : xor %eax,%eax => 0x08048475 : lea -0xc(%ebp),%eax 0x08048478 : mov %eax,(%esp) 0x0804847b : call 0x8048360  0x08048480 : lea -0xc(%ebp),%eax 0x08048483 : mov %eax,(%esp) 0x08048486 : call 0x8048380  0x0804848b : mov -0x4(%ebp),%eax 0x0804848e : xor %gs:0x14,%eax 0x08048495 : je 0x804849c  0x08048497 : call 0x8048370  0x0804849c : leave 0x0804849d : ret 

现在请看第三行, 0x08048467 : sub $0x10,%esp ,我只有8个字节被分配为本地变量,那么为什么编译器分配16个字节(0x10)。

其次, xor %gs:0x14,%eax含义是什么xor %gs:0x14,%eax

@Edit:如果是优化,有没有办法阻止它。

谢谢。

两件事情:

  1. 编译器可以为您没有在源代码中给出名称的中间表达式保留空间(或者相反,不为可以完全存在于寄存器中的局部变量分配空间)。 二进制文件中的堆栈槽列表不必与源代码中的局部变量列表匹配。
  2. 在某些平台上,编译器必须保持堆栈指针对齐。 对于您问题中的特定示例,编译器可能正在努力使堆栈指针与16字节的边界保持对齐。

关于你应该单独询问的另一个问题, xor %gs:0x14,%eax显然是堆栈保护机制的一部分,默认情况下启用。 如果您使用的是GCC,请使用-fno-stack-protector将其关闭。

除了已经给出的其他答案之外,gcc更倾向于保持堆栈16字节对齐以便在堆栈上存储SSE值,因为一些(全部?)SSE指令要求它们的存储器参数是16字节对齐的。

这更多建立在Pascal的答案之上,但在这种情况下,可能是因为堆栈保护机制。

你分配8个字节,这是公平的,并考虑堆栈指针。 此外,当前堆栈保护地址保存到%ebp ,后者指向以下行中当前堆栈帧的顶部

 0x0804846a <+6>: mov %gs:0x14,%eax 0x08048470 <+12>: mov %eax,-0x4(%ebp) 

这似乎需要四个字节。 鉴于此,其他四个字节可能用于某种forms的对齐,或者在以下行中与其他一些堆栈信息一起使用:

 => 0x08048475 <+17>: lea -0xc(%ebp),%eax 0x08048478 <+20>: mov %eax,(%esp)