I have a script builder for the kernel with two absolute characters: _kernel_start and _kernel_end . However, I get the linker migration error only for _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
There are many questions about SO about this error, but I have not found anything that solves my specific problem.
Apparently this:
_kernel_start = .;
... is considered 32-bit, whereas this:
. += KERNEL_BASE; _kernel_end = . - KERNEL_BASE;
... is regarded as 64-bit. If I move the _kernel_end character over the line . += KERNEL_BASE . += KERNEL_BASE as follows:
_kernel_end = .; . += KERNEL_BASE;
... then it works again. But I want _kernel_end at the end of my linker script.
The script component puts the boot code at the beginning of the memory, and the rest of the code in the upper half of 64-bit virtual memory. It looks like this:
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) } }
The kernel is really small, so _kernel_start = 0x00100000 and _kernel_end = 0x00142000 . He should not give me moving errors.
How can I rewrite the script builder so that _kernel_end does not give me more errors while moving? I do not want to use mcmodel=large for this single character only.
Here is the code in which I use characters. This is rust.
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) }
Here are the entries in the movement table of the compiled Rust file:
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