【问题标题】:Why gcc disassembler allocating extra space for local variable?为什么 gcc 反汇编程序为局部变量分配额外的空间?
【发布时间】:2014-01-18 20:31:46
【问题描述】:

我用 C 写过简单的函数,

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

当我在 gdb 的反汇编器中对其进行反汇编时,它会给出以下反汇编。

   0x08048464 <+0>: push   %ebp
   0x08048465 <+1>: mov    %esp,%ebp
   0x08048467 <+3>: sub    $0x10,%esp
   0x0804846a <+6>: mov    %gs:0x14,%eax
   0x08048470 <+12>:    mov    %eax,-0x4(%ebp)
   0x08048473 <+15>:    xor    %eax,%eax
=> 0x08048475 <+17>:    lea    -0xc(%ebp),%eax
   0x08048478 <+20>:    mov    %eax,(%esp)
   0x0804847b <+23>:    call   0x8048360 <gets@plt>
   0x08048480 <+28>:    lea    -0xc(%ebp),%eax
   0x08048483 <+31>:    mov    %eax,(%esp)
   0x08048486 <+34>:    call   0x8048380 <puts@plt>
   0x0804848b <+39>:    mov    -0x4(%ebp),%eax
   0x0804848e <+42>:    xor    %gs:0x14,%eax
   0x08048495 <+49>:    je     0x804849c <GetInput+56>
   0x08048497 <+51>:    call   0x8048370 <__stack_chk_fail@plt>
   0x0804849c <+56>:    leave  
   0x0804849d <+57>:    ret    

现在请看第三行,0x08048467 &lt;+3&gt;: sub $0x10,%esp,我只分配了 8 个字节作为局部变量,那么为什么编译器要分配 16 个字节(0x10)。

其次,xor %gs:0x14,%eax是什么意思。

@Edit:如果是优化,有什么办法可以阻止它。

谢谢。

【问题讨论】:

标签: c optimization assembly compiler-construction gdb


【解决方案1】:

两件事:

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

关于您应该单独提出的其他问题,xor %gs:0x14,%eax 显然是stack protection mechanism 的一部分,默认启用。如果您使用的是 GCC,请使用 -fno-stack-protector 将其关闭。

【讨论】:

  • 我正在学习逆向工程,我应该如何理解这种令人惊讶的行为?
  • @pranitkothari 这并不奇怪。现代编译器不会逐行翻译程序。编译器的目标是生成与源代码等效的汇编代码,即使它以不同的方式或以不同的顺序执行所有操作。当您匹配汇编和源代码时,请记住这一点。
【解决方案2】:

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

【讨论】:

  • 原来如此!我经常对此感到疑惑,因为 gcc 也在 32 位系统上执行此操作,我一直认为这可能只是对他们不关心的其他内容的一些不重要的优化。
【解决方案3】:

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

您分配了 8 个字节,这很公平,并与堆栈指针一起考虑。另外,当前栈保护地址被保存到%ebp,指向下面几行当前栈帧的top

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-25
    • 2022-06-14
    • 2015-12-01
    • 1970-01-01
    • 2011-09-06
    • 2015-07-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多