Странное поведение компоновщика: перемещение сокращено до нужного
У меня есть скрипт компоновщика для ядра с двумя абсолютными символами: _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