summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libexec/rtld-elf/alpha/reloc.c3
-rw-r--r--libexec/rtld-elf/debug.h4
-rw-r--r--libexec/rtld-elf/map_object.c63
-rw-r--r--libexec/rtld-elf/rtld.c340
-rw-r--r--libexec/rtld-elf/rtld.h27
5 files changed, 328 insertions, 109 deletions
diff --git a/libexec/rtld-elf/alpha/reloc.c b/libexec/rtld-elf/alpha/reloc.c
index 03d8c171183d..1b55d06e767c 100644
--- a/libexec/rtld-elf/alpha/reloc.c
+++ b/libexec/rtld-elf/alpha/reloc.c
@@ -60,8 +60,7 @@ extern Elf_Dyn _DYNAMIC;
/* Relocate a non-PLT object with addend. */
static int
-reloc_non_plt_obj(Obj_Entry *obj_rtld, const Obj_Entry *obj,
- const Elf_Rela *rela)
+reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela)
{
Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rela->r_offset);
diff --git a/libexec/rtld-elf/debug.h b/libexec/rtld-elf/debug.h
index 8d57ec7930ab..b3563386eaff 100644
--- a/libexec/rtld-elf/debug.h
+++ b/libexec/rtld-elf/debug.h
@@ -36,7 +36,9 @@
#error "This file must be compiled with GCC"
#endif
-extern void debug_printf(const char *, ...);
+#include <sys/cdefs.h>
+
+extern void debug_printf(const char *, ...) __printflike(1, 2);
extern int debug;
#ifdef DEBUG
diff --git a/libexec/rtld-elf/map_object.c b/libexec/rtld-elf/map_object.c
index 0d4114fc6c25..d7b6978ae9ee 100644
--- a/libexec/rtld-elf/map_object.c
+++ b/libexec/rtld-elf/map_object.c
@@ -27,9 +27,11 @@
#include <sys/param.h>
#include <sys/mman.h>
+#include <sys/stat.h>
#include <errno.h>
#include <stddef.h>
+#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -46,7 +48,7 @@ static int protflags(int); /* Elf flags -> mmap protection */
* for the shared object. Returns NULL on failure.
*/
Obj_Entry *
-map_object(int fd, const char *path)
+map_object(int fd, const char *path, const struct stat *sb)
{
Obj_Entry *obj;
union {
@@ -60,6 +62,7 @@ map_object(int fd, const char *path)
int nsegs;
Elf_Phdr *phdyn;
Elf_Phdr *phphdr;
+ Elf_Phdr *phinterp;
caddr_t mapbase;
size_t mapsize;
Elf_Off base_offset;
@@ -134,11 +137,14 @@ map_object(int fd, const char *path)
phdr = (Elf_Phdr *) (u.buf + u.hdr.e_phoff);
phlimit = phdr + u.hdr.e_phnum;
nsegs = 0;
- phdyn = NULL;
- phphdr = NULL;
+ phdyn = phphdr = phinterp = NULL;
while (phdr < phlimit) {
switch (phdr->p_type) {
+ case PT_INTERP:
+ phinterp = phdr;
+ break;
+
case PT_LOAD:
if (nsegs >= 2) {
_rtld_error("%s: too many PT_LOAD segments", path);
@@ -226,23 +232,62 @@ map_object(int fd, const char *path)
}
}
- obj = CNEW(Obj_Entry);
+ obj = obj_new();
+ if (sb != NULL) {
+ obj->dev = sb->st_dev;
+ obj->ino = sb->st_ino;
+ }
obj->mapbase = mapbase;
obj->mapsize = mapsize;
obj->textsize = round_page(segs[0]->p_vaddr + segs[0]->p_memsz) -
base_vaddr;
obj->vaddrbase = base_vaddr;
obj->relocbase = mapbase - base_vaddr;
- obj->dynamic = (const Elf_Dyn *)
- (mapbase + (phdyn->p_vaddr - base_vaddr));
+ obj->dynamic = (const Elf_Dyn *) (obj->relocbase + phdyn->p_vaddr);
if (u.hdr.e_entry != 0)
- obj->entry = (caddr_t) (mapbase + (u.hdr.e_entry - base_vaddr));
+ obj->entry = (caddr_t) (obj->relocbase + u.hdr.e_entry);
if (phphdr != NULL) {
- obj->phdr = (const Elf_Phdr *)
- (mapbase + (phphdr->p_vaddr - base_vaddr));
+ obj->phdr = (const Elf_Phdr *) (obj->relocbase + phphdr->p_vaddr);
obj->phsize = phphdr->p_memsz;
}
+ if (phinterp != NULL)
+ obj->interp = (const char *) (obj->relocbase + phinterp->p_vaddr);
+
+ return obj;
+}
+void
+obj_free(Obj_Entry *obj)
+{
+ Objlist_Entry *elm;
+
+ free(obj->path);
+ while (obj->needed != NULL) {
+ Needed_Entry *needed = obj->needed;
+ obj->needed = needed->next;
+ free(needed);
+ }
+ while (!STAILQ_EMPTY(&obj->dldags)) {
+ elm = STAILQ_FIRST(&obj->dldags);
+ STAILQ_REMOVE_HEAD(&obj->dldags, link);
+ free(elm);
+ }
+ while (!STAILQ_EMPTY(&obj->dagmembers)) {
+ elm = STAILQ_FIRST(&obj->dagmembers);
+ STAILQ_REMOVE_HEAD(&obj->dagmembers, link);
+ free(elm);
+ }
+ free(obj);
+}
+
+Obj_Entry *
+obj_new(void)
+{
+ Obj_Entry *obj;
+
+ obj = CNEW(Obj_Entry);
+ STAILQ_INIT(&obj->dldags);
+ STAILQ_INIT(&obj->dagmembers);
return obj;
}
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index a4a71bc537ef..8ba21b4f26c7 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -37,6 +37,7 @@
#include <sys/param.h>
#include <sys/mman.h>
+#include <sys/stat.h>
#include <dlfcn.h>
#include <err.h>
@@ -61,6 +62,7 @@
#define trace() msg("trace: " __XSTRING(__LINE__) "\n");
#define END_SYM "_end"
+#define PATH_RTLD "/usr/libexec/ld-elf.so.1"
/* Types. */
typedef void (*func_ptr_type)();
@@ -77,6 +79,8 @@ static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *);
static Obj_Entry *dlcheck(void *);
static char *find_library(const char *, const Obj_Entry *);
static const char *gethints(void);
+static void init_dag(Obj_Entry *);
+static void init_dag1(Obj_Entry *root, Obj_Entry *obj);
static void init_rtld(caddr_t);
static bool is_exported(const Elf_Sym *);
static void linkmap_add(Obj_Entry *);
@@ -85,13 +89,18 @@ static int load_needed_objects(Obj_Entry *);
static int load_preload_objects(void);
static Obj_Entry *load_object(char *);
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 int relocate_objects(Obj_Entry *, bool);
static void rtld_exit(void);
static char *search_library_path(const char *, const char *);
static void set_program_var(const char *, const void *);
+static const Elf_Sym *symlook_list(const char *, unsigned long,
+ Objlist *, const Obj_Entry **, bool in_plt);
static void trace_loaded_objects(Obj_Entry *obj);
static void unload_object(Obj_Entry *, bool do_fini_funcs);
-static void unref_object_dag(Obj_Entry *);
+static void unref_dag(Obj_Entry *);
void r_debug_state(void);
void xprintf(const char *, ...);
@@ -108,12 +117,16 @@ static char *ld_library_path; /* Environment variable for search path */
static char *ld_preload; /* Environment variable for libraries to
load first */
static char *ld_tracing; /* Called from ldd to print libs */
-static Obj_Entry **main_tail; /* Value of obj_tail after loading main and
- its needed shared libraries */
static Obj_Entry *obj_list; /* Head of linked list of shared objects */
static Obj_Entry **obj_tail; /* Link field of last object in list */
static Obj_Entry *obj_main; /* The main program shared object */
static Obj_Entry obj_rtld; /* The dynamic linker shared object */
+static unsigned long curmark; /* Current mark value */
+
+static Objlist list_global = /* Objects dlopened with RTLD_GLOBAL */
+ STAILQ_HEAD_INITIALIZER(list_global);
+static Objlist list_main = /* Objects loaded at program startup */
+ STAILQ_HEAD_INITIALIZER(list_main);
static Elf_Sym sym_zero; /* For resolving undefined weak refs. */
@@ -171,6 +184,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
Elf_Auxinfo *aux;
Elf_Auxinfo *auxp;
const char *argv0;
+ Obj_Entry *obj;
/*
* On entry, the dynamic linker itself has not been relocated yet.
@@ -228,7 +242,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
if (aux_info[AT_EXECFD] != NULL) { /* Load the main program. */
int fd = aux_info[AT_EXECFD]->a_un.a_val;
dbg("loading main program");
- obj_main = map_object(fd, argv0);
+ obj_main = map_object(fd, argv0, NULL);
close(fd);
if (obj_main == NULL)
die();
@@ -252,6 +266,19 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
obj_main->path = xstrdup(argv0);
obj_main->mainprog = true;
+
+ /*
+ * Get the actual dynamic linker pathname from the executable if
+ * possible. (It should always be possible.) That ensures that
+ * gdb will find the right dynamic linker even if a non-standard
+ * one is being used.
+ */
+ if (obj_main->interp != NULL &&
+ strcmp(obj_main->interp, obj_rtld.path) != 0) {
+ free(obj_rtld.path);
+ obj_rtld.path = xstrdup(obj_main->interp);
+ }
+
digest_dynamic(obj_main);
linkmap_add(obj_main);
@@ -273,7 +300,9 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
dbg("loading needed objects");
if (load_needed_objects(obj_main) == -1)
die();
- main_tail = obj_tail;
+
+ for (obj = obj_list; obj != NULL; obj = obj->next)
+ objlist_add(&list_main, obj);
if (ld_tracing) { /* We're done */
trace_loaded_objects(obj_main);
@@ -307,7 +336,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
}
Elf_Addr
-_rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
+_rtld_bind(Obj_Entry *obj, Elf_Word reloff)
{
const Elf_Rel *rel;
const Elf_Sym *def;
@@ -548,11 +577,12 @@ digest_dynamic(Obj_Entry *obj)
static Obj_Entry *
digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry, const char *path)
{
- Obj_Entry *obj = CNEW(Obj_Entry);
+ Obj_Entry *obj;
const Elf_Phdr *phlimit = phdr + phnum;
const Elf_Phdr *ph;
int nsegs = 0;
+ obj = obj_new();
for (ph = phdr; ph < phlimit; ph++) {
switch (ph->p_type) {
@@ -565,6 +595,10 @@ digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry, const char *path)
obj->phsize = ph->p_memsz;
break;
+ case PT_INTERP:
+ obj->interp = (const char *) ph->p_vaddr;
+ break;
+
case PT_LOAD:
if (nsegs >= 2) {
_rtld_error("%s: too many PT_LOAD segments", path);
@@ -681,95 +715,94 @@ find_library(const char *name, const Obj_Entry *refobj)
* defining object via the reference parameter DEFOBJ_OUT.
*/
const Elf_Sym *
-find_symdef(unsigned long symnum, const Obj_Entry *refobj,
+find_symdef(unsigned long symnum, Obj_Entry *refobj,
const Obj_Entry **defobj_out, bool in_plt)
{
const Elf_Sym *ref;
- const Elf_Sym *strongdef;
- const Elf_Sym *weakdef;
+ const Elf_Sym *def;
+ const Elf_Sym *symp;
const Obj_Entry *obj;
- const Obj_Entry *strongobj;
- const Obj_Entry *weakobj;
+ const Obj_Entry *defobj;
+ const Objlist_Entry *elm;
const char *name;
unsigned long hash;
ref = refobj->symtab + symnum;
name = refobj->strtab + ref->st_name;
hash = elf_hash(name);
+ def = NULL;
+ defobj = NULL;
+ curmark++;
if (refobj->symbolic) { /* Look first in the referencing object */
- const Elf_Sym *def = symlook_obj(name, hash, refobj, in_plt);
- if (def != NULL) {
- *defobj_out = refobj;
- return def;
+ symp = symlook_obj(name, hash, refobj, in_plt);
+ refobj->mark = curmark;
+ if (symp != NULL) {
+ def = symp;
+ defobj = refobj;
}
}
- /*
- * Look in all loaded objects. Skip the referencing object, if
- * we have already searched it. We keep track of the first weak
- * definition and the first strong definition we encounter. If
- * we find a strong definition we stop searching, because there
- * won't be anything better than that.
- */
- strongdef = weakdef = NULL;
- strongobj = weakobj = NULL;
- for (obj = obj_list; obj != NULL; obj = obj->next) {
- if (obj != refobj || !refobj->symbolic) {
- const Elf_Sym *def = symlook_obj(name, hash, obj, in_plt);
- if (def != NULL) {
- if (ELF_ST_BIND(def->st_info) == STB_WEAK) {
- if (weakdef == NULL) {
- weakdef = def;
- weakobj = obj;
- }
- } else {
- strongdef = def;
- strongobj = obj;
- break; /* We are done. */
- }
- }
+ /* Search all objects loaded at program start up. */
+ if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
+ symp = symlook_list(name, hash, &list_main, &obj, in_plt);
+ if (symp != NULL &&
+ (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
+ def = symp;
+ defobj = obj;
}
}
- /*
- * If we still don't have a strong definition, search the dynamic
- * linker itself, and possibly resolve the symbol from there.
- * This is how the application links to dynamic linker services
- * such as dlopen. Only the values listed in the "exports" array
- * can be resolved from the dynamic linker.
- */
- if (strongdef == NULL) {
- const Elf_Sym *def = symlook_obj(name, hash, &obj_rtld, in_plt);
- if (def != NULL && is_exported(def)) {
- if (ELF_ST_BIND(def->st_info) == STB_WEAK) {
- if (weakdef == NULL) {
- weakdef = def;
- weakobj = &obj_rtld;
- }
- } else {
- strongdef = def;
- strongobj = &obj_rtld;
- }
+ /* Search all dlopened DAGs containing the referencing object. */
+ STAILQ_FOREACH(elm, &refobj->dldags, link) {
+ if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK)
+ break;
+ symp = symlook_list(name, hash, &elm->obj->dagmembers, &obj, in_plt);
+ if (symp != NULL &&
+ (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
+ def = symp;
+ defobj = obj;
}
}
- if (strongdef != NULL) {
- *defobj_out = strongobj;
- return strongdef;
+ /* Search all RTLD_GLOBAL objects. */
+ if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
+ symp = symlook_list(name, hash, &list_global, &obj, in_plt);
+ if (symp != NULL &&
+ (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
+ def = symp;
+ defobj = obj;
+ }
}
- if (weakdef != NULL) {
- *defobj_out = weakobj;
- return weakdef;
+
+ /*
+ * Search the dynamic linker itself, and possibly resolve the
+ * symbol from there. This is how the application links to
+ * dynamic linker services such as dlopen. Only the values listed
+ * in the "exports" array can be resolved from the dynamic linker.
+ */
+ if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
+ symp = symlook_obj(name, hash, &obj_rtld, in_plt);
+ if (symp != NULL && is_exported(symp)) {
+ def = symp;
+ defobj = &obj_rtld;
+ }
}
- if (ELF_ST_BIND(ref->st_info) == STB_WEAK) {
- *defobj_out = obj_main;
- return &sym_zero;
+ /*
+ * If we found no definition and the reference is weak, treat the
+ * symbol as having the value zero.
+ */
+ if (def == NULL && ELF_ST_BIND(ref->st_info) == STB_WEAK) {
+ def = &sym_zero;
+ defobj = obj_main;
}
- _rtld_error("%s: Undefined symbol \"%s\"", refobj->path, name);
- return NULL;
+ if (def != NULL)
+ *defobj_out = defobj;
+ else
+ _rtld_error("%s: Undefined symbol \"%s\"", refobj->path, name);
+ return def;
}
/*
@@ -811,6 +844,28 @@ gethints(void)
return hints[0] != '\0' ? hints : NULL;
}
+static void
+init_dag(Obj_Entry *root)
+{
+ curmark++;
+ init_dag1(root, root);
+}
+
+static void
+init_dag1(Obj_Entry *root, Obj_Entry *obj)
+{
+ const Needed_Entry *needed;
+
+ if (obj->mark == curmark)
+ return;
+ obj->mark = curmark;
+ objlist_add(&obj->dldags, root);
+ objlist_add(&root->dagmembers, obj);
+ for (needed = obj->needed; needed != NULL; needed = needed->next)
+ if (needed->obj != NULL)
+ init_dag1(root, needed->obj);
+}
+
/*
* Initialize the dynamic linker. The argument is the address at which
* the dynamic linker has been mapped into memory. The primary task of
@@ -826,7 +881,7 @@ init_rtld(caddr_t mapbase)
* aren't yet initialized sufficiently to do that. Below we will
* replace the static version with a dynamically-allocated copy.
*/
- obj_rtld.path = "/usr/libexec/ld-elf.so.1";
+ obj_rtld.path = PATH_RTLD;
obj_rtld.rtld = true;
obj_rtld.mapbase = mapbase;
#ifdef PIC
@@ -943,20 +998,42 @@ static Obj_Entry *
load_object(char *path)
{
Obj_Entry *obj;
+ int fd = -1;
+ struct stat sb;
for (obj = obj_list->next; obj != NULL; obj = obj->next)
if (strcmp(obj->path, path) == 0)
break;
- if (obj == NULL) { /* First use of this object, so we must map it in */
- int fd;
-
+ /*
+ * If we didn't find a match by pathname, open the file and check
+ * again by device and inode. This avoids false mismatches caused
+ * by multiple links or ".." in pathnames.
+ *
+ * To avoid a race, we open the file and use fstat() rather than
+ * using stat().
+ */
+ if (obj == NULL) {
if ((fd = open(path, O_RDONLY)) == -1) {
_rtld_error("Cannot open \"%s\"", path);
return NULL;
}
+ if (fstat(fd, &sb) == -1) {
+ _rtld_error("Cannot fstat \"%s\"", path);
+ close(fd);
+ return NULL;
+ }
+ for (obj = obj_list->next; obj != NULL; obj = obj->next) {
+ if (obj->ino == sb.st_ino && obj->dev == sb.st_dev) {
+ close(fd);
+ break;
+ }
+ }
+ }
+
+ if (obj == NULL) { /* First use of this object, so we must map it in */
dbg("loading \"%s\"", path);
- obj = map_object(fd, path);
+ obj = map_object(fd, path, &sb);
close(fd);
if (obj == NULL) {
free(path);
@@ -1001,6 +1078,38 @@ obj_from_addr(const void *addr)
return NULL;
}
+static void
+objlist_add(Objlist *list, Obj_Entry *obj)
+{
+ Objlist_Entry *elm;
+
+ elm = NEW(Objlist_Entry);
+ elm->obj = obj;
+ STAILQ_INSERT_TAIL(list, elm, link);
+}
+
+static Objlist_Entry *
+objlist_find(Objlist *list, const Obj_Entry *obj)
+{
+ Objlist_Entry *elm;
+
+ STAILQ_FOREACH(elm, list, link)
+ if (elm->obj == obj)
+ return elm;
+ return NULL;
+}
+
+static void
+objlist_remove(Objlist *list, Obj_Entry *obj)
+{
+ Objlist_Entry *elm;
+
+ if ((elm = objlist_find(list, obj)) != NULL) {
+ STAILQ_REMOVE(list, elm, Struct_Objlist_Entry, link);
+ free(elm);
+ }
+}
+
/*
* Relocate newly-loaded shared objects. The argument is a pointer to
* the Obj_Entry for the first such object. All objects from the first
@@ -1154,11 +1263,14 @@ dlopen(const char *name, int mode)
if (obj) {
obj->dl_refcount++;
+ if (mode & RTLD_GLOBAL && objlist_find(&list_global, obj) == NULL)
+ objlist_add(&list_global, obj);
+ mode &= RTLD_MODEMASK;
if (*old_obj_tail != NULL) { /* We loaded something new. */
assert(*old_obj_tail == obj);
if (load_needed_objects(obj) == -1 ||
- relocate_objects(obj, mode == RTLD_NOW) == -1) {
+ (init_dag(obj), relocate_objects(obj, mode == RTLD_NOW)) == -1) {
unload_object(obj, false);
obj->dl_refcount--;
obj = NULL;
@@ -1178,9 +1290,11 @@ dlsym(void *handle, const char *name)
const Obj_Entry *obj;
unsigned long hash;
const Elf_Sym *def;
+ const Obj_Entry *defobj;
hash = elf_hash(name);
def = NULL;
+ defobj = NULL;
if (handle == NULL || handle == RTLD_NEXT) {
void *retaddr;
@@ -1190,12 +1304,16 @@ dlsym(void *handle, const char *name)
_rtld_error("Cannot determine caller's shared object");
return NULL;
}
- if (handle == NULL) /* Just the caller's shared object. */
+ if (handle == NULL) { /* Just the caller's shared object. */
def = symlook_obj(name, hash, obj, true);
- else { /* All the shared objects after the caller's */
- while ((obj = obj->next) != NULL)
- if ((def = symlook_obj(name, hash, obj, true)) != NULL)
+ defobj = obj;
+ } else { /* All the shared objects after the caller's */
+ while ((obj = obj->next) != NULL) {
+ if ((def = symlook_obj(name, hash, obj, true)) != NULL) {
+ defobj = obj;
break;
+ }
+ }
}
} else {
if ((obj = dlcheck(handle)) == NULL)
@@ -1203,20 +1321,20 @@ dlsym(void *handle, const char *name)
if (obj->mainprog) {
/* Search main program and all libraries loaded by it. */
- for ( ; obj != *main_tail; obj = obj->next)
- if ((def = symlook_obj(name, hash, obj, true)) != NULL)
- break;
+ curmark++;
+ def = symlook_list(name, hash, &list_main, &defobj, true);
} else {
/*
* XXX - This isn't correct. The search should include the whole
* DAG rooted at the given object.
*/
def = symlook_obj(name, hash, obj, true);
+ defobj = obj;
}
}
if (def != NULL)
- return obj->relocbase + def->st_value;
+ return defobj->relocbase + def->st_value;
_rtld_error("Undefined symbol \"%s\"", name);
return NULL;
@@ -1359,6 +1477,35 @@ set_program_var(const char *name, const void *value)
}
}
+static const Elf_Sym *
+symlook_list(const char *name, unsigned long hash, Objlist *objlist,
+ const Obj_Entry **defobj_out, bool in_plt)
+{
+ const Elf_Sym *symp;
+ const Elf_Sym *def;
+ const Obj_Entry *defobj;
+ const Objlist_Entry *elm;
+
+ def = NULL;
+ defobj = NULL;
+ STAILQ_FOREACH(elm, objlist, link) {
+ if (elm->obj->mark == curmark)
+ continue;
+ elm->obj->mark = curmark;
+ if ((symp = symlook_obj(name, hash, elm->obj, in_plt)) != NULL) {
+ if (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK) {
+ def = symp;
+ defobj = elm->obj;
+ if (ELF_ST_BIND(def->st_info) != STB_WEAK)
+ break;
+ }
+ }
+ }
+ if (def != NULL)
+ *defobj_out = defobj;
+ return def;
+}
+
/*
* Search the symbol table of a single shared object for a symbol of
* the given name. Returns a pointer to the symbol, or NULL if no
@@ -1484,13 +1631,17 @@ trace_loaded_objects(Obj_Entry *obj)
}
}
+/*
+ * Note, this is called only for objects loaded by dlopen().
+ */
static void
unload_object(Obj_Entry *root, bool do_fini_funcs)
{
- unref_object_dag(root);
+ unref_dag(root);
if (root->refcount == 0) { /* We are finished with some objects. */
Obj_Entry *obj;
Obj_Entry **linkp;
+ Objlist_Entry *elm;
/* Finalize objects that are about to be unmapped. */
if (do_fini_funcs)
@@ -1498,21 +1649,22 @@ unload_object(Obj_Entry *root, bool do_fini_funcs)
if (obj->refcount == 0 && obj->fini != NULL)
(*obj->fini)();
+ /* Remove the DAG from all objects' DAG lists. */
+ STAILQ_FOREACH(elm, &root->dagmembers , link)
+ objlist_remove(&elm->obj->dldags, root);
+
+ /* Remove the DAG from the RTLD_GLOBAL list. */
+ objlist_remove(&list_global, root);
+
/* Unmap all objects that are no longer referenced. */
linkp = &obj_list->next;
while ((obj = *linkp) != NULL) {
if (obj->refcount == 0) {
dbg("unloading \"%s\"", obj->path);
munmap(obj->mapbase, obj->mapsize);
- free(obj->path);
- while (obj->needed != NULL) {
- Needed_Entry *needed = obj->needed;
- obj->needed = needed->next;
- free(needed);
- }
linkmap_delete(obj);
*linkp = obj->next;
- free(obj);
+ obj_free(obj);
} else
linkp = &obj->next;
}
@@ -1521,7 +1673,7 @@ unload_object(Obj_Entry *root, bool do_fini_funcs)
}
static void
-unref_object_dag(Obj_Entry *root)
+unref_dag(Obj_Entry *root)
{
const Needed_Entry *needed;
@@ -1530,7 +1682,7 @@ unref_object_dag(Obj_Entry *root)
if (root->refcount == 0)
for (needed = root->needed; needed != NULL; needed = needed->next)
if (needed->obj != NULL)
- unref_object_dag(needed->obj);
+ unref_dag(needed->obj);
}
/*
diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h
index 2fe8b1507d49..c63e7d08836b 100644
--- a/libexec/rtld-elf/rtld.h
+++ b/libexec/rtld-elf/rtld.h
@@ -29,6 +29,7 @@
#define RTLD_H 1
#include <sys/types.h>
+#include <sys/queue.h>
#include <link.h>
#include <elf.h>
@@ -48,8 +49,16 @@ typedef unsigned char bool;
#define false 0
#define true 1
+struct stat;
struct Struct_Obj_Entry;
+typedef struct Struct_Objlist_Entry {
+ STAILQ_ENTRY(Struct_Objlist_Entry) link;
+ struct Struct_Obj_Entry *obj;
+} Objlist_Entry;
+
+typedef STAILQ_HEAD(Struct_Objlist, Struct_Objlist_Entry) Objlist;
+
typedef struct Struct_Needed_Entry {
struct Struct_Needed_Entry *next;
struct Struct_Obj_Entry *obj;
@@ -61,6 +70,10 @@ typedef struct Struct_Needed_Entry {
*
* Items marked with "(%)" are dynamically allocated, and must be freed
* when the structure is destroyed.
+ *
+ * CAUTION: It appears that the JDK port peeks into these structures.
+ * It looks at "next" and "mapbase" at least. Don't add new members
+ * near the front, until this can be straightened out.
*/
typedef struct Struct_Obj_Entry {
/*
@@ -85,6 +98,7 @@ typedef struct Struct_Obj_Entry {
caddr_t entry; /* Entry point */
const Elf_Phdr *phdr; /* Program header if it is mapped, else NULL */
size_t phsize; /* Size of program header in bytes */
+ const char *interp; /* Pathname of the interpreter, if any */
/* Items from the dynamic section. */
Elf_Addr *pltgot; /* PLT or GOT, depending on architecture */
@@ -118,13 +132,18 @@ typedef struct Struct_Obj_Entry {
bool traced; /* Already printed in ldd trace output */
struct link_map linkmap; /* for GDB */
+ Objlist dldags; /* Object belongs to these dlopened DAGs (%) */
+ Objlist dagmembers; /* DAG has these members (%) */
+ dev_t dev; /* Object's filesystem's device */
+ ino_t ino; /* Object's inode number */
+ unsigned long mark; /* Set to "curmark" to avoid repeat visits */
} Obj_Entry;
#define RTLD_MAGIC 0xd550b87a
#define RTLD_VERSION 1
extern void _rtld_error(const char *, ...) __printflike(1, 2);
-extern Obj_Entry *map_object(int, const char *);
+extern Obj_Entry *map_object(int, const char *, const struct stat *);
extern void *xcalloc(size_t);
extern void *xmalloc(size_t);
extern char *xstrdup(const char *);
@@ -135,9 +154,11 @@ extern Elf_Addr _GLOBAL_OFFSET_TABLE_[];
*/
int do_copy_relocations(Obj_Entry *);
unsigned long elf_hash(const char *);
-const Elf_Sym *find_symdef(unsigned long, const Obj_Entry *,
- const Obj_Entry **, bool);
+const Elf_Sym *find_symdef(unsigned long, Obj_Entry *, const Obj_Entry **,
+ bool);
void init_pltgot(Obj_Entry *);
+void obj_free(Obj_Entry *);
+Obj_Entry *obj_new(void);
int reloc_non_plt(Obj_Entry *, Obj_Entry *);
int reloc_plt(Obj_Entry *, bool);
void _rtld_bind_start(void);