为什么ld把我的5行无库C转换成100MB二进制文件?

为什么ld把我的5行无库C转换成100MB二进制文件?,c,gcc,x86,ld,osdev,C,Gcc,X86,Ld,Osdev,我正试图在下面的文档中开发一些非常低级的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

我正试图在下面的文档中开发一些非常低级的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
的二进制文件,其超过100兆字节。我反汇编了二进制代码,基本上是我的代码(大约十行),然后是一百兆的零,然后是某种页脚

额外的字节都是不必要的,因为我使用了
head
来剪掉那些不是我的代码的字节,它仍然可以正常运行

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

gcc -fno-pie -c main.c -o main.o
ld -o main.bin -Ttext 513 --oformat binary main.o
生成超过4MB的
main.bin
。同样,模式是相同的:我的代码,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

你在运行什么操作系统?@NateEldredge在问题的末尾添加了这一点。如果你改为链接到elf(删除
--oformat binary
)并运行
objdump-h
,你会看到有一个
.note.gnu.property
部分,它位于地址
0x080480f4
,这是你的130 MB。在二进制格式中,实现这一点的唯一方法是写入中间的所有零。我不知道为什么部分有那个地址,或者它是否应该存在。@NateEldredge:是的,编写自己的链接器脚本是内核的标准,尤其是平面二进制文件。你可以简单地忽略其他部分,它们将不包括在内。(不过,您必须确保包括GCC放置代码/数据的所有部分。)我不是链接器脚本方面的专家,但我肯定在其他SO问题的答案中看到过简单的示例,可能很容易在google上找到类似于
site:stackoverflow.com链接器脚本flat binary
的东西。我指的是一个通用的ELF GCC交叉编译器,它不绑定到您的本机工具链。有关它们的更多信息,请访问OSDev Wiki: