nasm:从 rip(指令指针)获取运行时重定位二进制文件的偏移量
nasm: get offset of relocated binary during runtime from rip (instruction pointer)
我有一个 x86_64 的 multiboot2 兼容 ELF 文件,其中 start-symbol 在 start.asm
中定义,一个 NASM 汇编文件。 multiboot2 header 包含 relocatable
标签。
因为 GRUB 不支持 multiboot2 + 可重定位的 ELF(至少在 2021 年 7 月 [3]),我想自己解决一些重定位来解决这个问题,只加载静态 ELF。
为此,我需要在我的第一个 entry-symbol(在 ELF header 中指定)在运行时获取偏移量,以便手动解析重定位。偏移量是指 GRUB 在内存中定位二进制文件的位置与 ELF 文件中符号的静态地址相比的差异。
在我的输入符号中,我处于 64 位长模式。在 NASM 语法中无法直接访问 rip
,因此我需要某种解决方法。
[1] [2] 之类的解决方案不起作用,因为 rip
keyword/register 在 NASM 中不可用。因此我不能使用
lea rax,[rip+0x1020304]
; rax contains offset
sub rax,0x1020304
我该如何解决这个问题?
在 nasm
中访问 rip
的唯一方法是通过 rel
-关键字 [1]。如果没有一个奇怪的解决方法,它不能立即使用,而只能使用一个符号。要用符号解决它,下面的代码有效:
; 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
请注意,这真的很棘手,需要对几个低级主题有深入的了解。谨慎使用。
我有一个 x86_64 的 multiboot2 兼容 ELF 文件,其中 start-symbol 在 start.asm
中定义,一个 NASM 汇编文件。 multiboot2 header 包含 relocatable
标签。
因为 GRUB 不支持 multiboot2 + 可重定位的 ELF(至少在 2021 年 7 月 [3]),我想自己解决一些重定位来解决这个问题,只加载静态 ELF。
为此,我需要在我的第一个 entry-symbol(在 ELF header 中指定)在运行时获取偏移量,以便手动解析重定位。偏移量是指 GRUB 在内存中定位二进制文件的位置与 ELF 文件中符号的静态地址相比的差异。
在我的输入符号中,我处于 64 位长模式。在 NASM 语法中无法直接访问 rip
,因此我需要某种解决方法。
[1] [2] 之类的解决方案不起作用,因为 rip
keyword/register 在 NASM 中不可用。因此我不能使用
lea rax,[rip+0x1020304]
; rax contains offset
sub rax,0x1020304
我该如何解决这个问题?
在 nasm
中访问 rip
的唯一方法是通过 rel
-关键字 [1]。如果没有一个奇怪的解决方法,它不能立即使用,而只能使用一个符号。要用符号解决它,下面的代码有效:
; 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
请注意,这真的很棘手,需要对几个低级主题有深入的了解。谨慎使用。