为什么ld把我的5行无库C转换成100MB二进制文件?
我正试图在下面的文档中开发一些非常低级的x86代码。我编写了以下C程序:为什么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
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: