编译器 : Understanding assembly code generated from small programs

标签 c linux gcc x86-64 disassembly

我正在自学编译器的工作原理。我通过阅读 GCC 从小型 64 位 Linux 程序生成的代码的反汇编来学习。

我写了这个 C 程序:

#include <stdio.h>

int main()
{
    for(int i=0;i<10;i++){
        int k=0;
    }
}

使用 objdump 后我得到:

00000000004004d6 <main>:
  4004d6:       55                      push   rbp
  4004d7:       48 89 e5                mov    rbp,rsp
  4004da:       c7 45 f8 00 00 00 00    mov    DWORD PTR [rbp-0x8],0x0
  4004e1:       eb 0b                   jmp    4004ee <main+0x18>
  4004e3:       c7 45 fc 00 00 00 00    mov    DWORD PTR [rbp-0x4],0x0
  4004ea:       83 45 f8 01             add    DWORD PTR [rbp-0x8],0x1
  4004ee:       83 7d f8 09             cmp    DWORD PTR [rbp-0x8],0x9
  4004f2:       7e ef                   jle    4004e3 <main+0xd>
  4004f4:       b8 00 00 00 00          mov    eax,0x0
  4004f9:       5d                      pop    rbp
  4004fa:       c3                      ret    
  4004fb:       0f 1f 44 00 00          nop    DWORD PTR [rax+rax*1+0x0]

现在我有些疑惑。

  1. 最后的 NOP 是做什么用的,为什么会有它? (对齐?)

  2. 我正在使用 gcc -Wall <program.c> 进行编译.为什么我没有收到警告 control reaches end of non-void function ?

  3. 为什么编译器不使用 sub rsp,0x10 在堆栈上分配空间? ?为什么不使用 rbp注册以引用本地堆栈数据?

    PS:如果我在 printf 中调用函数(如 for )循环,为什么编译器突然生成sub rsp,0x10 ?为什么它仍然使用 rsp 引用本地数据登记。我希望生成的代码使用 rbp 引用本地堆栈数据!

最佳答案

关于第二个问题,由于C99标准允许main函数中没有明确的return 0,编译器会隐式添加。请注意,这仅针对 main 函数,没有其他函数。

至于第三个问题,rbp 寄存器充当frame pointer .

最后是PS。很可能被调用的函数使用 16 字节 (0x10) 作为传递给函数的参数。减法是从堆栈中“删除”那些变量。它可能是您作为参数传递的两个指针吗?

如果您认真学习编译器的一般工作原理,并且可能想创建自己的编译器(这很有趣!:)),那么我建议您购买一些有关它的理论和实践的书籍。 The dragon book是任何程序员书架的绝佳补充。

关于编译器 : Understanding assembly code generated from small programs,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42994231/

相关文章:

linux - 使用 linux 命令行识别文件中具有 2 个字段的重复行

linux - 在不使用 yum 的情况下在 AWS EC2 上安装 gcc?

C 识别 -l 标志的库名称?

c++ - 访问非托管代码中函数的指针

c - sqlite 中的表名长度会影响性能。为什么?

php - 为什么这个 shell 脚本没有按预期从 PHP 运行?

linux - 在 TLB 访问中设置断点

c - 使用 zlib 解压 PNG

创建 vector 计算器附加函数。尝试为其添加任何值(value)

c++ - 为什么 syslog 有两个不同的函数声明?