long *video_memory = (long *)0xB8000;
int main() {
// long *video_memory = (long *)0xB8000;
*video_memory = 0x5050505050505050;
return 0;
}
为什么上面的C代码在链接时会创建2Mb二进制文件?
如果我注释全局变量而取消注释本地变量,那么它将起作用(文件只有几个字节)。
这是我链接/ [交叉]编译它的方式:
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
问题在于,链接器max-page-size
由于x86_64 ABI中的错误而导致了2MB的荒谬,最终导致在各个地方产生2MB的对齐要求。通常,它将文本和数据段放在文件的同一部分中,目的是将它映射两次,但是只有像ELF这样的合理二进制格式才能表示它;对于原始二进制文件,唯一能够实现对齐的方法是将近2MB的间隙。
正确的解决方法是在链接命令行上max-page-size
使用-z max-page-size=4096
(实际的硬件页面大小/内存保护的粒度)覆盖荒谬的默认值。如果您使用编译器驱动程序而不是ld
直接调用,那就是-Wl,-z,max-page-size=4096
。每当您使用会导致出现相同问题的强化选项时,现代托管工具链都会为您做到这一点,但显然裸机仍然没有。
您可能还考虑使用可以为内核加载ELF而不是原始二进制文件的引导加载程序。ELF加载程序易于编写,并让您做一些有用的事情,例如通过两次映射(在裸机级别,只需加载/复制)同一页两次来避免浪费的空间,在图像标题控制的位置设置入口点,而不是在引导程序等中进行硬编码。如果愿意,您甚至可以通过这种方式使内核独立于位置。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句