diff options
| author | skrll <skrll@NetBSD.org> | 2023-05-07 12:41:45 +0000 |
|---|---|---|
| committer | skrll <skrll@NetBSD.org> | 2023-05-07 12:41:45 +0000 |
| commit | 0cdd33139a1c60797bd5002b4944b2faa9e2f9c6 (patch) | |
| tree | 6358f451321d60c76649dcd34633a6c1799fdb77 /libexec/ld.elf_so | |
| parent | 67090cda0ba82dccb26f986c355d2b5926cf73c4 (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.c | 139 | ||||
| -rw-r--r-- | libexec/ld.elf_so/arch/riscv/rtld_start.S | 35 |
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) |
