summaryrefslogtreecommitdiff
path: root/libexec/ld.elf_so
diff options
context:
space:
mode:
authorskrll <skrll@NetBSD.org>2023-05-07 12:41:45 +0000
committerskrll <skrll@NetBSD.org>2023-05-07 12:41:45 +0000
commit0cdd33139a1c60797bd5002b4944b2faa9e2f9c6 (patch)
tree6358f451321d60c76649dcd34633a6c1799fdb77 /libexec/ld.elf_so
parent67090cda0ba82dccb26f986c355d2b5926cf73c4 (diff)
RISC-V support that works on QEMU with a single hart.
Thanks for Simon Burge for plic(4).
Diffstat (limited to 'libexec/ld.elf_so')
-rw-r--r--libexec/ld.elf_so/arch/riscv/mdreloc.c139
-rw-r--r--libexec/ld.elf_so/arch/riscv/rtld_start.S35
2 files changed, 116 insertions, 58 deletions
diff --git a/libexec/ld.elf_so/arch/riscv/mdreloc.c b/libexec/ld.elf_so/arch/riscv/mdreloc.c
index 666320dc468..05cc4b81906 100644
--- a/libexec/ld.elf_so/arch/riscv/mdreloc.c
+++ b/libexec/ld.elf_so/arch/riscv/mdreloc.c
@@ -1,4 +1,4 @@
-/* $NetBSD: mdreloc.c,v 1.7 2022/12/05 07:26:25 skrll Exp $ */
+/* $NetBSD: mdreloc.c,v 1.8 2023/05/07 12:41:48 skrll Exp $ */
/*-
* Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: mdreloc.c,v 1.7 2022/12/05 07:26:25 skrll Exp $");
+__RCSID("$NetBSD: mdreloc.c,v 1.8 2023/05/07 12:41:48 skrll Exp $");
#endif /* not lint */
#include <sys/types.h>
@@ -84,7 +84,7 @@ _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
rdbg(("RELATIVE/L(%p) -> %p in <self>",
where, (void *)val));
break;
- }
+ }
case R_TYPE(NONE):
break;
@@ -113,6 +113,7 @@ _rtld_relocate_nonplt_objects(Obj_Entry *obj)
case R_TYPESZ(ADDR):
case R_TYPESZ(TLS_DTPMOD):
case R_TYPESZ(TLS_DTPREL):
+ case R_TYPESZ(TLS_TPREL):
symnum = ELF_R_SYM(rela->r_info);
if (last_symnum != symnum) {
last_symnum = symnum;
@@ -131,63 +132,97 @@ _rtld_relocate_nonplt_objects(Obj_Entry *obj)
break;
case R_TYPE(RELATIVE): {
- symnum = ELF_R_SYM(rela->r_info);
- def = obj->symtab + symnum;
-
- Elf_Addr val = (Elf_Addr)obj->relocbase + rela->r_addend;
+ const Elf_Addr val = (Elf_Addr)obj->relocbase +
+ rela->r_addend;
rdbg(("RELATIVE(%p) -> %p (%s) in %s",
where, (void *)val,
- obj->strtab + def->st_name, obj->path));
+ obj->strtab +
+ obj->symtab[ELF_R_SYM(rela->r_info)].st_name,
+ obj->path));
*where = val;
break;
- }
+ }
case R_TYPESZ(ADDR): {
- Elf_Addr val = (Elf_Addr)defobj->relocbase + rela->r_addend;
+ const Elf_Addr val = (Elf_Addr)defobj->relocbase +
+ def->st_value + rela->r_addend;
+
+ rdbg(("ADDR(%p) -> %p (%s) in %s%s",
+ where, (void *)val,
+ obj->strtab +
+ obj->symtab[ELF_R_SYM(rela->r_info)].st_name,
+ obj->path,
+ def == &_rtld_sym_zero ? " (symzero)" : ""));
*where = val;
- rdbg(("ADDR %s in %s --> %p in %s",
- obj->strtab + obj->symtab[r_symndx].st_name,
- obj->path, (void *)val, defobj->path));
break;
- }
+ }
+
+ case R_TYPE(COPY):
+ /*
+ * These are deferred until all other relocations have
+ * been done. All we do here is make sure that the
+ * COPY relocation is not in a shared library. They
+ * are allowed only in executable files.
+ */
+ if (obj->isdynamic) {
+ _rtld_error("%s: Unexpected R_COPY relocation"
+ " in shared library", obj->path);
+ return -1;
+ }
+ rdbg(("COPY (avoid in main)"));
+ break;
case R_TYPESZ(TLS_DTPMOD): {
- Elf_Addr val = (Elf_Addr)defobj->tlsindex + rela->r_addend;
+ const Elf_Addr val = (Elf_Addr)defobj->tlsindex;
+
+ rdbg(("TLS_DTPMOD(%p) -> %p (%s) in %s",
+ where, (void *)val,
+ obj->strtab +
+ obj->symtab[ELF_R_SYM(rela->r_info)].st_name,
+ obj->path));
*where = val;
- rdbg(("DTPMOD %s in %s --> %p in %s",
- obj->strtab + obj->symtab[r_symndx].st_name,
- obj->path, (void *)val, defobj->path));
break;
- }
+ }
case R_TYPESZ(TLS_DTPREL): {
- Elf_Addr old = *where;
- Elf_Addr val = old;
+ const Elf_Addr val = (Elf_Addr)(def->st_value +
+ rela->r_addend - TLS_DTV_OFFSET);
- if (!defobj->tls_done && _rtld_tls_offset_allocate(obj))
- return -1;
+ rdbg(("TLS_DTPREL(%p) -> %p (%s) in %s",
+ where, (void *)val,
+ obj->strtab +
+ obj->symtab[ELF_R_SYM(rela->r_info)].st_name,
+ defobj->path));
- val = (Elf_Addr)def->st_value - TLS_DTV_OFFSET;
*where = val;
+ break;
+ }
- rdbg(("DTPREL %s in %s --> %p in %s",
- obj->strtab + obj->symtab[r_symndx].st_name,
- obj->path, (void *)val, defobj->path));
+ case R_TYPESZ(TLS_TPREL):
+ if (!defobj->tls_done &&
+ _rtld_tls_offset_allocate(obj))
+ return -1;
+
+ *where = (Elf_Addr)(def->st_value + defobj->tlsoffset +
+ rela->r_addend);
+
+ rdbg(("TLS_TPREL %s in %s --> %p in %s",
+ obj->strtab +
+ obj->symtab[ELF_R_SYM(rela->r_info)].st_name,
+ obj->path, (void *)*where, defobj->path));
break;
- }
default:
rdbg(("sym = %lu, type = %lu, offset = %p, "
- "addend = %p, contents = %p, symbol = %s",
+ "addend = %p, contents = %p",
(u_long)ELF_R_SYM(rela->r_info),
(u_long)ELF_R_TYPE(rela->r_info),
(void *)rela->r_offset, (void *)rela->r_addend,
- (void *)load_ptr(where, sizeof(Elf_Addr)),
- obj->strtab + obj->symtab[r_symndx].st_name));
+ (void *)*where));
_rtld_error("%s: Unsupported relocation type %ld "
"in non-PLT relocations",
obj->path, (u_long)r_type);
@@ -201,7 +236,23 @@ _rtld_relocate_nonplt_objects(Obj_Entry *obj)
int
_rtld_relocate_plt_lazy(Obj_Entry *obj)
{
- /* PLT fixups were done above in the GOT relocation. */
+
+ if (!obj->relocbase)
+ return 0;
+
+ for (const Elf_Rela *rela = obj->pltrela; rela < obj->pltrelalim; rela++) {
+ Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
+ switch (ELF_R_TYPE(rela->r_info)) {
+ case R_TYPE(JMP_SLOT):
+ /* Just relocate the GOT slots pointing into the PLT */
+ *where += (Elf_Addr)obj->relocbase;
+ rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where));
+ break;
+ default:
+ rdbg(("not yet... %d", (int)ELF_R_TYPE(rela->r_info) ));
+ }
+ }
+
return 0;
}
@@ -209,6 +260,7 @@ static int
_rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela,
Elf_Addr *tp)
{
+ Elf_Addr * const where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
const Obj_Entry *defobj;
Elf_Addr new_value;
@@ -228,29 +280,32 @@ _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela,
} else {
new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
}
- rdbg(("bind now/fixup in %s --> new=%p",
- defobj->strtab + def->st_name, (void *)new_value));
- *(Elf_Addr *)(obj->relocbase + rela->r_offset) = new_value;
-
+ rdbg(("bind now/fixup in %s --> old=%p new=%p",
+ defobj->strtab + def->st_name, (void *)*where,
+ (void *)new_value));
+ if (*where != new_value)
+ *where = new_value;
if (tp)
*tp = new_value;
+
return 0;
}
void *
-_rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
+_rtld_bind(const Obj_Entry *obj, Elf_Word gotoff)
{
- const Elf_Rela *pltrel = (const Elf_Rela *)(obj->pltrel + reloff);
- Elf_Addr new_value;
- int err;
+ const Elf_Addr relidx = (gotoff / sizeof(Elf_Addr));
+ const Elf_Rela *pltrela = obj->pltrela + relidx;
+
+ Elf_Addr new_value = 0;
_rtld_shared_enter();
- err = _rtld_relocate_plt_object(obj, pltrel, &new_value);
+ const int err = _rtld_relocate_plt_object(obj, pltrela, &new_value);
if (err)
_rtld_die();
_rtld_shared_exit();
- return (caddr_t)new_value;
+ return (void *)new_value;
}
int
diff --git a/libexec/ld.elf_so/arch/riscv/rtld_start.S b/libexec/ld.elf_so/arch/riscv/rtld_start.S
index 94b6f5dc0fd..d0f97dfea96 100644
--- a/libexec/ld.elf_so/arch/riscv/rtld_start.S
+++ b/libexec/ld.elf_so/arch/riscv/rtld_start.S
@@ -1,4 +1,4 @@
-/* $NetBSD: rtld_start.S,v 1.5 2022/12/05 07:33:43 skrll Exp $ */
+/* $NetBSD: rtld_start.S,v 1.6 2023/05/07 12:41:48 skrll Exp $ */
/*-
* Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -34,23 +34,22 @@
.globl _C_LABEL(_rtld_relocate_nonplt_self)
.globl _C_LABEL(_rtld)
-#if __SIZEOF_POINTER__ != SZREG
-#error SZREG is the wrong size
-#endif
+#define PTRSZ __SIZEOF_POINTER__
/*
* void
- * ___start(void (*cleanup)(void),
- * const Obj_Entry *obj,
- * struct ps_strings *ps_strings)
+ * ___start(
+ * void (*cleanup)(void),
+ * struct ps_strings *ps_strings
+ * )
*/
+
ENTRY(_rtld_start)
mv s0, sp # save stack pointer
- addi sp, sp, -4 * SZREG
- # adjust stack pointer
+ addi sp, sp, -4 * PTRSZ # adjust stack pointer
# -> 2 * PTR_SIZE(sp) for atexit
# -> 3 * PTR_SIZE(sp) for obj_main
- mv s1, a2 # save ps_strings pointer
+ mv s1, a1 # save ps_strings pointer
.L0: auipc gp, %pcrel_hi(_GLOBAL_OFFSET_TABLE_)
PTR_L t0, %pcrel_lo(.L0)(gp) # &_DYNAMIC
@@ -61,18 +60,22 @@ ENTRY(_rtld_start)
call _C_LABEL(_rtld_relocate_nonplt_self)
mv a1, s2 # relocbase
- addi a0, sp, 2 * SZREG # sp
+ addi a0, sp, 2 * PTRSZ # sp
call _C_LABEL(_rtld) # a0 = _rtld(sp, relocbase)
mv t0, a0
- PTR_L a0, 2 * SZREG(sp) # cleanup function
- PTR_L a1, 3 * SZREG(sp) # obj_main entry
- mv a2, s1 # restore ps_strings
- mv sp, s0 # readjust stack
+ PTR_L a0, 2 * PTRSZ(sp) # cleanup function
+// PTR_L a1, 3 * PTRSZ(sp) # obj_main pointer (not used)
+ mv a1, s1 # restore ps_strings
+ mv sp, s0 # restore stack pointer
mv s0, zero # break stack chain
- jr t0 # _start(cleanup, obj_main, ps_strings);
+ jr t0 # _start(cleanup, ps_strings);
END(_rtld_start)
+/*
+ * Needs to be 12 so that stack alignment is preserved on both RV32 and RV64.
+ */
+
#define XCALLFRAME_SIZ (12 * SZREG)
#define XCALLFRAME_RA ( 8 * SZREG)
#define XCALLFRAME_A7 ( 7 * SZREG)