如何使用 phdrs 命令修复链接描述文件中的重叠部分?

hac*_*atu 5 c assembly linker elf linker-scripts

我正在尝试制作一个简单的操作系统内核的上半部分。当像我一样使用 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

}
Run Code Online (Sandbox Code Playgroud)

我认为该代码与此错误无关。当我使用此链接器脚本(另外还使用 )链接我的目标文件时-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]
Run Code Online (Sandbox Code Playgroud)

加载内存地址的顺序是rodata、data、text,尽管我希望它们应该是data、rodata、text的顺序,因为这些节是按该顺序指定的,并且带有AT单调非递减位置的说明符(假设这些节不具有负尺寸)。

我应该指定我使用“段”来表示 ELF 程序头中的条目之一(PHDRS在链接描述文件中),使用“节”来表示 ELF 节头中的条目之一(SECTIONS在链接器脚本中)。我相信这是正确的术语,但承认我对链接器文件和 ELF 格式的理解最多是有限的。无论出于何种原因,如果 ELF 文件的入口点不在段中,Grub 都不会加载该文件。

为什么这些部分确实不符合我期望的顺序,我该如何调整它们?谢谢。