[SOLVED] 64-bit Higher Half relocation issues

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
isaacwoods
Member
Member
Posts: 47
Joined: Sun Sep 06, 2015 5:40 am

[SOLVED] 64-bit Higher Half relocation issues

Post by isaacwoods »

Hi, I'm trying to get a 64-bit higher half kernel working, which has been somewhat challenging. I opted to go with a 32-bit bootstrap placed in the physical address space, in which I set up identity mapping and enter Long Mode, then set up real higher-half page tables and then jump into the higher-half. The relevant part of the bootstrap code is:

Code: Select all

extern Entry64
InLongMode:
  ; Reload every data segment with 0 (Long-mode doesn't use segmentation)
  mov ax, 0
  mov ss, ax
  mov ds, ax
  mov es, ax
  mov fs, ax
  mov gs, ax

  ; This sets up the higher half page tables
  call MapHigherHalf

  ; Correct the address of the Multiboot structure
  add rdi, 0xffffff0000000000

  lea rax, [Entry64]
  jmp rax
Entry64 is defined in another file (linked into the virtual address space with a base of 0xffffff0000100000):

Code: Select all

bits 64
section .text
global Entry64
Entry64:
  ; Print OKAY
  mov rax, 0x2f592f412f4b2f4f
  mov qword [0xb8000], rax  ; TODO: use proper virtual address (this would only work because the identity mapping is still also in place)
  hlt
This is all linked into one executable (with the bootstrap at 0x100000 and the rest of the kernel at 0xffffff0000100000) with:

Code: Select all

KERNEL_LMA = 0x100000;
KERNEL_VMA = 0xffffff0000100000;

SECTIONS
{
  /*
   * First, we physically-map a bootstrap section that will load the 64-bit code. This is required
   * because we haven't enabled paging yet, and so code that uses virtual addresses won't work.
   */
  . = KERNEL_LMA;

  .bootstrap.text :
  {
    KEEP(*(.multiboot))
    *bootstrap.o (.text .text.*)
    . = ALIGN(4K);
  }

  .bootstrap.bss :
  {
    *bootstrap.o (.bss)
    . = ALIGN(4K);
  }

  .bootstrap.rodata :
  {
    *bootstrap.o (.rodata .rodata.*)
    . = ALIGN(4K);
  }

  /*
   * Then, we place everything else at proper virtual addresses
   */
  . = KERNEL_VMA;

  .rodata : AT(ADDR(.rodata) - KERNEL_VMA)
  {
    *(EXCLUDE_FILE(bootstrap.o) .rodata .rodata.*)
    . = ALIGN(4K);
  }
  ...
However, it seems to emit the incorrect relocation to load the address of Entry64 (I don't understand why this doesn't output a R86_64_64 type relocation):

Code: Select all

relocation truncated to fit: R_X86_64_32S against symbol `Entry64' defined in .text section in /home/isaac/Documents/RustOS/build/x86_64/entry64.o
There also seem to be problems with Entry64:

Code: Select all

entry64.s:11:(.stab+0x14): relocation truncated to fit: R_X86_64_32 against `.text'
entry64.s:11:(.stab+0x20): relocation truncated to fit: R_X86_64_32 against `.text'
entry64.s:12:(.stab+0x2c): relocation truncated to fit: R_X86_64_32 against `.text'
entry64.s:12:(.stab+0x38): relocation truncated to fit: R_X86_64_32 against `.text'
What's causing these issues, and is this even a sensible approach to 64-bit higher half? I came across this thread and tried to find the NASM version of movabs without success, but I think it should've just loaded the 64-bit addresses correctly? Thank you in advance, and sorry if I've cluttered the post with too much code etc.
Last edited by isaacwoods on Tue Oct 10, 2017 11:41 am, edited 1 time in total.
Korona
Member
Member
Posts: 1000
Joined: Thu May 17, 2007 1:27 pm
Contact:

Re: 64-bit Higher Half relocation issues

Post by Korona »

Code: Select all

entry64.s:11:(.stab+0x14): relocation truncated to fit: R_X86_64_32 against `.text'
means that the linker cannot satisfy a relocation that has an offset larger than 4 GiB.

In 64-bit code things like loads from memory and jumps/calls are still limited to 4 GiB. As the address space is much larger, instead of 32-bit absolute offsets RIP-relative offsets are used. If you want absolute 64-bit addressing, you need to load the address into a register first (using movabs).

The offending code is

Code: Select all

lea rax, [Entry64]
Use

Code: Select all

movabs rax, Entry64
instead. (I'm not sure if your assembler uses the mov mnenomic for the movabs instruction but considering that your code does assemble with 64-bit mov instructions, I guess it does.)
managarm: Microkernel-based OS capable of running a Wayland desktop (Discord: https://discord.gg/7WB6Ur3). My OS-dev projects: [mlibc: Portable C library for managarm, qword, Linux, Sigma, ...] [LAI: AML interpreter] [xbstrap: Build system for OS distributions].
isaacwoods
Member
Member
Posts: 47
Joined: Sun Sep 06, 2015 5:40 am

Re: 64-bit Higher Half relocation issues

Post by isaacwoods »

Okay, so NASM doesn't provide movabs, but I've replaced the

Code: Select all

lea rax, [Entry64]
with:

Code: Select all

mov rax, qword Entry64
which seems to disassemble to (obviously it won't be clear whether this actually does the relocation correctly until the link succeeds):

Code: Select all

48 b8 00 00 00 00 00 00 00 00 movabs rax, 0x0
However, I still have problems. This hasn't got rid of the relocation problems in Entry64, nor has it produced correct code for this (with or without the 'qword'):

Code: Select all

add rdi, qword 0xffffff0000000000
turns into:

Code: Select all

48 83 c7 00       add rdi, 0x0
The 0x48 prefix leads me to think its worked out it needs to produce 64-bit code, but then it only emits a 1-byte immediate!
Korona
Member
Member
Posts: 1000
Joined: Thu May 17, 2007 1:27 pm
Contact:

Re: 64-bit Higher Half relocation issues

Post by Korona »

There is no "add r/m64, imm64". movabs is the only instruction that takes a 64-bit immediate value. So load the value into a register first and then add it.
managarm: Microkernel-based OS capable of running a Wayland desktop (Discord: https://discord.gg/7WB6Ur3). My OS-dev projects: [mlibc: Portable C library for managarm, qword, Linux, Sigma, ...] [LAI: AML interpreter] [xbstrap: Build system for OS distributions].
Octocontrabass
Member
Member
Posts: 5586
Joined: Mon Mar 25, 2013 7:01 pm

Re: 64-bit Higher Half relocation issues

Post by Octocontrabass »

BaconWraith wrote:What's causing these issues, and is this even a sensible approach to 64-bit higher half?
Most instructions can only use 32-bit immediates and offsets, even though you're in 64-bit mode. The only instruction that can use a 64-bit immediate or offset is MOV. (AT&T syntax calls this "movabs".)

Most developers choose a kernel base address around -2GB (0xFFFFFFFF80000000) so kernel symbols can use R_X86_64_32S relocations. This choice also gives the most freedom to user-mode software, since the lowest 2GB of address space may use both R_X86_64_32 and R_X86_64_32S relocations.
BaconWraith wrote:I came across this thread and tried to find the NASM version of movabs without success, but I think it should've just loaded the 64-bit addresses correctly?
The NASM equivalent of movabs looks like this:

Code: Select all

mov <r64>, qword <symbol>
mov al/ax/eax/rax, [qword <symbol>]
mov [qword <symbol>], al/ax/eax/rax
isaacwoods
Member
Member
Posts: 47
Joined: Sun Sep 06, 2015 5:40 am

Re: 64-bit Higher Half relocation issues

Post by isaacwoods »

Thank you both for your replies! I've read up a little on that and probably should've known that I needed to use mov to load 64-bit immediates :oops: . I've moved the kernel base to 0xffffffff80000000, but this doesn't get rid of the .stab relocation truncations. Looking into it, .stab seems to be a obsolete debug symbol format, so I tried making NASM use DWARF with -Fdwarf and this seems to fix the relocation issues with that. Of course, it still doesn't work, but I'll try to figure out that on my own! Thank you very much again for your help and advice, and sorry for it being such a simple set of fixes
Post Reply