首页 > 解决方案 > 为什么 ld 将我的 5 行无库 C 代码变成了 100MB 的二进制文件?

问题描述

我正在尝试按照本文档开发一些非常低级的 x86 代码。我编写了以下 C 程序:

void main()
{
    char* video_memory = (char*) 0xb8000;
    *video_memory = 'X';
}

我像这样编译和链接它:

gcc -m32 -fno-pie -c main.c -o main.o
ld -m elf_i386 -o main.bin -Ttext 513 --oformat binary main.o

main.bin这会产生一个超过一百兆字节的二进制文件。我反汇编了那个二进制文件,它基本上是我的代码(大约十行),然后是一百兆的零,然后是某种页脚。

额外的字节都是不必要的,因为我曾经head剪掉那些不是我的代码的,它仍然运行良好。

我正在使用 32 位标志,因为我的测试机器是一台旧的 32 位笔记本电脑,但您可以在 64 位中获得类似(但不那么极端)的行为。这个脚本:

gcc -fno-pie -c main.c -o main.o
ld -o main.bin -Ttext 513 --oformat binary main.o

产生main.bin超过 4 MB 的 a。同样,模式是相同的:我的代码,4 兆零,然后是页脚。我的代码和零之间有一点噪音。这是反汇编的 4MB 文件:

       0:   f3 0f 1e fa             endbr64 
       4:   55                      push   %ebp
       5:   48                      dec    %eax
       6:   89 e5                   mov    %esp,%ebp
       8:   48                      dec    %eax
       9:   c7 45 f8 00 80 0b 00    movl   $0xb8000,-0x8(%ebp)
      10:   48                      dec    %eax
      11:   8b 45 f8                mov    -0x8(%ebp),%eax
      14:   c6 00 58                movb   $0x58,(%eax)
      17:   90                      nop
      18:   5d                      pop    %ebp
      19:   c3                      ret    
    ...
     aea:   00 00                   add    %al,(%eax)
     aec:   00 14 00                add    %dl,(%eax,%eax,1)
     aef:   00 00                   add    %al,(%eax)
     af1:   00 00                   add    %al,(%eax)
     af3:   00 00                   add    %al,(%eax)
     af5:   01 7a 52                add    %edi,0x52(%edx)
     af8:   00 01                   add    %al,(%ecx)
     afa:   78 10                   js     0xb0c
     afc:   01 1b                   add    %ebx,(%ebx)
     afe:   0c 07                   or     $0x7,%al
     b00:   08 90 01 00 00 1c       or     %dl,0x1c000001(%eax)
     b06:   00 00                   add    %al,(%eax)
     b08:   00 1c 00                add    %bl,(%eax,%eax,1)
     b0b:   00 00                   add    %al,(%eax)
     b0d:   f3 f4                   repz hlt 
     b0f:   ff                      (bad)  
     b10:   ff 1a                   lcall  *(%edx)
     b12:   00 00                   add    %al,(%eax)
     b14:   00 00                   add    %al,(%eax)
     b16:   45                      inc    %ebp
     b17:   0e                      push   %cs
     b18:   10 86 02 43 0d 06       adc    %al,0x60d4302(%esi)
     b1e:   51                      push   %ecx
     b1f:   0c 07                   or     $0x7,%al
     b21:   08 00                   or     %al,(%eax)
    ...
  3ffaeb:   00 00                   add    %al,(%eax)
  3ffaed:   04 00                   add    $0x0,%al
  3ffaef:   00 00                   add    %al,(%eax)
  3ffaf1:   10 00                   adc    %al,(%eax)
  3ffaf3:   00 00                   add    %al,(%eax)
  3ffaf5:   05 00 00 00 47          add    $0x47000000,%eax
  3ffafa:   4e                      dec    %esi
  3ffafb:   55                      push   %ebp
  3ffafc:   00 02                   add    %al,(%edx)
  3ffafe:   00 00                   add    %al,(%eax)
  3ffb00:   c0 04 00 00             rolb   $0x0,(%eax,%eax,1)
  3ffb04:   00 03                   add    %al,(%ebx)
  3ffb06:   00 00                   add    %al,(%eax)
  3ffb08:   00 00                   add    %al,(%eax)
  3ffb0a:   00 00                   add    %al,(%eax)
    ...

巨大的二进制文件有效,但它很难看,我想了解发生了什么。

我正在 64 位机器上的 Ubuntu 20.20 上进行编译/链接。工具版本:

gcc version 9.3.0 (Ubuntu 9.3.0-10ubuntu2) 
GNU ld (GNU Binutils for Ubuntu) 2.34

标签: cgccx86ldosdev

解决方案


推荐阅读