编译的Elf二进制文件太大

Compiled Elf binary is too big

本文关键字:二进制文件 Elf 编译      更新时间:2024-09-22
long *video_memory = (long *)0xB8000;
int main() {
// long *video_memory = (long *)0xB8000;
*video_memory = 0x5050505050505050;
return 0;
}

为什么上面的C代码在链接时会创建一个2Mb二进制文件?

如果我对全局var进行注释,并取消对本地var的注释,它就会起作用(然后文件只有几个字节(。

这就是我链接/[交叉]编译它的方式:

x86_64-elf-gcc -m64 -ffreestanding -nostdlib -mno-red-zone -c kernel.c -o bin/kernel.o
objcopy --remove-section .eh_frame bin/kernel.o
x86_64-elf-ld --oformat binary -Ttext 0x8000 bin/kernel_entry.o bin/kernel.o -o bin/kernel.bin
#  kernel.bin is now 2Mb

问题是,由于x86_64 ABI中的错误,链接器具有2MB的荒谬max-page-size,这最终导致在各个地方产生2MB的对齐要求。通常,它会将文本和数据段放在文件的同一部分,目的是将其映射两次,但这只有在ELF等合理的二进制格式下才能实现;对于原始二进制,它实现对齐的唯一方法是使用接近2MB的间隙。

正确的解决方案是在链接命令行上用-z max-page-size=4096(内存保护的实际硬件页面大小/粒度(覆盖荒谬的默认max-page-size。如果使用编译器驱动程序而不是直接调用ld,则为-Wl,-z,max-page-size=4096。无论何时使用会出现相同问题的硬化选项,现代托管工具链都会为您做到这一点,但显然裸金属仍然没有。

您还可以考虑使用一个引导加载程序,它可以为您的内核加载ELF,而不是原始二进制文件。ELF加载程序很容易编写,可以让你做一些有用的事情,比如通过映射(在裸机级别,只是加载/复制(同一页两次来避免浪费空间,在由图像头控制的位置上有一个入口点,而不是在引导加载程序中硬编码,等等。如果你愿意,你甚至可以通过这种方式使内核位置独立。