我试图在UEFI引导加载程序中获得内核入口函数,我很困惑。
这段代码为什么有效?
int (*kmain)(void*) = (int(*)(void*)) (elf->entry);
这就是我把它和
gcc -no-pie -nostdlib -ffreestanding -e kmain -o kernel.elf kernel.o
我知道这与-no-pie
有关,因为没有它就不会工作
elf-〉条目是一个虚拟地址,但由于我在引导程序中,它引用了一个物理地址,对吗?
如果elf-〉entry是0x 4000,那么它进入物理地址0x 4000,但是如果物理地址0x 4000已经被其他东西使用了呢?
如果没有-no-pie
,我必须使用base + elf->entry
来完成,其中base是elf文件的开始,我完全可以理解,但我不明白为什么elf->entry
就可以了
1条答案
按热度按时间7kqas0il1#
通常,链接器并不关心它在内存中的 * 什么地方 * 放置任何东西。它的主要工作是确保所有的内存引用都是一致的,而不管 * 内存是如何,布局的。链接器脚本的目的是告诉链接器如何布局内存。如果你没有提供链接器脚本,它将使用自己的默认值。换句话说,链接器不知道也不关心您是否已经在0x4000处加载了一些内容。您的工作是了解内存是如何布局的,如果您希望以特定的方式布局,则提供链接器脚本。
至于问题的
-no-pie
位,这归结为位置无关和非位置无关的可执行文件是如何加载的。UEFI引导加载程序是一个加载程序。在可执行文件中有一个标志,告诉加载程序它是否是一个PIE。如果不是,那么加载程序只需要使用文件中编码的确切地址。在这种情况下,elf->entry
指针将是完全正确的。如果它 * 是 * 一个PIE,那么加载程序可以将它放置在它喜欢的任何内存地址,在这种情况下,elf->entry
指针将相对于可执行文件被加载的地址。这就是为什么当你不提供-no-pie
标志时,你需要使用base + elf->entry
。