我试图让一个简单的操作系统内核更上一半。当像我一样使用Grub作为引导加载程序时,还必须有一些下半部分(32位)代码。因为我想保持这个32位代码尽可能简短,我不想在其中编写一个ELF加载器只是为了加载64位代码,因为这显然是荒谬的(这实际上是最常见的解决方案,但我我想尽可能避免它。)
我发现链接器脚本允许加载地址与虚拟地址不同。这很有用,因此我可以加载64位部分以适应小二进制文件,然后使用虚拟内存将正确的虚拟地址映射到它们加载的物理地址。这样做除了低文本部分没有放在文本段中。入口点_start
位于此部分中。
除非我在_start
命令中指定文本段,否则我无法将低文本部分(PHDRS
所在的位置)放在文本段中。当然,使用此命令会使链接器决定生成正常预期的段。当我这样做时,这些部分最终重叠,我不完全确定为什么。我在订单数据,rodata,文本中指定了段,并且这些段是相同的,但是它们的装载存储器地址被分配了rodata和数据交换,并且所有三个都重叠。
这是我的链接描述文件:
ENTRY(_start)
PHDRS {
.low PT_LOAD FILEHDR PHDRS;
.data PT_LOAD;
.rodata PT_LOAD;
.text PT_LOAD;
}
SECTIONS {
. = 1M;
.data_low BLOCK(4K) : ALIGN(4K) {
*(.bss_low)
} : .low
.rodata_low BLOCK(4K) : ALIGN(4K) {
KEEP(*(.multiboot_low))
*(.rodata_low)
} : .low
.text_low BLOCK(4K) : ALIGN(4K) {
*(.text_low)
} : .low
.stack 0xC0000000 : AT(0x200000) ALIGN(4K) {
*(.bootstrap_stack)
} : .data
_LADD_ = LOADADDR(.stack) + SIZEOF(.stack);
.data BLOCK(4K) : AT(_LADD_) ALIGN(4K) {
*(COMMON)
*(.bss)
} : .data
_LADD_ += SIZEOF(.data);
.rodata BLOCK(4K) : AT(_LADD_) ALIGN(4K) {
*(.rodata)
} : .rodata
_LADD_ += SIZEOF(.rodata);
.text BLOCK(4K) : AT(_LADD_) ALIGN(4K) {
*(.text)
} : .text
}
我认为代码与此错误无关。当我使用此链接描述文件(另外使用-n --gc-sections
)链接我的目标文件时,我收到此错误:
ld: section .data loaded at [0000000000200020,000000000020103f] overlaps section .rodata loaded at [0000000000200010,00000000002000d0]
ld: section .text loaded at [00000000002000d1,00000000002017ce] overlaps section .data loaded at [0000000000200020,000000000020103f]
加载内存地址按照rodata,data,text的顺序排列,即使我希望它们应该在订单数据,rodata,text中,因为这些部分是以AT
说明符的顺序指定的,单调非减少位置(假设各部分没有负面大小)。
我应该指明我正在使用" segment"表示ELF程序头中的一个条目(链接器脚本中的PHDRS
)和"部分"表示ELF节标题中的一个条目(链接描述文件中为SECTIONS
)。我认为这是正确的术语,但承认我对链接器文件和ELF格式的理解最多。无论出于何种原因,如果其入口点不在段中,Grub将不会加载ELF文件。
为什么这些部分确实不符合我期望它们的顺序,我怎样才能使它们成为现实?谢谢。