From 4bff590782e7100c86fb3cb5c40e46fb5c813b42 Mon Sep 17 00:00:00 2001 From: jdp Date: Sat, 29 Jan 2000 01:27:04 +0000 Subject: 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. --- libexec/rtld-elf/alpha/reloc.c | 68 +++++++++++++++++++++++++++++------------- libexec/rtld-elf/amd64/reloc.c | 35 +++++++++++++++------- libexec/rtld-elf/i386/reloc.c | 35 +++++++++++++++------- libexec/rtld-elf/rtld.c | 45 +++++++++++++++++++++++----- libexec/rtld-elf/rtld.h | 4 ++- 5 files changed, 137 insertions(+), 50 deletions(-) (limited to 'libexec') diff --git a/libexec/rtld-elf/alpha/reloc.c b/libexec/rtld-elf/alpha/reloc.c index 114f3ae..8763be4 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 217d88e..360733a 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 217d88e..360733a 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 652d0c8..146b9b2 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 3a88547..6d1ebbf 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); -- cgit v1.1