gcc堆栈优化?

时间:2011-01-14 17:59:01

标签: c gcc assembly x86 disassembly

我刚刚在C中编写了一个代码示例,并尝试将其拆解。以下是代码示例。

void start() {
    char phone[100];
    strcmp(phone, "12312312313");

    char name[100];
    strcmp(name, "eQuiNoX");

    char contact[100];
    strcmp(contact, "PM twitter.com/eQuiNoX__");
}

当我反汇编启动功能时,我得到以下结果: -

08048414 <start>:
 8048414: 55                    push   ebp
 8048415: 89 e5                 mov    ebp,esp
 8048417: 81 ec 58 01 00 00     sub    esp,0x158
 804841d: c9                    leave  
 804841e: c3                    ret   
  1. 我没有启用任何优化。有人可以解释为什么我从esp中减去158而不是将值推入堆栈并调用strcmp方法的汇编代码?是因为它不依赖于任何用户输入吗?
  2. 另外,有没有什么方法可以生成extended assembly(我不确定这是不是正确的术语,我只是希望看到用于将值推送到堆栈和调用strcmp函数的汇编代码) 。我有什么方法可以做到吗?
  3. 这种行为是针对处理器体系结构还是gcc版本或两者兼有的?

4 个答案:

答案 0 :(得分:10)

首先,strcmp是一个标准的库函数,因此gcc可以自由地了解它的工作原理。事实上,它确实;它很少会产生库调用。您可以尝试-fno-builtin禁用。

其次,您要与单位化值进行比较。这是,我相信未定义的行为。所以编译器可以做任何事情,包括生成随机代码。

您可以尝试使用-S选项来获取更详细的反汇编(或者更确切地说,缺少程序集);或者,如果使用-g进行编译(调试),objdump -S将显示源以及汇编代码。

以下是我使用gcc -fno-builtin -g -O0 test.c -c编译然后使用objdump -S test.o转储的示例:

test.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <main>:
#include <string.h>

int main() {
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 83 ec 10             sub    $0x10,%rsp
    const char foo[] = "foo";
   8:   8b 05 00 00 00 00       mov    0x0(%rip),%eax        # e <main+0xe>
   e:   89 45 f0                mov    %eax,-0x10(%rbp)
    return strcmp(foo, "bar");
  11:   48 8d 45 f0             lea    -0x10(%rbp),%rax
  15:   be 00 00 00 00          mov    $0x0,%esi
  1a:   48 89 c7                mov    %rax,%rdi
  1d:   e8 00 00 00 00          callq  22 <main+0x22>
}
  22:   c9                      leaveq 
  23:   c3                      retq   

答案 1 :(得分:4)

关于sub esp,0x158指令,而不是生成一堆push操作(涉及将操作数复制到堆栈中,而不仅仅是保留空间),通常编译器将保留足够的空间用于通过仅移动堆栈指针一次所有局部变量。这就是这条指令正在做的事情。 0x158是十进制的344,所以它为数组保留了300个字节,并且可能为编译器生成的结构留出了一些额外的空间(或者也可能将strcmp操作数放在堆栈上)。

答案 2 :(得分:4)

  1. 因为您的代码对程序执行没有影响。所有变量都在函数调用中使用,其返回值被丢弃,因此编译器将其标记为未使用的代码,并认为它应该删除。如果您想保留未使用的代码,请确保您没有使用任何优化 - 使用-O0进行编译。

  2. 请参阅上面的观点。

  3. 我怀疑大多数编译器会执行此优化,而不依赖于架构。

答案 3 :(得分:0)

它似乎确实已经过优化。您可以尝试使用-O0标志进行编译,以确保不进行优化(但我不确定它是否可行)。

或者您可以从start函数返回cmp结果,以显示您真正使用它们的编译器:

int start() {
    char phone[] = "43423432";
    return strcmp(phone, "12312312313");
}