Reputation: 6140
I have a multiboot2-compliant ELF file for x86_64, where the start-symbol is defined in start.asm
, a NASM assembly file. The multiboot2 header contains the relocatable
tag.
Because GRUB doesn't support multiboot2 + a relocatable ELF (at least in July 2021 [3]), I want to resolve some relocations by myself to work around this and just load a static ELF.
For this I need to get the offset during runtime in my very first entry-symbol (specified in ELF header) in order to resolve relocations manually. With offset I mean the difference where GRUB located the binary in memory compared to the static address of the symbol in the ELF file.
In my entry symbol I'm in 64-bit long mode. It is not possible to directly access rip
in NASM syntax, therefore I need some kind of workaround.
Solutions like [1] [2] do not work, because the rip
keyword/register is not usable in NASM. Therefore I can't use
lea rax,[rip+0x1020304]
; rax contains offset
sub rax,0x1020304
How can I solve this?
Upvotes: 1
Views: 460
Reputation: 6140
The only way to access rip
in nasm
is through the rel
-keyword [1]. Without an odd workaround, it can't take an immediate but only a symbol. To solve it with a symbol, the following code works:
; the function we want to jump to. We need to calculate the runtime
; address manually, because the ELF file is not relocatable, therefore static.
EXTERN entry_64_bit
; start symbol must be globally available (linker must find it, don't discard it)
; Referenced in ELF-Header.
GLOBAL start
SECTION .text
; always produce x-bit x86 code (even if this would be compiled to an ELF-32 file)
[BITS 64]
; very first entry point; this is the address where GRUB loads the binary
start:
; save values provided by multiboot2 bootloader (removed here)
; ...
; Set stack top (removed here)
; ...
; rbx: static link address
mov rbx, .eff_addr_magic_end
; rax: runtime address (relative to instruction pointer)
lea rax, [rel + .eff_addr_magic_end]
.eff_addr_magic_end:
; subtract address difference => offset
sub rax, rbx
; rax: address of Rust entry point (static link address + runtime offset)
add rax, entry_64_bit
jmp rax
Note that this is really tricky and needs deep expertise about several low level topics. Use with caution.
Upvotes: 3