Page MenuHomeFreeBSD

D46278.diff
No OneTemporary

D46278.diff

diff --git a/libexec/rtld-elf/riscv/reloc.c b/libexec/rtld-elf/riscv/reloc.c
--- a/libexec/rtld-elf/riscv/reloc.c
+++ b/libexec/rtld-elf/riscv/reloc.c
@@ -152,10 +152,20 @@
for (rela = obj->pltrela; rela < relalim; rela++) {
Elf_Addr *where;
- assert(ELF_R_TYPE(rela->r_info) == R_RISCV_JUMP_SLOT);
-
where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
- *where += (Elf_Addr)obj->relocbase;
+
+ switch (ELF_R_TYPE(rela->r_info)) {
+ case R_RISCV_JUMP_SLOT:
+ *where += (Elf_Addr)obj->relocbase;
+ break;
+ case R_RISCV_IRELATIVE:
+ obj->irelative = true;
+ break;
+ default:
+ _rtld_error("Unknown relocation type %u in PLT",
+ (unsigned int)ELF_R_TYPE(rela->r_info));
+ return (-1);
+ }
}
return (0);
@@ -187,6 +197,11 @@
return (-1);
}
+ if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
+ obj->gnu_ifunc = true;
+ continue;
+ }
+
*where = (Elf_Addr)(defobj->relocbase + def->st_value);
break;
default:
@@ -199,30 +214,89 @@
return (0);
}
+static void
+reloc_iresolve_one(Obj_Entry *obj, const Elf_Rela *rela,
+ RtldLockState *lockstate)
+{
+ Elf_Addr *where, target, *ptr;
+
+ ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend);
+ where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
+ lock_release(rtld_bind_lock, lockstate);
+ target = call_ifunc_resolver(ptr);
+ wlock_acquire(rtld_bind_lock, lockstate);
+ *where = target;
+}
+
int
-reloc_iresolve(Obj_Entry *obj __unused,
- struct Struct_RtldLockState *lockstate __unused)
+reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
{
+ const Elf_Rela *relalim;
+ const Elf_Rela *rela;
+
+ if (!obj->irelative)
+ return (0);
- /* XXX not implemented */
+ obj->irelative = false;
+ relalim = (const Elf_Rela *)((const char *)obj->pltrela +
+ obj->pltrelasize);
+ for (rela = obj->pltrela; rela < relalim; rela++) {
+ if (ELF_R_TYPE(rela->r_info) == R_RISCV_IRELATIVE)
+ reloc_iresolve_one(obj, rela, lockstate);
+ }
return (0);
}
int
-reloc_iresolve_nonplt(Obj_Entry *obj __unused,
- struct Struct_RtldLockState *lockstate __unused)
+reloc_iresolve_nonplt(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
{
+ const Elf_Rela *relalim;
+ const Elf_Rela *rela;
- /* XXX not implemented */
+ if (!obj->irelative_nonplt)
+ return (0);
+
+ obj->irelative_nonplt = false;
+ relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize);
+ for (rela = obj->rela; rela < relalim; rela++) {
+ if (ELF_R_TYPE(rela->r_info) == R_RISCV_IRELATIVE)
+ reloc_iresolve_one(obj, rela, lockstate);
+ }
return (0);
}
int
-reloc_gnu_ifunc(Obj_Entry *obj __unused, int flags __unused,
- struct Struct_RtldLockState *lockstate __unused)
+reloc_gnu_ifunc(Obj_Entry *obj, int flags,
+ struct Struct_RtldLockState *lockstate)
{
+ const Elf_Rela *relalim;
+ const Elf_Rela *rela;
+ Elf_Addr *where, target;
+ const Elf_Sym *def;
+ const Obj_Entry *defobj;
+
+ if (!obj->gnu_ifunc)
+ return (0);
- /* XXX not implemented */
+ relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize);
+ for (rela = obj->pltrela; rela < relalim; rela++) {
+ if (ELF_R_TYPE(rela->r_info) == R_RISCV_JUMP_SLOT) {
+ where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
+ def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
+ SYMLOOK_IN_PLT | flags, NULL, lockstate);
+ if (def == NULL)
+ return (-1);
+ if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC)
+ continue;
+
+ lock_release(rtld_bind_lock, lockstate);
+ target = (Elf_Addr)rtld_resolve_ifunc(defobj, def);
+ wlock_acquire(rtld_bind_lock, lockstate);
+ reloc_jmpslot(where, target, defobj, obj,
+ (const Elf_Rel *)rela);
+ }
+ }
+ obj->gnu_ifunc = false;
return (0);
}
@@ -232,7 +306,8 @@
const Elf_Rel *rel)
{
- assert(ELF_R_TYPE(rel->r_info) == R_RISCV_JUMP_SLOT);
+ assert(ELF_R_TYPE(rel->r_info) == R_RISCV_JUMP_SLOT ||
+ ELF_R_TYPE(rel->r_info) == R_RISCV_IRELATIVE);
if (*where != target && !ld_bind_not)
*where = target;
@@ -251,13 +326,9 @@
const Elf_Rela *rela;
const Elf_Sym *def;
SymCache *cache;
- Elf_Addr *where;
+ Elf_Addr *where, symval;
unsigned long symnum;
- if ((flags & SYMLOOK_IFUNC) != 0)
- /* XXX not implemented */
- return (0);
-
/*
* The dynamic loader may be called from a thread, we have
* limited amounts of stack available so we cannot use alloca().
@@ -285,8 +356,27 @@
if (def == NULL)
return (-1);
- *where = (Elf_Addr)(defobj->relocbase + def->st_value +
- rela->r_addend);
+ /*
+ * If symbol is IFUNC, only perform relocation
+ * when caller allowed it by passing
+ * SYMLOOK_IFUNC flag. Skip the relocations
+ * otherwise.
+ */
+ if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
+ if ((flags & SYMLOOK_IFUNC) == 0) {
+ obj->non_plt_gnu_ifunc = true;
+ continue;
+ }
+ symval = (Elf_Addr)rtld_resolve_ifunc(defobj,
+ def);
+ } else {
+ if ((flags & SYMLOOK_IFUNC) != 0)
+ continue;
+ symval = (Elf_Addr)(defobj->relocbase +
+ def->st_value);
+ }
+
+ *where = symval + rela->r_addend;
break;
case R_RISCV_TLS_DTPMOD64:
def = find_symdef(symnum, obj, &defobj, flags, cache,
@@ -365,6 +455,9 @@
case R_RISCV_RELATIVE:
*where = (Elf_Addr)(obj->relocbase + rela->r_addend);
break;
+ case R_RISCV_IRELATIVE:
+ obj->irelative_nonplt = true;
+ break;
default:
rtld_printf("%s: Unhandled relocation %lu\n",
obj->path, ELF_R_TYPE(rela->r_info));
@@ -375,10 +468,13 @@
return (0);
}
+unsigned long elf_hwcap;
+
void
-ifunc_init(Elf_Auxinfo *aux_info[__min_size(AT_COUNT)] __unused)
+ifunc_init(Elf_Auxinfo *aux_info[__min_size(AT_COUNT)])
{
-
+ if (aux_info[AT_HWCAP] != NULL)
+ elf_hwcap = aux_info[AT_HWCAP]->a_un.a_val;
}
void
diff --git a/libexec/rtld-elf/riscv/rtld_machdep.h b/libexec/rtld-elf/riscv/rtld_machdep.h
--- a/libexec/rtld-elf/riscv/rtld_machdep.h
+++ b/libexec/rtld-elf/riscv/rtld_machdep.h
@@ -83,8 +83,11 @@
__asm __volatile("mv gp, %0" :: "r"(old1)); \
})
+extern unsigned long elf_hwcap;
#define call_ifunc_resolver(ptr) \
- (((Elf_Addr (*)(void))ptr)())
+ (((Elf_Addr (*)(unsigned long, unsigned long, unsigned long, \
+ unsigned long, unsigned long, unsigned long, unsigned long, \
+ unsigned long))ptr)(elf_hwcap, 0, 0, 0, 0, 0, 0, 0))
/*
* TLS

File Metadata

Mime Type
text/plain
Expires
Tue, Nov 19, 9:25 PM (21 h, 36 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14723744
Default Alt Text
D46278.diff (6 KB)

Event Timeline