svn commit: r229503 - in stable/9/libexec/rtld-elf: . amd64 arm
i386 ia64 mips powerpc powerpc64 sparc64
Konstantin Belousov
kib at FreeBSD.org
Wed Jan 4 16:43:29 UTC 2012
Author: kib
Date: Wed Jan 4 16:43:29 2012
New Revision: 229503
URL: http://svn.freebsd.org/changeset/base/229503
Log:
MFC r228435:
Add support for STT_GNU_IFUNC and R_MACHINE_IRELATIVE GNU extensions to
rtld on 386 and amd64.
MFC r228503:
Postpone the resolution for irelative/ifunc right before initializers
are called, and drop bind lock around calls to dispatcher. Use
initlist to iterate over the objects instead of the ->next, due to
drop of the bind lock in iteration.
For i386/reloc.c:reloc_iresolve(), fix calculation of the dispatch
function address for dso, by taking into account possible non-zero
relocbase.
MFC r228635 (by nwhitehorn):
Fix RTLD on PowerPC after r228435. Changing the order of init_pltgot()
caused the icache to be invalidated at the wrong time, resulting in
an icache full of nonsense in the PLT section.
Modified:
stable/9/libexec/rtld-elf/amd64/reloc.c
stable/9/libexec/rtld-elf/arm/reloc.c
stable/9/libexec/rtld-elf/i386/reloc.c
stable/9/libexec/rtld-elf/ia64/reloc.c
stable/9/libexec/rtld-elf/mips/reloc.c
stable/9/libexec/rtld-elf/powerpc/reloc.c
stable/9/libexec/rtld-elf/powerpc64/reloc.c
stable/9/libexec/rtld-elf/rtld.c
stable/9/libexec/rtld-elf/rtld.h
stable/9/libexec/rtld-elf/sparc64/reloc.c
Directory Properties:
stable/9/libexec/rtld-elf/ (props changed)
Modified: stable/9/libexec/rtld-elf/amd64/reloc.c
==============================================================================
--- stable/9/libexec/rtld-elf/amd64/reloc.c Wed Jan 4 16:43:08 2012 (r229502)
+++ stable/9/libexec/rtld-elf/amd64/reloc.c Wed Jan 4 16:43:29 2012 (r229503)
@@ -344,11 +344,22 @@ reloc_plt(Obj_Entry *obj)
for (rela = obj->pltrela; rela < relalim; rela++) {
Elf_Addr *where;
- assert(ELF_R_TYPE(rela->r_info) == R_X86_64_JMP_SLOT);
-
- /* Relocate the GOT slot pointing into the PLT. */
- where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
- *where += (Elf_Addr)obj->relocbase;
+ switch(ELF_R_TYPE(rela->r_info)) {
+ case R_X86_64_JMP_SLOT:
+ /* Relocate the GOT slot pointing into the PLT. */
+ where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
+ *where += (Elf_Addr)obj->relocbase;
+ break;
+
+ case R_X86_64_IRELATIVE:
+ obj->irelative = true;
+ break;
+
+ default:
+ _rtld_error("Unknown relocation type %x in PLT",
+ (unsigned int)ELF_R_TYPE(rela->r_info));
+ return (-1);
+ }
}
return 0;
}
@@ -368,19 +379,98 @@ reloc_jmpslots(Obj_Entry *obj, RtldLockS
const Elf_Sym *def;
const Obj_Entry *defobj;
- assert(ELF_R_TYPE(rela->r_info) == R_X86_64_JMP_SLOT);
- where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
- def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, true, NULL,
- lockstate);
- if (def == NULL)
- return -1;
- target = (Elf_Addr)(defobj->relocbase + def->st_value + rela->r_addend);
- reloc_jmpslot(where, target, defobj, obj, (const Elf_Rel *)rela);
+ switch (ELF_R_TYPE(rela->r_info)) {
+ case R_X86_64_JMP_SLOT:
+ where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
+ def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, true, NULL,
+ lockstate);
+ if (def == NULL)
+ return (-1);
+ if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
+ obj->gnu_ifunc = true;
+ continue;
+ }
+ target = (Elf_Addr)(defobj->relocbase + def->st_value + rela->r_addend);
+ reloc_jmpslot(where, target, defobj, obj, (const Elf_Rel *)rela);
+ break;
+
+ case R_X86_64_IRELATIVE:
+ break;
+
+ default:
+ _rtld_error("Unknown relocation type %x in PLT",
+ (unsigned int)ELF_R_TYPE(rela->r_info));
+ return (-1);
+ }
}
obj->jmpslots_done = true;
return 0;
}
+int
+reloc_iresolve(Obj_Entry *obj, RtldLockState *lockstate)
+{
+ const Elf_Rela *relalim;
+ const Elf_Rela *rela;
+
+ if (!obj->irelative)
+ return (0);
+ relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize);
+ for (rela = obj->pltrela; rela < relalim; rela++) {
+ Elf_Addr *where, target, *ptr;
+
+ switch (ELF_R_TYPE(rela->r_info)) {
+ case R_X86_64_JMP_SLOT:
+ break;
+
+ case R_X86_64_IRELATIVE:
+ ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend);
+ where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
+ lock_release(rtld_bind_lock, lockstate);
+ target = ((Elf_Addr (*)(void))ptr)();
+ wlock_acquire(rtld_bind_lock, lockstate);
+ *where = target;
+ break;
+ }
+ }
+ obj->irelative = false;
+ return (0);
+}
+
+int
+reloc_gnu_ifunc(Obj_Entry *obj, RtldLockState *lockstate)
+{
+ const Elf_Rela *relalim;
+ const Elf_Rela *rela;
+
+ if (!obj->gnu_ifunc)
+ return (0);
+ relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize);
+ for (rela = obj->pltrela; rela < relalim; rela++) {
+ Elf_Addr *where, target;
+ const Elf_Sym *def;
+ const Obj_Entry *defobj;
+
+ switch (ELF_R_TYPE(rela->r_info)) {
+ case R_X86_64_JMP_SLOT:
+ where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
+ def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, true, 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);
+ break;
+ }
+ }
+ obj->gnu_ifunc = false;
+ return (0);
+}
+
void
allocate_initial_tls(Obj_Entry *objs)
{
Modified: stable/9/libexec/rtld-elf/arm/reloc.c
==============================================================================
--- stable/9/libexec/rtld-elf/arm/reloc.c Wed Jan 4 16:43:08 2012 (r229502)
+++ stable/9/libexec/rtld-elf/arm/reloc.c Wed Jan 4 16:43:29 2012 (r229503)
@@ -337,6 +337,22 @@ reloc_jmpslots(Obj_Entry *obj, RtldLockS
return (0);
}
+int
+reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
+{
+
+ /* XXX not implemented */
+ return (0);
+}
+
+int
+reloc_gnu_ifunc(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
+{
+
+ /* XXX not implemented */
+ return (0);
+}
+
Elf_Addr
reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj,
const Obj_Entry *obj, const Elf_Rel *rel)
Modified: stable/9/libexec/rtld-elf/i386/reloc.c
==============================================================================
--- stable/9/libexec/rtld-elf/i386/reloc.c Wed Jan 4 16:43:08 2012 (r229502)
+++ stable/9/libexec/rtld-elf/i386/reloc.c Wed Jan 4 16:43:29 2012 (r229503)
@@ -298,13 +298,24 @@ reloc_plt(Obj_Entry *obj)
rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
for (rel = obj->pltrel; rel < rellim; rel++) {
- Elf_Addr *where;
+ Elf_Addr *where/*, val*/;
- assert(ELF_R_TYPE(rel->r_info) == R_386_JMP_SLOT);
-
- /* Relocate the GOT slot pointing into the PLT. */
- where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
- *where += (Elf_Addr)obj->relocbase;
+ switch (ELF_R_TYPE(rel->r_info)) {
+ case R_386_JMP_SLOT:
+ /* Relocate the GOT slot pointing into the PLT. */
+ where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
+ *where += (Elf_Addr)obj->relocbase;
+ break;
+
+ case R_386_IRELATIVE:
+ obj->irelative = true;
+ break;
+
+ default:
+ _rtld_error("Unknown relocation type %x in PLT",
+ ELF_R_TYPE(rel->r_info));
+ return (-1);
+ }
}
return 0;
}
@@ -324,19 +335,95 @@ reloc_jmpslots(Obj_Entry *obj, RtldLockS
const Elf_Sym *def;
const Obj_Entry *defobj;
- assert(ELF_R_TYPE(rel->r_info) == R_386_JMP_SLOT);
- where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
- def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true, NULL,
- lockstate);
- if (def == NULL)
- return -1;
- target = (Elf_Addr)(defobj->relocbase + def->st_value);
- reloc_jmpslot(where, target, defobj, obj, rel);
+ switch (ELF_R_TYPE(rel->r_info)) {
+ case R_386_JMP_SLOT:
+ where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
+ def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true, NULL,
+ lockstate);
+ if (def == NULL)
+ return (-1);
+ if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
+ obj->gnu_ifunc = true;
+ continue;
+ }
+ target = (Elf_Addr)(defobj->relocbase + def->st_value);
+ reloc_jmpslot(where, target, defobj, obj, rel);
+ break;
+
+ case R_386_IRELATIVE:
+ break;
+
+ default:
+ _rtld_error("Unknown relocation type %x in PLT",
+ ELF_R_TYPE(rel->r_info));
+ return (-1);
+ }
}
+
obj->jmpslots_done = true;
return 0;
}
+int
+reloc_iresolve(Obj_Entry *obj, RtldLockState *lockstate)
+{
+ const Elf_Rel *rellim;
+ const Elf_Rel *rel;
+ Elf_Addr *where, target;
+
+ if (!obj->irelative)
+ return (0);
+ rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
+ for (rel = obj->pltrel; rel < rellim; rel++) {
+ switch (ELF_R_TYPE(rel->r_info)) {
+ case R_386_IRELATIVE:
+ where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
+ lock_release(rtld_bind_lock, lockstate);
+ target = ((Elf_Addr (*)(void))(obj->relocbase + *where))();
+ wlock_acquire(rtld_bind_lock, lockstate);
+ *where = target;
+ break;
+ }
+ }
+ obj->irelative = false;
+ return (0);
+}
+
+int
+reloc_gnu_ifunc(Obj_Entry *obj, RtldLockState *lockstate)
+{
+ const Elf_Rel *rellim;
+ const Elf_Rel *rel;
+
+ if (!obj->gnu_ifunc)
+ return (0);
+ rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
+ for (rel = obj->pltrel; rel < rellim; rel++) {
+ Elf_Addr *where, target;
+ const Elf_Sym *def;
+ const Obj_Entry *defobj;
+
+ switch (ELF_R_TYPE(rel->r_info)) {
+ case R_386_JMP_SLOT:
+ where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
+ def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true, 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, rel);
+ break;
+ }
+ }
+
+ obj->gnu_ifunc = false;
+ return (0);
+}
+
void
allocate_initial_tls(Obj_Entry *objs)
{
Modified: stable/9/libexec/rtld-elf/ia64/reloc.c
==============================================================================
--- stable/9/libexec/rtld-elf/ia64/reloc.c Wed Jan 4 16:43:08 2012 (r229502)
+++ stable/9/libexec/rtld-elf/ia64/reloc.c Wed Jan 4 16:43:29 2012 (r229503)
@@ -435,6 +435,22 @@ reloc_plt(Obj_Entry *obj)
return 0;
}
+int
+reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
+{
+
+ /* XXX not implemented */
+ return (0);
+}
+
+int
+reloc_gnu_ifunc(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
+{
+
+ /* XXX not implemented */
+ return (0);
+}
+
/* Relocate the jump slots in an object. */
int
reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate)
Modified: stable/9/libexec/rtld-elf/mips/reloc.c
==============================================================================
--- stable/9/libexec/rtld-elf/mips/reloc.c Wed Jan 4 16:43:08 2012 (r229502)
+++ stable/9/libexec/rtld-elf/mips/reloc.c Wed Jan 4 16:43:29 2012 (r229503)
@@ -498,6 +498,22 @@ reloc_jmpslots(Obj_Entry *obj, RtldLockS
return (0);
}
+int
+reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
+{
+
+ /* XXX not implemented */
+ return (0);
+}
+
+int
+reloc_gnu_ifunc(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
+{
+
+ /* XXX not implemented */
+ return (0);
+}
+
Elf_Addr
reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj,
const Obj_Entry *obj, const Elf_Rel *rel)
Modified: stable/9/libexec/rtld-elf/powerpc/reloc.c
==============================================================================
--- stable/9/libexec/rtld-elf/powerpc/reloc.c Wed Jan 4 16:43:08 2012 (r229502)
+++ stable/9/libexec/rtld-elf/powerpc/reloc.c Wed Jan 4 16:43:29 2012 (r229503)
@@ -370,7 +370,7 @@ reloc_plt_object(Obj_Entry *obj, const E
/*
- * The icache will be sync'd in init_pltgot, which is called
+ * The icache will be sync'd in reloc_plt, which is called
* after all the slots have been updated
*/
@@ -386,6 +386,7 @@ reloc_plt(Obj_Entry *obj)
{
const Elf_Rela *relalim;
const Elf_Rela *rela;
+ int N = obj->pltrelasize / sizeof(Elf_Rela);
if (obj->pltrelasize != 0) {
@@ -400,6 +401,13 @@ reloc_plt(Obj_Entry *obj)
}
}
+ /*
+ * Sync the icache for the byte range represented by the
+ * trampoline routines and call slots.
+ */
+ if (obj->pltgot != NULL)
+ __syncicache(obj->pltgot, JMPTAB_BASE(N)*4);
+
return (0);
}
@@ -508,6 +516,21 @@ reloc_jmpslot(Elf_Addr *wherep, Elf_Addr
return (target);
}
+int
+reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
+{
+
+ /* XXX not implemented */
+ return (0);
+}
+
+int
+reloc_gnu_ifunc(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
+{
+
+ /* XXX not implemented */
+ return (0);
+}
/*
* Setup the plt glue routines.
@@ -584,10 +607,9 @@ init_pltgot(Obj_Entry *obj)
pltresolve[4] |= _ppc_la(obj);
/*
- * Sync the icache for the byte range represented by the
- * trampoline routines and call slots.
+ * The icache will be sync'd in reloc_plt, which is called
+ * after all the slots have been updated
*/
- __syncicache(obj->pltgot, JMPTAB_BASE(N)*4);
}
void
Modified: stable/9/libexec/rtld-elf/powerpc64/reloc.c
==============================================================================
--- stable/9/libexec/rtld-elf/powerpc64/reloc.c Wed Jan 4 16:43:08 2012 (r229502)
+++ stable/9/libexec/rtld-elf/powerpc64/reloc.c Wed Jan 4 16:43:29 2012 (r229503)
@@ -459,6 +459,22 @@ reloc_jmpslot(Elf_Addr *wherep, Elf_Addr
return (target);
}
+int
+reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
+{
+
+ /* XXX not implemented */
+ return (0);
+}
+
+int
+reloc_gnu_ifunc(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
+{
+
+ /* XXX not implemented */
+ return (0);
+}
+
void
init_pltgot(Obj_Entry *obj)
{
Modified: stable/9/libexec/rtld-elf/rtld.c
==============================================================================
--- stable/9/libexec/rtld-elf/rtld.c Wed Jan 4 16:43:08 2012 (r229502)
+++ stable/9/libexec/rtld-elf/rtld.c Wed Jan 4 16:43:29 2012 (r229503)
@@ -116,6 +116,8 @@ static void objlist_push_tail(Objlist *,
static void objlist_remove(Objlist *, Obj_Entry *);
static void *path_enumerate(const char *, path_enum_proc, void *);
static int relocate_objects(Obj_Entry *, bool, Obj_Entry *, RtldLockState *);
+static int resolve_objects_ifunc(Obj_Entry *first, bool bind_now,
+ RtldLockState *lockstate);
static int rtld_dirname(const char *, char *);
static int rtld_dirname_abs(const char *, char *);
static void rtld_exit(void);
@@ -513,6 +515,10 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_
ld_bind_now != NULL && *ld_bind_now != '\0', &obj_rtld, NULL) == -1)
die();
+ if (resolve_objects_ifunc(obj_main,
+ ld_bind_now != NULL && *ld_bind_now != '\0', NULL) == -1)
+ die();
+
dbg("doing copy relocations");
if (do_copy_relocations(obj_main) == -1)
die();
@@ -561,6 +567,17 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_
return (func_ptr_type) obj_main->entry;
}
+void *
+rtld_resolve_ifunc(const Obj_Entry *obj, const Elf_Sym *def)
+{
+ void *ptr;
+ Elf_Addr target;
+
+ ptr = (void *)make_function_pointer(def, obj);
+ target = ((Elf_Addr (*)(void))ptr)();
+ return ((void *)target);
+}
+
Elf_Addr
_rtld_bind(Obj_Entry *obj, Elf_Size reloff)
{
@@ -584,8 +601,10 @@ _rtld_bind(Obj_Entry *obj, Elf_Size relo
&lockstate);
if (def == NULL)
die();
-
- target = (Elf_Addr)(defobj->relocbase + def->st_value);
+ if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC)
+ target = (Elf_Addr)rtld_resolve_ifunc(defobj, def);
+ else
+ target = (Elf_Addr)(defobj->relocbase + def->st_value);
dbg("\"%s\" in \"%s\" ==> %p in \"%s\"",
defobj->strtab + def->st_name, basename(obj->path),
@@ -1944,6 +1963,10 @@ relocate_objects(Obj_Entry *first, bool
}
}
+
+ /* Set the special PLT or GOT entries. */
+ init_pltgot(obj);
+
/* Process the PLT relocations. */
if (reloc_plt(obj) == -1)
return -1;
@@ -1952,7 +1975,6 @@ relocate_objects(Obj_Entry *first, bool
if (reloc_jmpslots(obj, lockstate) == -1)
return -1;
-
/*
* Set up the magic number and version in the Obj_Entry. These
* were checked in the crt1.o from the original ElfKit, so we
@@ -1960,12 +1982,55 @@ relocate_objects(Obj_Entry *first, bool
*/
obj->magic = RTLD_MAGIC;
obj->version = RTLD_VERSION;
-
- /* Set the special PLT or GOT entries. */
- init_pltgot(obj);
}
- return 0;
+ return (0);
+}
+
+/*
+ * The handling of R_MACHINE_IRELATIVE relocations and jumpslots
+ * referencing STT_GNU_IFUNC symbols is postponed till the other
+ * relocations are done. The indirect functions specified as
+ * ifunc are allowed to call other symbols, so we need to have
+ * objects relocated before asking for resolution from indirects.
+ *
+ * The R_MACHINE_IRELATIVE slots are resolved in greedy fashion,
+ * instead of the usual lazy handling of PLT slots. It is
+ * consistent with how GNU does it.
+ */
+static int
+resolve_object_ifunc(Obj_Entry *obj, bool bind_now, RtldLockState *lockstate)
+{
+ if (obj->irelative && reloc_iresolve(obj, lockstate) == -1)
+ return (-1);
+ if ((obj->bind_now || bind_now) && obj->gnu_ifunc &&
+ reloc_gnu_ifunc(obj, lockstate) == -1)
+ return (-1);
+ return (0);
+}
+
+static int
+resolve_objects_ifunc(Obj_Entry *first, bool bind_now, RtldLockState *lockstate)
+{
+ Obj_Entry *obj;
+
+ for (obj = first; obj != NULL; obj = obj->next) {
+ if (resolve_object_ifunc(obj, bind_now, lockstate) == -1)
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+initlist_objects_ifunc(Objlist *list, bool bind_now, RtldLockState *lockstate)
+{
+ Objlist_Entry *elm;
+
+ STAILQ_FOREACH(elm, list, link) {
+ if (resolve_object_ifunc(elm->obj, bind_now, lockstate) == -1)
+ return (-1);
+ }
+ return (0);
}
/*
@@ -2170,6 +2235,16 @@ dlopen(const char *name, int mode)
mode & (RTLD_MODEMASK | RTLD_GLOBAL)));
}
+static void
+dlopen_cleanup(Obj_Entry *obj)
+{
+
+ obj->dl_refcount--;
+ unref_dag(obj);
+ if (obj->refcount == 0)
+ unload_object(obj);
+}
+
static Obj_Entry *
dlopen_object(const char *name, Obj_Entry *refobj, int lo_flags, int mode)
{
@@ -2208,10 +2283,7 @@ dlopen_object(const char *name, Obj_Entr
goto trace;
if (result == -1 || (relocate_objects(obj, (mode & RTLD_MODEMASK)
== RTLD_NOW, &obj_rtld, &lockstate)) == -1) {
- obj->dl_refcount--;
- unref_dag(obj);
- if (obj->refcount == 0)
- unload_object(obj);
+ dlopen_cleanup(obj);
obj = NULL;
} else {
/* Make list of init functions to call. */
@@ -2245,6 +2317,14 @@ dlopen_object(const char *name, Obj_Entr
map_stacks_exec(&lockstate);
+ if (initlist_objects_ifunc(&initlist, (mode & RTLD_MODEMASK) == RTLD_NOW,
+ &lockstate) == -1) {
+ objlist_clear(&initlist);
+ dlopen_cleanup(obj);
+ lock_release(rtld_bind_lock, &lockstate);
+ return (NULL);
+ }
+
/* Call the init functions. */
objlist_call_init(&initlist, &lockstate);
objlist_clear(&initlist);
@@ -2376,9 +2456,11 @@ do_dlsym(void *handle, const char *name,
* the relocated value of the symbol.
*/
if (ELF_ST_TYPE(def->st_info) == STT_FUNC)
- return make_function_pointer(def, defobj);
+ return (make_function_pointer(def, defobj));
+ else if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC)
+ return (rtld_resolve_ifunc(defobj, def));
else
- return defobj->relocbase + def->st_value;
+ return (defobj->relocbase + def->st_value);
}
_rtld_error("Undefined symbol \"%s\"", name);
@@ -2822,6 +2904,8 @@ get_program_var_addr(const char *name, R
if (ELF_ST_TYPE(req.sym_out->st_info) == STT_FUNC)
return ((const void **)make_function_pointer(req.sym_out,
req.defobj_out));
+ else if (ELF_ST_TYPE(req.sym_out->st_info) == STT_GNU_IFUNC)
+ return ((const void **)rtld_resolve_ifunc(req.defobj_out, req.sym_out));
else
return ((const void **)(req.defobj_out->relocbase +
req.sym_out->st_value));
@@ -3088,6 +3172,7 @@ symlook_obj1(SymLook *req, const Obj_Ent
case STT_FUNC:
case STT_NOTYPE:
case STT_OBJECT:
+ case STT_GNU_IFUNC:
if (symp->st_value == 0)
continue;
/* fallthrough */
Modified: stable/9/libexec/rtld-elf/rtld.h
==============================================================================
--- stable/9/libexec/rtld-elf/rtld.h Wed Jan 4 16:43:08 2012 (r229502)
+++ stable/9/libexec/rtld-elf/rtld.h Wed Jan 4 16:43:29 2012 (r229503)
@@ -230,6 +230,8 @@ typedef struct Struct_Obj_Entry {
bool on_fini_list: 1; /* Object is already on fini list. */
bool dag_inited : 1; /* Object has its DAG initialized. */
bool filtees_loaded : 1; /* Filtees loaded */
+ bool irelative : 1; /* Object has R_MACHDEP_IRELATIVE relocs */
+ bool gnu_ifunc : 1; /* Object has references to STT_GNU_IFUNC */
struct link_map linkmap; /* For GDB and dlinfo() */
Objlist dldags; /* Object belongs to these dlopened DAGs (%) */
@@ -317,6 +319,7 @@ void lockdflt_init(void);
void obj_free(Obj_Entry *);
Obj_Entry *obj_new(void);
void _rtld_bind_start(void);
+void *rtld_resolve_ifunc(const Obj_Entry *obj, const Elf_Sym *def);
void symlook_init(SymLook *, const char *);
int symlook_obj(SymLook *, const Obj_Entry *);
void *tls_get_addr_common(Elf_Addr** dtvp, int index, size_t offset);
@@ -334,6 +337,8 @@ int do_copy_relocations(Obj_Entry *);
int reloc_non_plt(Obj_Entry *, Obj_Entry *, struct Struct_RtldLockState *);
int reloc_plt(Obj_Entry *);
int reloc_jmpslots(Obj_Entry *, struct Struct_RtldLockState *);
+int reloc_iresolve(Obj_Entry *, struct Struct_RtldLockState *);
+int reloc_gnu_ifunc(Obj_Entry *, struct Struct_RtldLockState *);
void allocate_initial_tls(Obj_Entry *);
#endif /* } */
Modified: stable/9/libexec/rtld-elf/sparc64/reloc.c
==============================================================================
--- stable/9/libexec/rtld-elf/sparc64/reloc.c Wed Jan 4 16:43:08 2012 (r229502)
+++ stable/9/libexec/rtld-elf/sparc64/reloc.c Wed Jan 4 16:43:29 2012 (r229503)
@@ -550,6 +550,22 @@ reloc_jmpslots(Obj_Entry *obj, RtldLockS
return (0);
}
+int
+reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
+{
+
+ /* XXX not implemented */
+ return (0);
+}
+
+int
+reloc_gnu_ifunc(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
+{
+
+ /* XXX not implemented */
+ return (0);
+}
+
Elf_Addr
reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *obj,
const Obj_Entry *refobj, const Elf_Rel *rel)
More information about the svn-src-stable-9
mailing list