OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Apr 18, 2024 10:01 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 4 posts ] 
Author Message
 Post subject: Relocation truncated to fit ...
PostPosted: Sat Oct 10, 2020 4:47 pm 
Offline

Joined: Sat Oct 10, 2020 4:05 pm
Posts: 14
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.


Top
 Profile  
 
 Post subject: Re: Relocation truncated to fit ...
PostPosted: Sat Oct 10, 2020 11:06 pm 
Offline
Member
Member

Joined: Tue Aug 11, 2020 12:14 pm
Posts: 151
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


Top
 Profile  
 
 Post subject: Re: Relocation truncated to fit ...
PostPosted: Sun Oct 11, 2020 1:35 am 
Offline
Member
Member
User avatar

Joined: Thu Oct 13, 2016 4:55 pm
Posts: 1584
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


Top
 Profile  
 
 Post subject: Re: Relocation truncated to fit ...
PostPosted: Sun Oct 11, 2020 4:58 am 
Offline

Joined: Sat Oct 10, 2020 4:05 pm
Posts: 14
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.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 4 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Google [Bot] and 104 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group