GCC + LD + NDISASM = 大量的汇编指令

Posted

技术标签:

【中文标题】GCC + LD + NDISASM = 大量的汇编指令【英文标题】:GCC + LD + NDISASM = huge amount of assembler instructions 【发布时间】:2020-10-27 16:54:53 【问题描述】:

我是 C 和 GCC 编译器的新手,并试图通过反汇编生成的二进制文件来研究如何将 C 编译成机器代码,但是编译然后反汇编一个非常简单的函数的结果似乎过于复杂。

我有 basic.c 文件:

int my_function()
    int a = 0xbaba;
    int b = 0xffaa;
    return a + b;

然后我使用 gcc -ffreestanding -c basic.c -o basic.o

编译它

当我分解 basic.o 目标文件时,我得到了相当预期的输出:

0000000000000000 <my_function>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   c7 45 fc ba ba 00 00    movl   $0xbaba,-0x4(%rbp)
   b:   c7 45 f8 aa ff 00 00    movl   $0xffaa,-0x8(%rbp)
  12:   8b 55 fc                mov    -0x4(%rbp),%edx
  15:   8b 45 f8                mov    -0x8(%rbp),%eax
  18:   01 d0                   add    %edx,%eax
  1a:   5d                      pop    %rbp
  1b:   c3                      retq 

看起来很棒。但后来我使用链接器生成原始二进制文件:ld -o basic.bin -Ttext 0x0 --oformat binary basic.o

所以在使用命令 ndisasm -b 32 basic.bin > basic.dis 反汇编这个 basic.bin 文件后,我得到了一些有趣的东西:

00000000  55                push ebp
00000001  48                dec eax
00000002  89E5              mov ebp,esp
00000004  C745FCBABA0000    mov dword [ebp-0x4],0xbaba
0000000B  C745F8AAFF0000    mov dword [ebp-0x8],0xffaa
00000012  8B55FC            mov edx,[ebp-0x4]
00000015  8B45F8            mov eax,[ebp-0x8]
00000018  01D0              add eax,edx
0000001A  5D                pop ebp
0000001B  C3                ret
0000001C  0000              add [eax],al
0000001E  0000              add [eax],al
00000020  1400              adc al,0x0
00000022  0000              add [eax],al
00000024  0000              add [eax],al
00000026  0000              add [eax],al
00000028  017A52            add [edx+0x52],edi
0000002B  0001              add [ecx],al
0000002D  7810              js 0x3f
0000002F  011B              add [ebx],ebx
00000031  0C07              or al,0x7
00000033  08900100001C      or [eax+0x1c000001],dl
00000039  0000              add [eax],al
0000003B  001C00            add [eax+eax],bl
0000003E  0000              add [eax],al
00000040  C0FFFF            sar bh,byte 0xff
00000043  FF1C00            call far [eax+eax]
00000046  0000              add [eax],al
00000048  00410E            add [ecx+0xe],al
0000004B  108602430D06      adc [esi+0x60d4302],al
00000051  57                push edi
00000052  0C07              or al,0x7
00000054  0800              or [eax],al
00000056  0000              add [eax],al

我真的不知道像 SAR、JS、DEC 这样的命令来自哪里以及为什么需要它们。我猜,那是因为我为编译器或链接器指定了无效的参数。

【问题讨论】:

它们不是命令(指令),它们是您作为指令反汇编的数据。它们不是必需的,您的目标文件中可能有除 .text 之外的其他部分。 使用objdump -D 打印出这些部分。但您看到的可能是与.eh_frame 部分相关的数据。这些部分只是数据,但 ndiasm 将所有内容解码为指令,因为二进制格式不会区分实际代码和数据,因此默认情况下所有内容都被解码为指令。 如果您删除 .eh_frame 部分或根本不生成它们,那么您应该看到您想要的。尝试将 -fno-asynchronous-unwind-tables 选项添加到 GCC 命令行。评论不会进入二进制文件,但.eh_frame 会。您生成了 64 位代码,因此您需要使用 -b64 反汇编以获得您想要的解码。 另外,您编译为 64 位机器代码,但随后您将其反汇编为 32 位。这就是为什么 mov rbp, rsp 变成 dec eax; mov ebp, esp 的原因。 那么您的函数以ret 结束,因此永远不会执行其他数据。 ret 下面结束函数的所有东西都不会被执行。这只是数据。 .comment 部分位于 ELF 文件(对象)中,但未标记为可分配,因此在生成二进制文件时将它们排除在外。 .eh_frame 部分是可分配的,因此它们出现在二进制文件中。 【参考方案1】:

正如我从 @Michael Petch cmets 得出的结论:

所需函数的二进制表示由反汇编文件的00000000-0000001B行代码sn-p表示,并在最后执行命令ret,所以第二部分文件的 (0000001B-00000056) 永远不会执行 - 它是元数据。

根据 @Michael Petch@Jester cmets:

我可以弄清楚目标文件由许多部分组成https://en.wikipedia.org/wiki/Object_file 生成的 basic.o 文件原本有三个部分:

.text(函数本身) .comment(二进制文件中未表示) .eh_frame

什么是 .eh_frame 部分以及 GCC 编译器创建它的原因,如下所述: Why GCC compiled C program needs .eh_frame section?

通过使用参数 -fno-asynchronous-unwind-tables 运行 gcc,我可以从目标文件中删除 .eh_frame 部分。

【讨论】:

如果您只是希望 NASM 语法反汇编和/或除 GNU binutils 之外的反汇编程序来仔细检查 binutils 错误,Agner Fog 的objconv 可以做到这一点。 (与ndisasm 不同,它理解.o 目标文件格式,因此您无需先将部分转储到平面二进制文件。)How to disassemble a binary executable in Linux to get the assembly code?。

以上是关于GCC + LD + NDISASM = 大量的汇编指令的主要内容,如果未能解决你的问题,请参考以下文章

如何修改传递给 ld 的选项,而不重新编译 gcc

gcc 错误“/usr/bin/ld: 找不到 -lstdc++”

GCC 编译使用动态链接库 LD

gcc static静态编译选项提示错误:/usr/lib/ld:cannot find -lc

collect2:错误:ld 返回 1 退出状态,gcc

gcc和ld 中的参数 --whole-archive 和 --no-whole-archive