OSDev.org
https://forum.osdev.org/

Relocation truncated to fit ...
https://forum.osdev.org/viewtopic.php?f=1&t=37333
Page 1 of 1

Author:  Doctor5555 [ Sat Oct 10, 2020 4:47 pm ]
Post subject:  Relocation truncated to fit ...

This question has probably been answered in many places before, but none of the responses I have found have worked.
Currently, I use UEFI to launch a bootloader which loads my kernel. The kernel is in ELF64 format. Having finally figured out how to virtually map memory, I want to move the kernel to the higher half.
To do this, I've changed the virtual memory address in the linker script. Unfortunately, this causes a large number of R_X86_64_PC32, R_X86_64_32S and R_X86_64_PLT32 relocation truncated to fit errors.
According to every source I have been able to find, adding -mcmodel=large and -fPIC to the compiler/linker options should fix this. However, it does not. Removing -mcmodel=large reduces the errors to only the R_X86_64_PC32 variants in .start.
Linker script:
Code:
ENTRY(_start)

KERNEL_PMA = 0x00080000;
KERNEL_VMA = 0xC0000000;

SECTIONS
{
    . = KERNEL_PMA;

    .start : {
        _start = .;
        *(.start)
        . = ALIGN(4096);
    }

    . += KERNEL_VMA;

    .text : AT(ADDR(.text) - KERNEL_VMA)
    {
        _code = .;
        *(.text)
        *(.rodata*)
        . = ALIGN(4096);
    }

   .data : AT(ADDR(.data) - KERNEL_VMA)
   {
        _data = .;
        *(.data)
        . = ALIGN(4096);
   }

   .eh_frame : AT(ADDR(.eh_frame) - KERNEL_VMA)
   {
       _ehframe = .;
       *(.eh_frame)
        . = ALIGN(4096);
   }

   .bss : AT(ADDR(.bss) - KERNEL_VMA)
   {
       _bss = .;
       *(.bss)

       /*
        * You usually need to include generated COMMON symbols
        * under kernel BSS section or use gcc's -fno-common
        */

        *(COMMON)
       . = ALIGN(4096);
   }

   _end = .;

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

To GCC for compilation of all .c files, I pass:
Code:
-O2 -g -ffreestanding -Wall -Wextra -fstack-protector -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -mcmodel=large -D__is_kernel -Iinclude

And when linking:
Code:
-ffreestanding -Wall -Wextra -fstack-protector -z max-page-size=0x1000 -static -mcmodel=large

boot.s:
Code:
global _start

section .start

_start:
    mov rdi, rcx

    extern early_kmain
    call early_kmain

    extern _init
    call _init

    extern kmain
    call kmain

    extern _fini
    call _fini

.end:
    cli
.loop:
    jmp .loop

.size: equ $ - _start

And last, but not least, the error output:
Code:
arch/x86_64/boot.o: in function `_start':
arch/x86_64/boot.s:(.start+0xb): relocation truncated to fit: R_X86_64_PC32 against symbol `_init' defined in .init section in arch/x86_64/crti.o
arch/x86_64/boot.s:(.start+0x10): relocation truncated to fit: R_X86_64_PC32 against symbol `kmain' defined in .text section in kernel/kernel.o
arch/x86_64/boot.s:(.start+0x15): relocation truncated to fit: R_X86_64_PC32 against symbol `_fini' defined in .fini section in arch/x86_64/crti.o
kernel/kernel.o:(.eh_frame+0x20): relocation truncated to fit: R_X86_64_PC32 against `.start'
arch/x86_64/crtbegin.o: in function `deregister_tm_clones':
crtstuff.c:(.text+0x7): relocation truncated to fit: R_X86_64_32S against `.tm_clone_table'
arch/x86_64/crtbegin.o: in function `register_tm_clones':
crtstuff.c:(.text+0x38): relocation truncated to fit: R_X86_64_32S against `.tm_clone_table'
arch/x86_64/crtbegin.o: in function `__do_global_dtors_aux':
crtstuff.c:(.text+0x95): relocation truncated to fit: R_X86_64_32S against `.dtors'
crtstuff.c:(.text+0xe0): relocation truncated to fit: R_X86_64_PLT32 against undefined symbol `__deregister_frame_info'
arch/x86_64/crtbegin.o: in function `frame_dummy':
crtstuff.c:(.text+0x119): relocation truncated to fit: R_X86_64_PLT32 against undefined symbol `__register_frame_info'
/Users/doctor5555/Dev/betelgeuse/sysroot/usr/lib/libk.a(printf.libk.o): in function `printf':
/Users/doctor5555/Dev/betelgeuse/libc/stdio/printf.c:69:(.text+0xf8): relocation truncated to fit: R_X86_64_32S against `.rodata'
/Users/doctor5555/Dev/betelgeuse/libc/stdio/printf.c:129:(.text+0x146): additional relocation overflows omitted from the output


If someone could help point me towards what obvious error I am missing, or perhaps hopefully not so obvious error, that would be much apperciated.

Author:  sj95126 [ Sat Oct 10, 2020 11:06 pm ]
Post subject:  Re: Relocation truncated to fit ...

At some point, you have to explicitly jump to high-load space, and you can't do that directly with call as you've written it, because it only uses 32-bit displacements from your current location. Hence the truncation.

Here's how I trampoline into high-load space:
(Forgive the AT&T syntax, it's been too long since I've used Intel)
Code:
   movabsq   $(KERNEL_BASE+trampoline), %rax
   jmp   *%rax
trampoline:

Alternatively, your calls could be rewritten as, e.g.:

Code:
movabsq $early_kmain, %rax
call *%rax

Author:  bzt [ Sun Oct 11, 2020 1:35 am ]
Post subject:  Re: Relocation truncated to fit ...

Doctor5555 wrote:
The kernel is in ELF64 format.
Code:
KERNEL_PMA = 0x00080000;
KERNEL_VMA = 0xC0000000;

SECTIONS
{
    . = KERNEL_PMA;                  <-- this

    .start : {
        _start = .;
        *(.start)
        . = ALIGN(4096);
    }

    . += KERNEL_VMA;                  <-- this
The two addresses are both in lower mem in long mode. And using both addresses in the linker script will make your binary 3G in size (max_page_size won't always solve this, at least not with some versions of gcc, you'll need --nmagic or --omagic, to workaround the bug in ld).

In the _start section, use only absolute virtual (higher-half) addresses, as @sj95126 suggested, then it won't matter where that code is actually mapped in lower-half. Or even better, just link _start with the rest.

BTW, with UEFI, there's no need to put _start at a fixed address, just link your kernel at VMA (do not use PMA in the linker script at all). With UEFI there's no guarantee that address 0x80000 is going to be free anyway.

Cheers,
bzt

Author:  Doctor5555 [ Sun Oct 11, 2020 4:58 am ]
Post subject:  Re: Relocation truncated to fit ...

Thanks to @sj95126 for the tip on how to jump to higher mem. Code is nasm that I used was:
Code:
mov rax, QWORD _start_high
jmp [rax]

This removed the first 3 linker errors, but I also had to move the kernel to -2GiB and compile with -mcmodel=kernel, and recompile libgcc with -mcmodel=large, to actually remove all the errors.
I might also map the kernel to higher half in the bootloader before jumping to _start, and then map it all to vma.

Page 1 of 1 All times are UTC - 6 hours
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/