Странное поведение компоновщика: перемещение сокращено до нужного

У меня есть скрипт компоновщика для ядра с двумя абсолютными символами: _kernel_start а также _kernel_end, Однако я получаю ошибку перемещения компоновщика только для _kernel_end:

In function `kernel::mem::mm::setup_memorymap':
/home/virtlink/kernel/src/mem/mm.rs:25:(.text._ZN3mem2mm15setup_memorymap):
  relocation truncated to fit: R_X86_64_PC32 against symbol `_kernel_end'
  defined in *ABS* section in ./kernel.bin

На SO было много вопросов об этой ошибке, но я не нашел ни одного, который решал бы мою конкретную проблему.

Видимо, это:

_kernel_start = .;

... считается 32-битным, тогда как это:

. += KERNEL_BASE;
_kernel_end = . - KERNEL_BASE;

... считается 64-битным Если я перееду _kernel_end символ над . += KERNEL_BASE строка как это:

_kernel_end = .;
. += KERNEL_BASE;

... тогда это снова работает. Но я хочу _kernel_end в конце мой скрипт компоновщика.

Сценарий компоновщика помещает загрузочный код в начало памяти, а остальной код - в верхнюю половину 64-битного пространства виртуальной памяти. Это выглядит так:

OUTPUT_FORMAT(elf64-x86-64)

KERNEL_BASE = 0xFFFFFFFF80000000;

SECTIONS
{
    /* Boot code at 1 MiB */
    . = 1M;
    _kernel_start = .;
    .boot :
    {
        KEEP( *(.multiboot) )
        *(.boot)
        *(.bootdata)
    }

    /* Kernel code at high virtual address. */
    . += KERNEL_BASE;
    .text ALIGN(4K) : AT(ADDR(.text) - KERNEL_BASE)
    {
        *(.text)
        *(.gnu.linkonce.t*)
    }
    .data ALIGN(4K) : AT(ADDR(.data) - KERNEL_BASE)
    {
        *(.data)
        *(.gnu.linkonce.d*)
    }
    .rodata ALIGN(4K) : AT(ADDR(.rodata) - KERNEL_BASE)
    {
        *(.rodata)
        *(.gnu.linkonce.r*)
    }
    .bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_BASE)
    {
        *(COMMON)
        *(.bss)
        *(.bss.*)
        *(.gnu.linkonce.b*)
    }
    _kernel_end = . - KERNEL_BASE;

    /DISCARD/ :
    {
        *(.comment)
        *(.eh_frame)
    }
}

Ядро действительно маленькое, поэтому _kernel_start = 0x00100000 а также _kernel_end = 0x00142000, Это не должно дать мне ошибки перемещения.

Как я могу переписать скрипт компоновщика так, чтобы _kernel_end не дай мне больше ошибок при переезде? Я не хочу использовать mcmodel=large только для этого одного символа.


Вот код, в котором я использую символы. Это Руст.

fn get_kernel_location() -> (*const u8, *const u8) {
    extern {
        static _kernel_start: u8;
        static _kernel_end: u8;
    }

    let kernel_start: *const u8 = &_kernel_start;
    let kernel_end: *const u8 = &_kernel_end;

    println!("{:p}", kernel_start);
    println!("{:p}", kernel_end);

    (kernel_start, kernel_end)
}

Вот записи в таблице перемещений скомпилированного объектного файла Rust:

  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000000012  058800000009 R_X86_64_GOTPCREL 0000000000000000 _kernel_end - 4
000000000019  058900000009 R_X86_64_GOTPCREL 0000000000000000 _kernel_start - 4

0 ответов

Другие вопросы по тегам