Browse Source

LibELF: Add riscv64 PLT trampoline

This code is based on the aarch64 implementation.
Sönke Holz 1 year ago
parent
commit
525555181e

+ 74 - 3
Userland/Libraries/LibELF/Arch/riscv64/plt_trampoline.S

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, Sönke Holz <sholz8530@gmail.com>
+ * Copyright (c) 2023-2024, Sönke Holz <sholz8530@gmail.com>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
@@ -9,6 +9,77 @@
 .hidden _plt_trampoline
 .type _plt_trampoline,@function
 
+// This function is called by the PLT stub to resolve functions lazily at runtime.
+// It saves off any argument registers that might be clobbered by the symbol
+// resolution code, calls that, and then jumps to the resolved function.
+//
+// See section 8.4.6 "Program Linkage Table" of the RISC-V psABI.
+// https://github.com/riscv-non-isa/riscv-elf-psabi-doc/releases/download/v1.0/riscv-abi.pdf
+//
+// The calling convention is:
+//   t0 = .got.plt[1] (DynamicObject*)
+//   t1 = .got.plt offset
 _plt_trampoline:
-    // FIXME: Implement the PLT trampoline.
-    unimp
+    // Save argument registers a0-a7, fa0-fa7 and ra.
+    addi sp, sp, -(18 * 8)
+
+    sd a0, 0*8(sp)
+    sd a1, 1*8(sp)
+    sd a2, 2*8(sp)
+    sd a3, 3*8(sp)
+    sd a4, 4*8(sp)
+    sd a5, 5*8(sp)
+    sd a6, 6*8(sp)
+    sd a7, 7*8(sp)
+
+    // NOTE: We only support ABI_FLEN=64 in LibELF/Validation.cpp,
+    //       so we only save the lower 64 bits of the fa* registers.
+    fsd fa0, 8*8(sp)
+    fsd fa1, 9*8(sp)
+    fsd fa2, 10*8(sp)
+    fsd fa3, 11*8(sp)
+    fsd fa4, 12*8(sp)
+    fsd fa5, 13*8(sp)
+    fsd fa6, 14*8(sp)
+    fsd fa7, 15*8(sp)
+
+    sd ra, 16*8(sp)
+
+    // The DynamicObject* is in t0.
+    mv a0, t0
+
+    // GOT entries are 8 bytes, but sizeof(Elf64_Rela) == 24, so multiply
+    // t1 by 3 to get the relocation offset.
+    slli a1, t1, 1
+    add a1, a1, t1
+
+    call _fixup_plt_entry
+
+    // Save the resolved function's address.
+    mv t0, a0
+
+    // Restore argument registers and ra.
+    ld a0, 0*8(sp)
+    ld a1, 1*8(sp)
+    ld a2, 2*8(sp)
+    ld a3, 3*8(sp)
+    ld a4, 4*8(sp)
+    ld a5, 5*8(sp)
+    ld a6, 6*8(sp)
+    ld a7, 7*8(sp)
+
+    fld fa0, 8*8(sp)
+    fld fa1, 9*8(sp)
+    fld fa2, 10*8(sp)
+    fld fa3, 11*8(sp)
+    fld fa4, 12*8(sp)
+    fld fa5, 13*8(sp)
+    fld fa6, 14*8(sp)
+    fld fa7, 15*8(sp)
+
+    ld ra, 16*8(sp)
+
+    addi sp, sp, 18 * 8
+
+    // Jump to the resolved function.
+    jr t0

+ 8 - 0
Userland/Libraries/LibELF/DynamicLoader.cpp

@@ -790,8 +790,16 @@ void DynamicLoader::setup_plt_trampoline()
     VirtualAddress got_address = m_dynamic_object->plt_got_base_address();
 
     auto* got_ptr = (FlatPtr*)got_address.as_ptr();
+
+#if ARCH(AARCH64) || ARCH(X86_64)
     got_ptr[1] = (FlatPtr)m_dynamic_object.ptr();
     got_ptr[2] = (FlatPtr)&_plt_trampoline;
+#elif ARCH(RISCV64)
+    got_ptr[0] = (FlatPtr)&_plt_trampoline;
+    got_ptr[1] = (FlatPtr)m_dynamic_object.ptr();
+#else
+#    error Unknown architecture
+#endif
 }
 
 // Called from our ASM routine _plt_trampoline.