aboutsummaryrefslogtreecommitdiff
path: root/libexec/rtld-elf
diff options
context:
space:
mode:
authorJohn Polstra <jdp@FreeBSD.org>2000-01-29 01:27:04 +0000
committerJohn Polstra <jdp@FreeBSD.org>2000-01-29 01:27:04 +0000
commit7dbe16fbeef1df733f74de7203647a4eba928609 (patch)
treee68cb1ab7205d71d070d2a9fc194f8a433a8b083 /libexec/rtld-elf
parent2a0bb85541802e36517ff6b94b5020ef14b496a4 (diff)
downloadsrc-7dbe16fbeef1df733f74de7203647a4eba928609.tar.gz
src-7dbe16fbeef1df733f74de7203647a4eba928609.zip
When a threads package registers locking methods with dllockinit(),
figure out which shared object(s) contain the the locking methods and fully bind those objects as if they had been loaded with LD_BIND_NOW=1. The goal is to keep the locking methods from requiring any lazy binding. Otherwise infinite recursion occurs in _rtld_bind. This fixes the infinite recursion problem in the linuxthreads port.
Notes
Notes: svn path=/head/; revision=56780
Diffstat (limited to 'libexec/rtld-elf')
-rw-r--r--libexec/rtld-elf/alpha/reloc.c68
-rw-r--r--libexec/rtld-elf/amd64/reloc.c35
-rw-r--r--libexec/rtld-elf/i386/reloc.c35
-rw-r--r--libexec/rtld-elf/rtld.c45
-rw-r--r--libexec/rtld-elf/rtld.h4
5 files changed, 137 insertions, 50 deletions
diff --git a/libexec/rtld-elf/alpha/reloc.c b/libexec/rtld-elf/alpha/reloc.c
index 114f3ae438ed..8763be46952b 100644
--- a/libexec/rtld-elf/alpha/reloc.c
+++ b/libexec/rtld-elf/alpha/reloc.c
@@ -159,7 +159,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
/* Process the PLT relocations. */
int
-reloc_plt(Obj_Entry *obj, bool bind_now)
+reloc_plt(Obj_Entry *obj)
{
/* All PLT relocations are the same kind: either Elf_Rel or Elf_Rela. */
if (obj->pltrelsize != 0) {
@@ -175,17 +175,6 @@ reloc_plt(Obj_Entry *obj, bool bind_now)
/* Relocate the GOT slot pointing into the PLT. */
where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
*where += (Elf_Addr)obj->relocbase;
-
- if (bind_now) { /* Fully resolve the procedure address. */
- const Elf_Sym *def;
- const Obj_Entry *defobj;
-
- def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true);
- if (def == NULL)
- return -1;
- reloc_jmpslot(where,
- (Elf_Addr)(defobj->relocbase + def->st_value));
- }
}
} else {
const Elf_Rela *relalim;
@@ -200,19 +189,56 @@ reloc_plt(Obj_Entry *obj, bool bind_now)
/* Relocate the GOT slot pointing into the PLT. */
where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
*where += (Elf_Addr)obj->relocbase;
+ }
+ }
+ return 0;
+}
- if (bind_now) { /* Fully resolve the procedure address. */
- const Elf_Sym *def;
- const Obj_Entry *defobj;
+/* Relocate the jump slots in an object. */
+int
+reloc_jmpslots(Obj_Entry *obj)
+{
+ if (obj->jmpslots_done)
+ return 0;
+ /* All PLT relocations are the same kind: either Elf_Rel or Elf_Rela. */
+ if (obj->pltrelsize != 0) {
+ const Elf_Rel *rellim;
+ const Elf_Rel *rel;
- def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, true);
- if (def == NULL)
- return -1;
- reloc_jmpslot(where,
- (Elf_Addr)(defobj->relocbase + def->st_value));
- }
+ rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
+ for (rel = obj->pltrel; rel < rellim; rel++) {
+ Elf_Addr *where;
+ const Elf_Sym *def;
+ const Obj_Entry *defobj;
+
+ assert(ELF_R_TYPE(rel->r_info) == R_ALPHA_JMP_SLOT);
+ where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
+ def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true);
+ if (def == NULL)
+ return -1;
+ reloc_jmpslot(where,
+ (Elf_Addr)(defobj->relocbase + def->st_value));
+ }
+ } else {
+ const Elf_Rela *relalim;
+ const Elf_Rela *rela;
+
+ relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize);
+ for (rela = obj->pltrela; rela < relalim; rela++) {
+ Elf_Addr *where;
+ const Elf_Sym *def;
+ const Obj_Entry *defobj;
+
+ assert(ELF_R_TYPE(rela->r_info) == R_ALPHA_JMP_SLOT);
+ where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
+ def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, true);
+ if (def == NULL)
+ return -1;
+ reloc_jmpslot(where,
+ (Elf_Addr)(defobj->relocbase + def->st_value));
}
}
+ obj->jmpslots_done = true;
return 0;
}
diff --git a/libexec/rtld-elf/amd64/reloc.c b/libexec/rtld-elf/amd64/reloc.c
index 217d88e707de..360733a71109 100644
--- a/libexec/rtld-elf/amd64/reloc.c
+++ b/libexec/rtld-elf/amd64/reloc.c
@@ -203,7 +203,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
/* Process the PLT relocations. */
int
-reloc_plt(Obj_Entry *obj, bool bind_now)
+reloc_plt(Obj_Entry *obj)
{
const Elf_Rel *rellim;
const Elf_Rel *rel;
@@ -217,17 +217,32 @@ reloc_plt(Obj_Entry *obj, bool bind_now)
/* Relocate the GOT slot pointing into the PLT. */
where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
*where += (Elf_Addr)obj->relocbase;
+ }
+ return 0;
+}
- if (bind_now) { /* Fully resolve the procedure address. */
- const Elf_Sym *def;
- const Obj_Entry *defobj;
+/* Relocate the jump slots in an object. */
+int
+reloc_jmpslots(Obj_Entry *obj)
+{
+ const Elf_Rel *rellim;
+ const Elf_Rel *rel;
- def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true);
- if (def == NULL)
- return -1;
- reloc_jmpslot(where,
- (Elf_Addr)(defobj->relocbase + def->st_value));
- }
+ if (obj->jmpslots_done)
+ return 0;
+ rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
+ for (rel = obj->pltrel; rel < rellim; rel++) {
+ Elf_Addr *where;
+ 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);
+ if (def == NULL)
+ return -1;
+ reloc_jmpslot(where, (Elf_Addr)(defobj->relocbase + def->st_value));
}
+ obj->jmpslots_done = true;
return 0;
}
diff --git a/libexec/rtld-elf/i386/reloc.c b/libexec/rtld-elf/i386/reloc.c
index 217d88e707de..360733a71109 100644
--- a/libexec/rtld-elf/i386/reloc.c
+++ b/libexec/rtld-elf/i386/reloc.c
@@ -203,7 +203,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
/* Process the PLT relocations. */
int
-reloc_plt(Obj_Entry *obj, bool bind_now)
+reloc_plt(Obj_Entry *obj)
{
const Elf_Rel *rellim;
const Elf_Rel *rel;
@@ -217,17 +217,32 @@ reloc_plt(Obj_Entry *obj, bool bind_now)
/* Relocate the GOT slot pointing into the PLT. */
where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
*where += (Elf_Addr)obj->relocbase;
+ }
+ return 0;
+}
- if (bind_now) { /* Fully resolve the procedure address. */
- const Elf_Sym *def;
- const Obj_Entry *defobj;
+/* Relocate the jump slots in an object. */
+int
+reloc_jmpslots(Obj_Entry *obj)
+{
+ const Elf_Rel *rellim;
+ const Elf_Rel *rel;
- def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true);
- if (def == NULL)
- return -1;
- reloc_jmpslot(where,
- (Elf_Addr)(defobj->relocbase + def->st_value));
- }
+ if (obj->jmpslots_done)
+ return 0;
+ rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
+ for (rel = obj->pltrel; rel < rellim; rel++) {
+ Elf_Addr *where;
+ 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);
+ if (def == NULL)
+ return -1;
+ reloc_jmpslot(where, (Elf_Addr)(defobj->relocbase + def->st_value));
}
+ obj->jmpslots_done = true;
return 0;
}
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index 652d0c8d7e6f..146b9b2ba696 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -98,6 +98,7 @@ static Obj_Entry *obj_from_addr(const void *);
static void objlist_add(Objlist *, Obj_Entry *);
static Objlist_Entry *objlist_find(Objlist *, const Obj_Entry *);
static void objlist_remove(Objlist *, Obj_Entry *);
+static void prebind(void *);
static int relocate_objects(Obj_Entry *, bool);
static void rtld_exit(void);
static char *search_library_path(const char *, const char *);
@@ -1232,9 +1233,14 @@ relocate_objects(Obj_Entry *first, bool bind_now)
}
/* Process the PLT relocations. */
- if (reloc_plt(obj, bind_now))
+ if (reloc_plt(obj) == -1)
+ return -1;
+ /* Relocate the jump slots if we are doing immediate binding. */
+ if (bind_now)
+ if (reloc_jmpslots(obj) == -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
@@ -1361,8 +1367,11 @@ dllockinit(void *context,
void (*lock_destroy)(void *lock),
void (*context_destroy)(void *context))
{
+ bool is_dflt = false;
+
/* NULL arguments mean reset to the built-in locks. */
if (lock_create == NULL) {
+ is_dflt = true;
context = NULL;
lock_create = lockdflt_create;
rlock_acquire = wlock_acquire = lockdflt_acquire;
@@ -1383,15 +1392,18 @@ dllockinit(void *context,
lockinfo.context_destroy(lockinfo.context);
/*
- * Allocate the locks we will need and call all the new locking
- * methods, to accomplish any needed lazy binding for the methods
- * themselves.
+ * Make sure the shared objects containing the locking methods are
+ * fully bound, to avoid infinite recursion when they are called
+ * from the lazy binding code.
*/
+ if (!is_dflt) {
+ prebind((void *)rlock_acquire);
+ prebind((void *)wlock_acquire);
+ prebind((void *)lock_release);
+ }
+
+ /* Allocate our lock. */
lockinfo.thelock = lock_create(lockinfo.context);
- rlock_acquire(lockinfo.thelock);
- lock_release(lockinfo.thelock);
- wlock_acquire(lockinfo.thelock);
- lock_release(lockinfo.thelock);
/* Record the new method information. */
lockinfo.context = context;
@@ -1402,6 +1414,23 @@ dllockinit(void *context,
lockinfo.context_destroy = context_destroy;
}
+static void
+prebind(void *addr)
+{
+ Obj_Entry *obj;
+
+ if ((obj = obj_from_addr(addr)) == NULL) {
+ _rtld_error("Cannot determine shared object of locking method at %p",
+ addr);
+ die();
+ }
+ if (!obj->rtld && !obj->jmpslots_done) {
+ dbg("Pre-binding %s for locking", obj->path);
+ if (reloc_jmpslots(obj) == -1)
+ die();
+ }
+}
+
void *
dlopen(const char *name, int mode)
{
diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h
index 3a88547d0298..6d1ebbf37b05 100644
--- a/libexec/rtld-elf/rtld.h
+++ b/libexec/rtld-elf/rtld.h
@@ -142,6 +142,7 @@ typedef struct Struct_Obj_Entry {
bool textrel; /* True if there are relocations to text seg */
bool symbolic; /* True if generated with "-Bsymbolic" */
bool traced; /* Already printed in ldd trace output */
+ bool jmpslots_done; /* Already have relocated the jump slots */
struct link_map linkmap; /* for GDB */
Objlist dldags; /* Object belongs to these dlopened DAGs (%) */
@@ -176,7 +177,8 @@ void lockdflt_release(void *);
void obj_free(Obj_Entry *);
Obj_Entry *obj_new(void);
int reloc_non_plt(Obj_Entry *, Obj_Entry *);
-int reloc_plt(Obj_Entry *, bool);
+int reloc_plt(Obj_Entry *);
+int reloc_jmpslots(Obj_Entry *);
void _rtld_bind_start(void);
const Elf_Sym *symlook_obj(const char *, unsigned long,
const Obj_Entry *, bool);