summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2003-08-19 13:11:09 +0000
committerEric Andersen <andersen@codepoet.org>2003-08-19 13:11:09 +0000
commit2711bc5895accc67e27232d9b75fc12c7994837f (patch)
tree945cf31c093b07bbdc09222c405297b7951336d1
parentbca6a155c79147f706242ed7c590a3538e407a40 (diff)
Cool. Found most of the problem. Turns out we were inadvertanly loading some
libraries multiple times, wasting memory and causing different libraries to use different symbol sets, some of which were not properly resolved. Continue scrubbing ld.so and converting it to use proper types.
-rw-r--r--ldso/include/dl-hash.h31
-rw-r--r--ldso/include/ld_hash.h31
-rw-r--r--ldso/ldso/dl-elf.c25
-rw-r--r--ldso/ldso/dl-hash.c11
-rw-r--r--ldso/ldso/hash.c11
-rw-r--r--ldso/ldso/i386/elfinterp.c48
-rw-r--r--ldso/ldso/ldso.c22
-rw-r--r--ldso/ldso/readelflib1.c25
-rw-r--r--ldso/libdl/dlib.c289
-rw-r--r--ldso/libdl/libdl.c289
10 files changed, 501 insertions, 281 deletions
diff --git a/ldso/include/dl-hash.h b/ldso/include/dl-hash.h
index d7ed5ab2c..246ed2608 100644
--- a/ldso/include/dl-hash.h
+++ b/ldso/include/dl-hash.h
@@ -12,13 +12,13 @@ struct dyn_elf{
struct dyn_elf * next;
struct dyn_elf * prev;
};
-
+
struct elf_resolve{
/* These entries must be in this order to be compatible with the interface used
by gdb to obtain the list of symbols. */
- char * loadaddr;
- char * libname;
- unsigned long dynamic_addr;
+ ElfW(Addr) loadaddr; /* Base address shared object is loaded at. */
+ char *libname; /* Absolute file name object was found in. */
+ ElfW(Dyn) *dynamic_addr; /* Dynamic section of the shared object. */
struct elf_resolve * next;
struct elf_resolve * prev;
/* Nothing after this address is used by gdb. */
@@ -53,25 +53,10 @@ struct elf_resolve{
#endif
};
-#if 0
-/*
- * The DT_DEBUG entry in the .dynamic section is given the address of this structure.
- * gdb can pick this up to obtain the correct list of loaded modules.
- */
-
-struct r_debug{
- int r_version;
- struct elf_resolve * link_map;
- unsigned long brk_fun;
- enum {RT_CONSISTENT, RT_ADD, RT_DELETE};
- unsigned long ldbase;
-};
-#endif
-
-#define COPY_RELOCS_DONE 1
-#define RELOCS_DONE 2
-#define JMP_RELOCS_DONE 4
-#define INIT_FUNCS_CALLED 8
+#define COPY_RELOCS_DONE 1
+#define RELOCS_DONE 2
+#define JMP_RELOCS_DONE 4
+#define INIT_FUNCS_CALLED 8
extern struct dyn_elf * _dl_symbol_tables;
extern struct elf_resolve * _dl_loaded_modules;
diff --git a/ldso/include/ld_hash.h b/ldso/include/ld_hash.h
index d7ed5ab2c..246ed2608 100644
--- a/ldso/include/ld_hash.h
+++ b/ldso/include/ld_hash.h
@@ -12,13 +12,13 @@ struct dyn_elf{
struct dyn_elf * next;
struct dyn_elf * prev;
};
-
+
struct elf_resolve{
/* These entries must be in this order to be compatible with the interface used
by gdb to obtain the list of symbols. */
- char * loadaddr;
- char * libname;
- unsigned long dynamic_addr;
+ ElfW(Addr) loadaddr; /* Base address shared object is loaded at. */
+ char *libname; /* Absolute file name object was found in. */
+ ElfW(Dyn) *dynamic_addr; /* Dynamic section of the shared object. */
struct elf_resolve * next;
struct elf_resolve * prev;
/* Nothing after this address is used by gdb. */
@@ -53,25 +53,10 @@ struct elf_resolve{
#endif
};
-#if 0
-/*
- * The DT_DEBUG entry in the .dynamic section is given the address of this structure.
- * gdb can pick this up to obtain the correct list of loaded modules.
- */
-
-struct r_debug{
- int r_version;
- struct elf_resolve * link_map;
- unsigned long brk_fun;
- enum {RT_CONSISTENT, RT_ADD, RT_DELETE};
- unsigned long ldbase;
-};
-#endif
-
-#define COPY_RELOCS_DONE 1
-#define RELOCS_DONE 2
-#define JMP_RELOCS_DONE 4
-#define INIT_FUNCS_CALLED 8
+#define COPY_RELOCS_DONE 1
+#define RELOCS_DONE 2
+#define JMP_RELOCS_DONE 4
+#define INIT_FUNCS_CALLED 8
extern struct dyn_elf * _dl_symbol_tables;
extern struct elf_resolve * _dl_loaded_modules;
diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c
index dd3d9a293..3df8b1461 100644
--- a/ldso/ldso/dl-elf.c
+++ b/ldso/ldso/dl-elf.c
@@ -180,7 +180,7 @@ struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt,
{
char *pnt, *pnt1;
struct elf_resolve *tpnt1;
- char *libname;
+ char *libname, *libname2;
_dl_internal_error_number = 0;
pnt = libname = full_libname;
@@ -190,12 +190,33 @@ struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt,
if (_dl_strlen(full_libname) > 1024)
goto goof;
- /* Skip over any initial initial './' path to get the libname */
+ /* Skip over any initial initial './' and '/' stuff to
+ * get the short form libname with no path garbage */
pnt1 = _dl_strrchr(pnt, '/');
if (pnt1) {
libname = pnt1 + 1;
}
+ /* Critical step! Weed out duplicates early to avoid
+ * function aliasing, which wastes memory, and causes
+ * really bad things to happen with weaks and globals. */
+ for (tpnt1 = _dl_loaded_modules; tpnt1; tpnt1 = tpnt1->next) {
+
+ /* Skip over any initial initial './' and '/' stuff to
+ * get the short form libname with no path garbage */
+ libname2 = tpnt1->libname;
+ pnt1 = _dl_strrchr(libname2, '/');
+ if (pnt1) {
+ libname2 = pnt1 + 1;
+ }
+
+ if (_dl_strcmp(libname2, libname) == 0) {
+ /* Well, that was certainly easy */
+ return tpnt1;
+ }
+ }
+
+
#if defined (__SUPPORT_LD_DEBUG__)
if(_dl_debug) _dl_dprintf(_dl_debug_file, "searching for library: '%s'\n", libname);
#endif
diff --git a/ldso/ldso/dl-hash.c b/ldso/ldso/dl-hash.c
index bd7ac7708..1eb7c5dd9 100644
--- a/ldso/ldso/dl-hash.c
+++ b/ldso/ldso/dl-hash.c
@@ -123,7 +123,7 @@ struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
tpnt->next = NULL;
tpnt->init_flag = 0;
tpnt->libname = _dl_strdup(libname);
- tpnt->dynamic_addr = dynamic_addr;
+ tpnt->dynamic_addr = (ElfW(Dyn) *)dynamic_addr;
tpnt->dynamic_size = dynamic_size;
tpnt->libtype = loaded_file;
@@ -135,7 +135,7 @@ struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
hash_addr += tpnt->nbucket;
tpnt->chains = hash_addr;
}
- tpnt->loadaddr = loadaddr;
+ tpnt->loadaddr = (ElfW(Addr))loadaddr;
for (i = 0; i < 24; i++)
tpnt->dynamic_info[i] = dynamic_info[i];
#ifdef __mips__
@@ -285,15 +285,14 @@ char *_dl_find_hash(const char *name, struct dyn_elf *rpnt1,
ELF32_ST_TYPE(symtab[si].st_info)
== STT_NOTYPE)
{ /* nakao */
- data_result = tpnt->loadaddr +
+ data_result = (char *)tpnt->loadaddr +
symtab[si].st_value; /* nakao */
break; /* nakao */
} else /* nakao */
- return tpnt->loadaddr + symtab[si].st_value;
+ return (char*)tpnt->loadaddr + symtab[si].st_value;
case STB_WEAK:
if (!weak_result)
- weak_result =
- tpnt->loadaddr + symtab[si].st_value;
+ weak_result = (char *)tpnt->loadaddr + symtab[si].st_value;
break;
default: /* Do local symbols need to be examined? */
break;
diff --git a/ldso/ldso/hash.c b/ldso/ldso/hash.c
index bd7ac7708..1eb7c5dd9 100644
--- a/ldso/ldso/hash.c
+++ b/ldso/ldso/hash.c
@@ -123,7 +123,7 @@ struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
tpnt->next = NULL;
tpnt->init_flag = 0;
tpnt->libname = _dl_strdup(libname);
- tpnt->dynamic_addr = dynamic_addr;
+ tpnt->dynamic_addr = (ElfW(Dyn) *)dynamic_addr;
tpnt->dynamic_size = dynamic_size;
tpnt->libtype = loaded_file;
@@ -135,7 +135,7 @@ struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
hash_addr += tpnt->nbucket;
tpnt->chains = hash_addr;
}
- tpnt->loadaddr = loadaddr;
+ tpnt->loadaddr = (ElfW(Addr))loadaddr;
for (i = 0; i < 24; i++)
tpnt->dynamic_info[i] = dynamic_info[i];
#ifdef __mips__
@@ -285,15 +285,14 @@ char *_dl_find_hash(const char *name, struct dyn_elf *rpnt1,
ELF32_ST_TYPE(symtab[si].st_info)
== STT_NOTYPE)
{ /* nakao */
- data_result = tpnt->loadaddr +
+ data_result = (char *)tpnt->loadaddr +
symtab[si].st_value; /* nakao */
break; /* nakao */
} else /* nakao */
- return tpnt->loadaddr + symtab[si].st_value;
+ return (char*)tpnt->loadaddr + symtab[si].st_value;
case STB_WEAK:
if (!weak_result)
- weak_result =
- tpnt->loadaddr + symtab[si].st_value;
+ weak_result = (char *)tpnt->loadaddr + symtab[si].st_value;
break;
default: /* Do local symbols need to be examined? */
break;
diff --git a/ldso/ldso/i386/elfinterp.c b/ldso/ldso/i386/elfinterp.c
index 2e59e461f..7f2b8ff71 100644
--- a/ldso/ldso/i386/elfinterp.c
+++ b/ldso/ldso/i386/elfinterp.c
@@ -87,7 +87,7 @@ static void debug_reloc(Elf32_Sym *symtab,char *strtab, ELF_RELOC *rpnt)
rpnt->r_offset,
rpnt->r_addend);
#else
- _dl_dprintf(_dl_debug_file, "%s\toffset=%x",
+ _dl_dprintf(_dl_debug_file, "%s\toffset=%x\n",
_dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
rpnt->r_offset);
#endif
@@ -157,7 +157,7 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
_dl_dprintf(_dl_debug_file, "\nresolve function: %s",
strtab + symtab[symtab_index].st_name);
if(_dl_debug_detail) _dl_dprintf(_dl_debug_file,
- "\n\tpatch %x ==> %x @ %x\n", *got_addr, new_addr, got_addr);
+ "\n\tpatched %x ==> %x @ %x\n", *got_addr, new_addr, got_addr);
}
}
if (!_dl_debug_nofixups) {
@@ -178,7 +178,6 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
{
unsigned int i;
char *strtab;
- int goof = 0;
Elf32_Sym *symtab;
ELF_RELOC *rpnt;
int symtab_index;
@@ -230,10 +229,10 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
else if (res >0)
{
_dl_dprintf(2, "can't resolve symbol\n");
- goof += res;
+ return res;
}
}
- return goof;
+ return 0;
}
@@ -243,19 +242,23 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
{
int reloc_type;
int symtab_index;
+ char *symname;
unsigned long *reloc_addr;
unsigned long symbol_addr;
- int goof = 0;
+#if defined (__SUPPORT_LD_DEBUG__)
+ unsigned long old_val;
+#endif
reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
reloc_type = ELF32_R_TYPE(rpnt->r_info);
symtab_index = ELF32_R_SYM(rpnt->r_info);
symbol_addr = 0;
+ symname = strtab + symtab[symtab_index].st_name;
if (symtab_index) {
- symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name,
- scope, (reloc_type == R_386_JMP_SLOT ? tpnt : NULL), symbolrel);
+ symbol_addr = (unsigned long) _dl_find_hash(symname, scope,
+ (reloc_type == R_386_JMP_SLOT ? tpnt : NULL), symbolrel);
/*
* We want to allow undefined references to weak symbols - this might
@@ -265,16 +268,15 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
#if defined (__SUPPORT_LD_DEBUG__)
- _dl_dprintf(2, "library '%s': NOT resolving global symbol '%s'\n",
- tpnt->libname, strtab + symtab[symtab_index].st_name);
+ _dl_dprintf(2, "\tglobal symbol '%s' already defined in '%s'\n",
+ symname, tpnt->libname);
#endif
- goof++;
+ return 0;
}
}
#if defined (__SUPPORT_LD_DEBUG__)
- {
- unsigned long old_val = *reloc_addr;
+ old_val = *reloc_addr;
#endif
switch (reloc_type) {
case R_386_NONE:
@@ -299,13 +301,11 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
return -1; /*call _dl_exit(1) */
}
#if defined (__SUPPORT_LD_DEBUG__)
- if(_dl_debug_reloc && _dl_debug_detail)
- _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
- }
-
+ if(_dl_debug_reloc && _dl_debug_detail)
+ _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
#endif
- return goof;
+ return 0;
}
static int
@@ -314,6 +314,9 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
{
int reloc_type;
unsigned long *reloc_addr;
+#if defined (__SUPPORT_LD_DEBUG__)
+ unsigned long old_val;
+#endif
(void)scope;
(void)symtab;
(void)strtab;
@@ -322,8 +325,7 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
reloc_type = ELF32_R_TYPE(rpnt->r_info);
#if defined (__SUPPORT_LD_DEBUG__)
- {
- unsigned long old_val = *reloc_addr;
+ old_val = *reloc_addr;
#endif
switch (reloc_type) {
case R_386_NONE:
@@ -335,10 +337,8 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
return -1; /*call _dl_exit(1) */
}
#if defined (__SUPPORT_LD_DEBUG__)
- if(_dl_debug_reloc && _dl_debug_detail)
- _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
- }
-
+ if(_dl_debug_reloc && _dl_debug_detail)
+ _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
#endif
return 0;
diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c
index 7bfe24947..b3fbab842 100644
--- a/ldso/ldso/ldso.c
+++ b/ldso/ldso/ldso.c
@@ -142,7 +142,6 @@ static char *_dl_malloc_addr, *_dl_mmap_zero;
static char *_dl_trace_loaded_objects = 0;
static int (*_dl_elf_main) (int, char **, char **);
-static int (*_dl_elf_init) (void);
struct r_debug *_dl_debug_addr = NULL;
unsigned long *_dl_brkp;
unsigned long *_dl_envp;
@@ -665,7 +664,7 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a
tpnt->next = 0;
tpnt->libname = 0;
tpnt->libtype = program_interpreter;
- tpnt->loadaddr = (char *) load_addr;
+ tpnt->loadaddr = (ElfW(Addr)) load_addr;
#ifdef ALLOW_ZERO_PLTGOT
if (tpnt->dynamic_info[DT_PLTGOT])
@@ -690,17 +689,17 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a
tpnt->ppnt = myppnt = (ElfW(Phdr) *) (load_addr + epnt->e_phoff);
for (j = 0; j < epnt->e_phnum; j++, myppnt++) {
if (myppnt->p_type == PT_DYNAMIC) {
- tpnt->dynamic_addr = myppnt->p_vaddr + load_addr;
+ tpnt->dynamic_addr = (ElfW(Dyn) *)myppnt->p_vaddr + load_addr;
#if defined(__mips__)
{
int k = 1;
- Elf32_Dyn *dpnt = (Elf32_Dyn *) tpnt->dynamic_addr;
+ ElfW(Dyn) *dpnt = (ElfW(Dyn) *) tpnt->dynamic_addr;
while(dpnt->d_tag) {
dpnt++;
k++;
}
- tpnt->dynamic_size = k * sizeof(Elf32_Dyn);
+ tpnt->dynamic_size = k * sizeof(ElfW(Dyn));
}
#else
tpnt->dynamic_size = myppnt->p_filesz;
@@ -1038,8 +1037,7 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a
for (dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag;
dpnt++) {
if (dpnt->d_tag == DT_NEEDED) {
- lpntstr = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] +
- dpnt->d_un.d_val;
+ lpntstr = (char*) (tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] + dpnt->d_un.d_val);
if (_dl_strcmp(lpntstr, "libc.so.6") == 0) {
char *name, *msg;
name = tcurr->libname;
@@ -1261,15 +1259,17 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a
tpnt->init_flag |= INIT_FUNCS_CALLED;
if (tpnt->dynamic_info[DT_INIT]) {
- _dl_elf_init = (int (*)(void)) (intptr_t) (tpnt->loadaddr + tpnt->dynamic_info[DT_INIT]);
-
+ void (*dl_elf_func) (void);
+ dl_elf_func = (void (*)(void)) (intptr_t) (tpnt->loadaddr + tpnt->dynamic_info[DT_INIT]);
#if defined (__SUPPORT_LD_DEBUG__)
if(_dl_debug) _dl_dprintf(_dl_debug_file,"\ncalling init: %s\n\n", tpnt->libname);
#endif
- (*_dl_elf_init) ();
+ (*dl_elf_func) ();
}
if (_dl_atexit && tpnt->dynamic_info[DT_FINI]) {
- (*_dl_atexit) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
+ void (*dl_elf_func) (void);
+ dl_elf_func = (void (*)(void)) (intptr_t) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
+ (*_dl_atexit) (dl_elf_func);
#if defined (__SUPPORT_LD_DEBUG__)
if(_dl_debug && _dl_on_exit)
{
diff --git a/ldso/ldso/readelflib1.c b/ldso/ldso/readelflib1.c
index dd3d9a293..3df8b1461 100644
--- a/ldso/ldso/readelflib1.c
+++ b/ldso/ldso/readelflib1.c
@@ -180,7 +180,7 @@ struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt,
{
char *pnt, *pnt1;
struct elf_resolve *tpnt1;
- char *libname;
+ char *libname, *libname2;
_dl_internal_error_number = 0;
pnt = libname = full_libname;
@@ -190,12 +190,33 @@ struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt,
if (_dl_strlen(full_libname) > 1024)
goto goof;
- /* Skip over any initial initial './' path to get the libname */
+ /* Skip over any initial initial './' and '/' stuff to
+ * get the short form libname with no path garbage */
pnt1 = _dl_strrchr(pnt, '/');
if (pnt1) {
libname = pnt1 + 1;
}
+ /* Critical step! Weed out duplicates early to avoid
+ * function aliasing, which wastes memory, and causes
+ * really bad things to happen with weaks and globals. */
+ for (tpnt1 = _dl_loaded_modules; tpnt1; tpnt1 = tpnt1->next) {
+
+ /* Skip over any initial initial './' and '/' stuff to
+ * get the short form libname with no path garbage */
+ libname2 = tpnt1->libname;
+ pnt1 = _dl_strrchr(libname2, '/');
+ if (pnt1) {
+ libname2 = pnt1 + 1;
+ }
+
+ if (_dl_strcmp(libname2, libname) == 0) {
+ /* Well, that was certainly easy */
+ return tpnt1;
+ }
+ }
+
+
#if defined (__SUPPORT_LD_DEBUG__)
if(_dl_debug) _dl_dprintf(_dl_debug_file, "searching for library: '%s'\n", libname);
#endif
diff --git a/ldso/libdl/dlib.c b/ldso/libdl/dlib.c
index a15518230..9ca624962 100644
--- a/ldso/libdl/dlib.c
+++ b/ldso/libdl/dlib.c
@@ -13,6 +13,7 @@ int dlclose(void *) __attribute__ ((__weak__, __alias__ ("_dlclose")));
void *dlsym(void *, const char *) __attribute__ ((__weak__, __alias__ ("_dlsym")));
const char *dlerror(void) __attribute__ ((__weak__, __alias__ ("_dlerror")));
int dladdr(void *, Dl_info *) __attribute__ ((__weak__, __alias__ ("_dladdr")));
+void _dlinfo(void);
#ifdef __PIC__
@@ -121,16 +122,14 @@ static void __attribute__ ((destructor)) dl_cleanup(void)
void *_dlopen(const char *libname, int flag)
{
- struct elf_resolve *tpnt, *tfrom;
- struct dyn_elf *rpnt = NULL;
- struct dyn_elf *dyn_chain;
+ struct elf_resolve *tpnt, *tfrom, *tcurr;
+ struct dyn_elf *dyn_chain, *rpnt = NULL;
struct dyn_elf *dpnt;
static int dl_init = 0;
- char *from;
+ ElfW(Addr) from;
+ const char *libname1, *libname2, *ptr;
+ struct elf_resolve *tpnt1;
void (*dl_brk) (void);
-#ifdef __PIC__
- int (*dl_elf_init) (void);
-#endif
/* A bit of sanity checking... */
if (!(flag & (RTLD_LAZY|RTLD_NOW))) {
@@ -138,7 +137,7 @@ void *_dlopen(const char *libname, int flag)
return NULL;
}
- from = __builtin_return_address(0);
+ from = (ElfW(Addr)) __builtin_return_address(0);
/* Have the dynamic linker use the regular malloc function now */
if (!dl_init) {
@@ -150,9 +149,7 @@ void *_dlopen(const char *libname, int flag)
if (!libname)
return _dl_symbol_tables;
-#ifdef USE_CACHE
_dl_map_cache();
-#endif
/*
* Try and locate the module we were called from - we
@@ -166,101 +163,204 @@ void *_dlopen(const char *libname, int flag)
for (dpnt = _dl_symbol_tables; dpnt; dpnt = dpnt->next) {
tpnt = dpnt->dyn;
if (tpnt->loadaddr < from
- && (tfrom == NULL || tfrom->loadaddr < tpnt->loadaddr))
+ && (tfrom == NULL || tfrom->loadaddr < tpnt->loadaddr))
tfrom = tpnt;
}
+ /* Skip over any initial initial './' and '/' stuff to
+ * get the short form libname with no path garbage */
+ libname1 = libname;
+ ptr = _dl_strrchr(libname1, '/');
+ if (ptr) {
+ libname1 = ptr + 1;
+ }
+
+
+ /* Weed out duplicates early to avoid function aliasing */
+ for (tpnt1 = _dl_loaded_modules; tpnt1; tpnt1 = tpnt1->next) {
+ /* Skip over any initial initial './' and '/' stuff to
+ * get the short form libname with no path garbage */
+ libname2 = tpnt1->libname;
+ ptr = _dl_strrchr(libname2, '/');
+ if (ptr) {
+ libname2 = ptr + 1;
+ }
+
+ if (_dl_strcmp(libname1, libname2) == 0) {
+ /* Well, that was certainly easy */
+ return tpnt1;
+ }
+ }
+
+
+
+ /* Try to load the specified library */
+#ifdef __SUPPORT_LD_DEBUG__
+ _dl_dprintf(_dl_debug_file, "Trying to dlopen '%s'\n", (char*)libname);
+#endif
if (!(tpnt = _dl_load_shared_library(0, &rpnt, tfrom, (char*)libname))) {
-#ifdef USE_CACHE
_dl_unmap_cache();
-#endif
return NULL;
}
//tpnt->libtype = loaded_file;
- dyn_chain = rpnt = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
- _dl_memset(rpnt, 0, sizeof(struct dyn_elf));
- rpnt->dyn = tpnt;
- rpnt->flags = flag;
+
+ dyn_chain = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
+ _dl_memset(dyn_chain, 0, sizeof(struct dyn_elf));
+ dyn_chain->dyn = tpnt;
+ dyn_chain->flags = flag;
if (!tpnt->symbol_scope)
tpnt->symbol_scope = dyn_chain;
- rpnt->next_handle = _dl_handles;
- _dl_handles = rpnt;
+ dyn_chain->next_handle = _dl_handles;
+ _dl_handles = rpnt = dyn_chain;
- /*
- * OK, we have the requested file in memory. Now check for
- * any other requested files that may also be required.
- */
- {
- struct elf_resolve *tcurr;
- struct elf_resolve * tpnt1;
- Elf32_Dyn * dpnt;
- char * lpnt;
-
- tcurr = tpnt;
- do{
- for(dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag; dpnt++)
- {
-
- if(dpnt->d_tag == DT_NEEDED)
- {
- lpnt = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] +
- dpnt->d_un.d_val;
- if(!(tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpnt)))
- goto oops;
- rpnt->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
- _dl_memset (rpnt->next, 0, sizeof (struct dyn_elf));
- rpnt = rpnt->next;
- if (!tpnt1->symbol_scope) tpnt1->symbol_scope = dyn_chain;
- rpnt->dyn = tpnt1;
- };
+#ifdef __SUPPORT_LD_DEBUG__
+ _dl_dprintf(_dl_debug_file, "Looking for needed libraries\n");
+#endif
+ for (tcurr = tpnt; tcurr; tcurr = tcurr->next)
+ {
+ Elf32_Dyn *dpnt;
+ char *lpntstr;
+ for (dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag; dpnt++) {
+ if (dpnt->d_tag == DT_NEEDED) {
+ lpntstr = (char*)tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] +
+ dpnt->d_un.d_val;
+
+ /* Skip over any initial initial './' and '/' stuff to
+ * get the short form libname with no path garbage */
+ libname1 = lpntstr;
+ ptr = _dl_strrchr(libname1, '/');
+ if (ptr) {
+ libname1 = ptr + 1;
+ }
+
+ /* Linked with glibc? */
+ if (_dl_strcmp(libname1, "libc.so.6") == 0) {
+ _dl_dprintf(2, "\tERROR: %s is linked with GNU libc!\n",
+ tcurr->libname);
+ goto oops;
+ }
+
+#if 0
+ {
+ struct elf_resolve *tpnt2;
+ /* Weed out duplicates early to avoid function aliasing */
+ for (tpnt2 = _dl_loaded_modules; tpnt2; tpnt2 = tpnt2->next) {
+ /* Skip over any initial initial './' and '/' stuff to
+ * get the short form libname with no path garbage */
+ libname2 = tpnt2->libname;
+ ptr = _dl_strrchr(libname2, '/');
+ if (ptr) {
+ libname2 = ptr + 1;
+ }
+
+ if (_dl_strcmp(libname1, libname2) == 0) {
+ /* Well, that was certainly easy */
+#ifdef __SUPPORT_LD_DEBUG__
+ _dl_dprintf(_dl_debug_file, "\tLibrary '%s' needed by '%s' "
+ "already loaded\n", lpntstr, tcurr->libname);
+#endif
+ continue;
+ }
+ }
+ }
+#endif
+
+#ifdef __SUPPORT_LD_DEBUG__
+ _dl_dprintf(_dl_debug_file, "Trying to load '%s', needed by '%s'\n",
+ lpntstr, tcurr->libname);
+#endif
+
+#if 1
+
+ if (!(tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpntstr))) {
+ goto oops;
+ }
+#else
+ if (!(tpnt1 = _dlopen(lpntstr, flag))) {
+ goto oops;
+ }
+#endif
+
+ rpnt->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
+ _dl_memset (rpnt->next, 0, sizeof (struct dyn_elf));
+ rpnt = rpnt->next;
+ if (!tpnt1->symbol_scope) tpnt1->symbol_scope = rpnt;
+ rpnt->dyn = tpnt1;
+
+ }
}
-
- tcurr = tcurr->next;
- } while(tcurr);
- }
-
+ }
+
/*
* OK, now attach the entire chain at the end
*/
-
rpnt->next = _dl_symbol_tables;
+#ifdef __mips__
/*
- * MIPS is special *sigh*
+ * Relocation of the GOT entries for MIPS have to be done
+ * after all the libraries have been loaded.
*/
-#ifdef __mips__
_dl_perform_mips_global_got_relocations(tpnt);
#endif
- if (_dl_fixup(tpnt, (flag & RTLD_LAZY))) {
- _dl_error_number = LD_NO_SYMBOL;
+#ifdef __SUPPORT_LD_DEBUG__
+ _dl_dprintf(_dl_debug_file, "Beginning dlopen relocation fixups\n");
+#endif
+ /*
+ * OK, now all of the kids are tucked into bed in their proper addresses.
+ * Now we go through and look for REL and RELA records that indicate fixups
+ * to the GOT tables. We need to do this in reverse order so that COPY
+ * directives work correctly */
+ if (_dl_fixup(dyn_chain->dyn, (flag & RTLD_LAZY)))
goto oops;
+
+#ifdef __SUPPORT_LD_DEBUG__
+ _dl_dprintf(_dl_debug_file, "Beginning dlopen copy fixups\n");
+#endif
+ if (_dl_symbol_tables) {
+ if (_dl_copy_fixups(dyn_chain))
+ goto oops;
}
+
+ /* TODO: Should we set the protections of all pages back to R/O now ? */
+
+
+ /* Notify the debugger we have added some objects. */
+ _dl_debug_addr->r_state = RT_ADD;
if (_dl_debug_addr) {
- dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
- if (dl_brk != NULL) {
- _dl_debug_addr->r_state = RT_ADD;
- (*dl_brk) ();
+ dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
+ if (dl_brk != NULL) {
+ _dl_debug_addr->r_state = RT_ADD;
+ (*dl_brk) ();
- _dl_debug_addr->r_state = RT_CONSISTENT;
- (*dl_brk) ();
- }
+ _dl_debug_addr->r_state = RT_CONSISTENT;
+ (*dl_brk) ();
+ }
}
+#if 1
+#ifdef __SUPPORT_LD_DEBUG__
+ _dlinfo();
+#endif
+#endif
+
#ifdef __PIC__
- /* Find the last library */
- for (tpnt = dyn_chain->dyn; tpnt->next!=NULL; tpnt = tpnt->next)
- ;
+ /* Find the last library so we can run things in the right order */
+ for (rpnt = _dl_symbol_tables; rpnt!=NULL&& rpnt->next!=NULL; rpnt=rpnt->next)
+ ;
+
/* Run the ctors and set up the dtors */
- for (; tpnt != dyn_chain->dyn->prev; tpnt=tpnt->prev)
+ for (;rpnt!=NULL; rpnt=rpnt->prev)
{
/* Apparently crt1 for the application is responsible for handling this.
* We only need to run the init/fini for shared libraries
*/
+ tpnt = rpnt->dyn;
if (tpnt->libtype == program_interpreter)
continue;
if (tpnt->libtype == elf_executable)
@@ -270,26 +370,32 @@ void *_dlopen(const char *libname, int flag)
tpnt->init_flag |= INIT_FUNCS_CALLED;
if (tpnt->dynamic_info[DT_INIT]) {
- dl_elf_init = (int (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_INIT]);
- (*dl_elf_init) ();
+ void (*dl_elf_func) (void);
+ dl_elf_func = (void (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_INIT]);
+ if (dl_elf_func && *dl_elf_func != NULL) {
+#ifdef __SUPPORT_LD_DEBUG__
+ _dl_dprintf(2, "running ctors for library %s at '%x'\n", tpnt->libname, dl_elf_func);
+#endif
+ (*dl_elf_func) ();
+ }
}
if (tpnt->dynamic_info[DT_FINI]) {
- atexit((void (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]));
+ void (*dl_elf_func) (void);
+ dl_elf_func = (void (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
+ if (dl_elf_func && *dl_elf_func != NULL) {
+#ifdef __SUPPORT_LD_DEBUG__
+ _dl_dprintf(2, "setting up dtors for library %s at '%x'\n", tpnt->libname, dl_elf_func);
+#endif
+ atexit(dl_elf_func);
+ }
}
-
}
#endif
-
-#ifdef USE_CACHE
- _dl_unmap_cache();
-#endif
return (void *) dyn_chain;
- oops:
+oops:
/* Something went wrong. Clean up and return NULL. */
-#ifdef USE_CACHE
_dl_unmap_cache();
-#endif
do_dlclose(dyn_chain, 0);
return NULL;
}
@@ -298,7 +404,7 @@ void *_dlsym(void *vhandle, const char *name)
{
struct elf_resolve *tpnt, *tfrom;
struct dyn_elf *handle;
- char *from;
+ ElfW(Addr) from;
struct dyn_elf *rpnt;
void *ret;
@@ -325,7 +431,7 @@ void *_dlsym(void *vhandle, const char *name)
* dynamic loader itself, as it doesn't know
* how to properly treat it.
*/
- from = __builtin_return_address(0);
+ from = (ElfW(Addr)) __builtin_return_address(0);
tfrom = NULL;
for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next) {
@@ -442,7 +548,7 @@ static int do_dlclose(void *vhandle, int need_fini)
if (end < ppnt->p_vaddr + ppnt->p_memsz)
end = ppnt->p_vaddr + ppnt->p_memsz;
}
- _dl_munmap(rpnt->dyn->loadaddr, end);
+ _dl_munmap((void*)rpnt->dyn->loadaddr, end);
/* Next, remove rpnt->dyn from the loaded_module list */
if (_dl_loaded_modules == rpnt->dyn) {
_dl_loaded_modules = rpnt->dyn->next;
@@ -527,9 +633,7 @@ int _dladdr(void *__address, Dl_info * __dlip)
struct elf_resolve *pelf;
struct elf_resolve *rpnt;
-#ifdef USE_CACHE
_dl_map_cache();
-#endif
/*
* Try and locate the module address is in
@@ -537,7 +641,7 @@ int _dladdr(void *__address, Dl_info * __dlip)
pelf = NULL;
#if 0
- _dl_dprintf(2, "dladdr( 0x%p, 0x%p )\n", __address, __dlip);
+ _dl_dprintf(2, "dladdr( %x, %x )\n", __address, __dlip);
#endif
for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next) {
@@ -545,10 +649,10 @@ int _dladdr(void *__address, Dl_info * __dlip)
tpnt = rpnt;
#if 0
- _dl_dprintf(2, "Module \"%s\" at 0x%p\n",
+ _dl_dprintf(2, "Module \"%s\" at %x\n",
tpnt->libname, tpnt->loadaddr);
#endif
- if (tpnt->loadaddr < (char *) __address
+ if (tpnt->loadaddr < (ElfW(Addr)) __address
&& (pelf == NULL || pelf->loadaddr < tpnt->loadaddr)) {
pelf = tpnt;
}
@@ -568,24 +672,25 @@ int _dladdr(void *__address, Dl_info * __dlip)
int hn, si;
int sf;
int sn = 0;
- void *sa = 0;
+ ElfW(Addr) sa;
+ sa = 0;
symtab = (Elf32_Sym *) (pelf->dynamic_info[DT_SYMTAB] + pelf->loadaddr);
strtab = (char *) (pelf->dynamic_info[DT_STRTAB] + pelf->loadaddr);
sf = 0;
for (hn = 0; hn < pelf->nbucket; hn++) {
for (si = pelf->elf_buckets[hn]; si; si = pelf->chains[si]) {
- void *symbol_addr;
+ ElfW(Addr) symbol_addr;
symbol_addr = pelf->loadaddr + symtab[si].st_value;
- if (symbol_addr <= __address && (!sf || sa < symbol_addr)) {
+ if (symbol_addr <= (ElfW(Addr))__address && (!sf || sa < symbol_addr)) {
sa = symbol_addr;
sn = si;
sf = 1;
}
#if 0
- _dl_dprintf(2, "Symbol \"%s\" at 0x%p\n",
+ _dl_dprintf(2, "Symbol \"%s\" at %x\n",
strtab + symtab[si].st_name, symbol_addr);
#endif
}
@@ -593,9 +698,9 @@ int _dladdr(void *__address, Dl_info * __dlip)
if (sf) {
__dlip->dli_fname = pelf->libname;
- __dlip->dli_fbase = pelf->loadaddr;
+ __dlip->dli_fbase = (void *)pelf->loadaddr;
__dlip->dli_sname = strtab + symtab[sn].st_name;
- __dlip->dli_saddr = sa;
+ __dlip->dli_saddr = (void *)sa;
}
return 1;
}
diff --git a/ldso/libdl/libdl.c b/ldso/libdl/libdl.c
index a15518230..9ca624962 100644
--- a/ldso/libdl/libdl.c
+++ b/ldso/libdl/libdl.c
@@ -13,6 +13,7 @@ int dlclose(void *) __attribute__ ((__weak__, __alias__ ("_dlclose")));
void *dlsym(void *, const char *) __attribute__ ((__weak__, __alias__ ("_dlsym")));
const char *dlerror(void) __attribute__ ((__weak__, __alias__ ("_dlerror")));
int dladdr(void *, Dl_info *) __attribute__ ((__weak__, __alias__ ("_dladdr")));
+void _dlinfo(void);
#ifdef __PIC__
@@ -121,16 +122,14 @@ static void __attribute__ ((destructor)) dl_cleanup(void)
void *_dlopen(const char *libname, int flag)
{
- struct elf_resolve *tpnt, *tfrom;
- struct dyn_elf *rpnt = NULL;
- struct dyn_elf *dyn_chain;
+ struct elf_resolve *tpnt, *tfrom, *tcurr;
+ struct dyn_elf *dyn_chain, *rpnt = NULL;
struct dyn_elf *dpnt;
static int dl_init = 0;
- char *from;
+ ElfW(Addr) from;
+ const char *libname1, *libname2, *ptr;
+ struct elf_resolve *tpnt1;
void (*dl_brk) (void);
-#ifdef __PIC__
- int (*dl_elf_init) (void);
-#endif
/* A bit of sanity checking... */
if (!(flag & (RTLD_LAZY|RTLD_NOW))) {
@@ -138,7 +137,7 @@ void *_dlopen(const char *libname, int flag)
return NULL;
}
- from = __builtin_return_address(0);
+ from = (ElfW(Addr)) __builtin_return_address(0);
/* Have the dynamic linker use the regular malloc function now */
if (!dl_init) {
@@ -150,9 +149,7 @@ void *_dlopen(const char *libname, int flag)
if (!libname)
return _dl_symbol_tables;
-#ifdef USE_CACHE
_dl_map_cache();
-#endif
/*
* Try and locate the module we were called from - we
@@ -166,101 +163,204 @@ void *_dlopen(const char *libname, int flag)
for (dpnt = _dl_symbol_tables; dpnt; dpnt = dpnt->next) {
tpnt = dpnt->dyn;
if (tpnt->loadaddr < from
- && (tfrom == NULL || tfrom->loadaddr < tpnt->loadaddr))
+ && (tfrom == NULL || tfrom->loadaddr < tpnt->loadaddr))
tfrom = tpnt;
}
+ /* Skip over any initial initial './' and '/' stuff to
+ * get the short form libname with no path garbage */
+ libname1 = libname;
+ ptr = _dl_strrchr(libname1, '/');
+ if (ptr) {
+ libname1 = ptr + 1;
+ }
+
+
+ /* Weed out duplicates early to avoid function aliasing */
+ for (tpnt1 = _dl_loaded_modules; tpnt1; tpnt1 = tpnt1->next) {
+ /* Skip over any initial initial './' and '/' stuff to
+ * get the short form libname with no path garbage */
+ libname2 = tpnt1->libname;
+ ptr = _dl_strrchr(libname2, '/');
+ if (ptr) {
+ libname2 = ptr + 1;
+ }
+
+ if (_dl_strcmp(libname1, libname2) == 0) {
+ /* Well, that was certainly easy */
+ return tpnt1;
+ }
+ }
+
+
+
+ /* Try to load the specified library */
+#ifdef __SUPPORT_LD_DEBUG__
+ _dl_dprintf(_dl_debug_file, "Trying to dlopen '%s'\n", (char*)libname);
+#endif
if (!(tpnt = _dl_load_shared_library(0, &rpnt, tfrom, (char*)libname))) {
-#ifdef USE_CACHE
_dl_unmap_cache();
-#endif
return NULL;
}
//tpnt->libtype = loaded_file;
- dyn_chain = rpnt = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
- _dl_memset(rpnt, 0, sizeof(struct dyn_elf));
- rpnt->dyn = tpnt;
- rpnt->flags = flag;
+
+ dyn_chain = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
+ _dl_memset(dyn_chain, 0, sizeof(struct dyn_elf));
+ dyn_chain->dyn = tpnt;
+ dyn_chain->flags = flag;
if (!tpnt->symbol_scope)
tpnt->symbol_scope = dyn_chain;
- rpnt->next_handle = _dl_handles;
- _dl_handles = rpnt;
+ dyn_chain->next_handle = _dl_handles;
+ _dl_handles = rpnt = dyn_chain;
- /*
- * OK, we have the requested file in memory. Now check for
- * any other requested files that may also be required.
- */
- {
- struct elf_resolve *tcurr;
- struct elf_resolve * tpnt1;
- Elf32_Dyn * dpnt;
- char * lpnt;
-
- tcurr = tpnt;
- do{
- for(dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag; dpnt++)
- {
-
- if(dpnt->d_tag == DT_NEEDED)
- {
- lpnt = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] +
- dpnt->d_un.d_val;
- if(!(tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpnt)))
- goto oops;
- rpnt->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
- _dl_memset (rpnt->next, 0, sizeof (struct dyn_elf));
- rpnt = rpnt->next;
- if (!tpnt1->symbol_scope) tpnt1->symbol_scope = dyn_chain;
- rpnt->dyn = tpnt1;
- };
+#ifdef __SUPPORT_LD_DEBUG__
+ _dl_dprintf(_dl_debug_file, "Looking for needed libraries\n");
+#endif
+ for (tcurr = tpnt; tcurr; tcurr = tcurr->next)
+ {
+ Elf32_Dyn *dpnt;
+ char *lpntstr;
+ for (dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag; dpnt++) {
+ if (dpnt->d_tag == DT_NEEDED) {
+ lpntstr = (char*)tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] +
+ dpnt->d_un.d_val;
+
+ /* Skip over any initial initial './' and '/' stuff to
+ * get the short form libname with no path garbage */
+ libname1 = lpntstr;
+ ptr = _dl_strrchr(libname1, '/');
+ if (ptr) {
+ libname1 = ptr + 1;
+ }
+
+ /* Linked with glibc? */
+ if (_dl_strcmp(libname1, "libc.so.6") == 0) {
+ _dl_dprintf(2, "\tERROR: %s is linked with GNU libc!\n",
+ tcurr->libname);
+ goto oops;
+ }
+
+#if 0
+ {
+ struct elf_resolve *tpnt2;
+ /* Weed out duplicates early to avoid function aliasing */
+ for (tpnt2 = _dl_loaded_modules; tpnt2; tpnt2 = tpnt2->next) {
+ /* Skip over any initial initial './' and '/' stuff to
+ * get the short form libname with no path garbage */
+ libname2 = tpnt2->libname;
+ ptr = _dl_strrchr(libname2, '/');
+ if (ptr) {
+ libname2 = ptr + 1;
+ }
+
+ if (_dl_strcmp(libname1, libname2) == 0) {
+ /* Well, that was certainly easy */
+#ifdef __SUPPORT_LD_DEBUG__
+ _dl_dprintf(_dl_debug_file, "\tLibrary '%s' needed by '%s' "
+ "already loaded\n", lpntstr, tcurr->libname);
+#endif
+ continue;
+ }
+ }
+ }
+#endif
+
+#ifdef __SUPPORT_LD_DEBUG__
+ _dl_dprintf(_dl_debug_file, "Trying to load '%s', needed by '%s'\n",
+ lpntstr, tcurr->libname);
+#endif
+
+#if 1
+
+ if (!(tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpntstr))) {
+ goto oops;
+ }
+#else
+ if (!(tpnt1 = _dlopen(lpntstr, flag))) {
+ goto oops;
+ }
+#endif
+
+ rpnt->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
+ _dl_memset (rpnt->next, 0, sizeof (struct dyn_elf));
+ rpnt = rpnt->next;
+ if (!tpnt1->symbol_scope) tpnt1->symbol_scope = rpnt;
+ rpnt->dyn = tpnt1;
+
+ }
}
-
- tcurr = tcurr->next;
- } while(tcurr);
- }
-
+ }
+
/*
* OK, now attach the entire chain at the end
*/
-
rpnt->next = _dl_symbol_tables;
+#ifdef __mips__
/*
- * MIPS is special *sigh*
+ * Relocation of the GOT entries for MIPS have to be done
+ * after all the libraries have been loaded.
*/
-#ifdef __mips__
_dl_perform_mips_global_got_relocations(tpnt);
#endif
- if (_dl_fixup(tpnt, (flag & RTLD_LAZY))) {
- _dl_error_number = LD_NO_SYMBOL;
+#ifdef __SUPPORT_LD_DEBUG__
+ _dl_dprintf(_dl_debug_file, "Beginning dlopen relocation fixups\n");
+#endif
+ /*
+ * OK, now all of the kids are tucked into bed in their proper addresses.
+ * Now we go through and look for REL and RELA records that indicate fixups
+ * to the GOT tables. We need to do this in reverse order so that COPY
+ * directives work correctly */
+ if (_dl_fixup(dyn_chain->dyn, (flag & RTLD_LAZY)))
goto oops;
+
+#ifdef __SUPPORT_LD_DEBUG__
+ _dl_dprintf(_dl_debug_file, "Beginning dlopen copy fixups\n");
+#endif
+ if (_dl_symbol_tables) {
+ if (_dl_copy_fixups(dyn_chain))
+ goto oops;
}
+
+ /* TODO: Should we set the protections of all pages back to R/O now ? */
+
+
+ /* Notify the debugger we have added some objects. */
+ _dl_debug_addr->r_state = RT_ADD;
if (_dl_debug_addr) {
- dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
- if (dl_brk != NULL) {
- _dl_debug_addr->r_state = RT_ADD;
- (*dl_brk) ();
+ dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
+ if (dl_brk != NULL) {
+ _dl_debug_addr->r_state = RT_ADD;
+ (*dl_brk) ();
- _dl_debug_addr->r_state = RT_CONSISTENT;
- (*dl_brk) ();
- }
+ _dl_debug_addr->r_state = RT_CONSISTENT;
+ (*dl_brk) ();
+ }
}
+#if 1
+#ifdef __SUPPORT_LD_DEBUG__
+ _dlinfo();
+#endif
+#endif
+
#ifdef __PIC__
- /* Find the last library */
- for (tpnt = dyn_chain->dyn; tpnt->next!=NULL; tpnt = tpnt->next)
- ;
+ /* Find the last library so we can run things in the right order */
+ for (rpnt = _dl_symbol_tables; rpnt!=NULL&& rpnt->next!=NULL; rpnt=rpnt->next)
+ ;
+
/* Run the ctors and set up the dtors */
- for (; tpnt != dyn_chain->dyn->prev; tpnt=tpnt->prev)
+ for (;rpnt!=NULL; rpnt=rpnt->prev)
{
/* Apparently crt1 for the application is responsible for handling this.
* We only need to run the init/fini for shared libraries
*/
+ tpnt = rpnt->dyn;
if (tpnt->libtype == program_interpreter)
continue;
if (tpnt->libtype == elf_executable)
@@ -270,26 +370,32 @@ void *_dlopen(const char *libname, int flag)
tpnt->init_flag |= INIT_FUNCS_CALLED;
if (tpnt->dynamic_info[DT_INIT]) {
- dl_elf_init = (int (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_INIT]);
- (*dl_elf_init) ();
+ void (*dl_elf_func) (void);
+ dl_elf_func = (void (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_INIT]);
+ if (dl_elf_func && *dl_elf_func != NULL) {
+#ifdef __SUPPORT_LD_DEBUG__
+ _dl_dprintf(2, "running ctors for library %s at '%x'\n", tpnt->libname, dl_elf_func);
+#endif
+ (*dl_elf_func) ();
+ }
}
if (tpnt->dynamic_info[DT_FINI]) {
- atexit((void (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]));
+ void (*dl_elf_func) (void);
+ dl_elf_func = (void (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
+ if (dl_elf_func && *dl_elf_func != NULL) {
+#ifdef __SUPPORT_LD_DEBUG__
+ _dl_dprintf(2, "setting up dtors for library %s at '%x'\n", tpnt->libname, dl_elf_func);
+#endif
+ atexit(dl_elf_func);
+ }
}
-
}
#endif
-
-#ifdef USE_CACHE
- _dl_unmap_cache();
-#endif
return (void *) dyn_chain;
- oops:
+oops:
/* Something went wrong. Clean up and return NULL. */
-#ifdef USE_CACHE
_dl_unmap_cache();
-#endif
do_dlclose(dyn_chain, 0);
return NULL;
}
@@ -298,7 +404,7 @@ void *_dlsym(void *vhandle, const char *name)
{
struct elf_resolve *tpnt, *tfrom;
struct dyn_elf *handle;
- char *from;
+ ElfW(Addr) from;
struct dyn_elf *rpnt;
void *ret;
@@ -325,7 +431,7 @@ void *_dlsym(void *vhandle, const char *name)
* dynamic loader itself, as it doesn't know
* how to properly treat it.
*/
- from = __builtin_return_address(0);
+ from = (ElfW(Addr)) __builtin_return_address(0);
tfrom = NULL;
for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next) {
@@ -442,7 +548,7 @@ static int do_dlclose(void *vhandle, int need_fini)
if (end < ppnt->p_vaddr + ppnt->p_memsz)
end = ppnt->p_vaddr + ppnt->p_memsz;
}
- _dl_munmap(rpnt->dyn->loadaddr, end);
+ _dl_munmap((void*)rpnt->dyn->loadaddr, end);
/* Next, remove rpnt->dyn from the loaded_module list */
if (_dl_loaded_modules == rpnt->dyn) {
_dl_loaded_modules = rpnt->dyn->next;
@@ -527,9 +633,7 @@ int _dladdr(void *__address, Dl_info * __dlip)
struct elf_resolve *pelf;
struct elf_resolve *rpnt;
-#ifdef USE_CACHE
_dl_map_cache();
-#endif
/*
* Try and locate the module address is in
@@ -537,7 +641,7 @@ int _dladdr(void *__address, Dl_info * __dlip)
pelf = NULL;
#if 0
- _dl_dprintf(2, "dladdr( 0x%p, 0x%p )\n", __address, __dlip);
+ _dl_dprintf(2, "dladdr( %x, %x )\n", __address, __dlip);
#endif
for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next) {
@@ -545,10 +649,10 @@ int _dladdr(void *__address, Dl_info * __dlip)
tpnt = rpnt;
#if 0
- _dl_dprintf(2, "Module \"%s\" at 0x%p\n",
+ _dl_dprintf(2, "Module \"%s\" at %x\n",
tpnt->libname, tpnt->loadaddr);
#endif
- if (tpnt->loadaddr < (char *) __address
+ if (tpnt->loadaddr < (ElfW(Addr)) __address
&& (pelf == NULL || pelf->loadaddr < tpnt->loadaddr)) {
pelf = tpnt;
}
@@ -568,24 +672,25 @@ int _dladdr(void *__address, Dl_info * __dlip)
int hn, si;
int sf;
int sn = 0;
- void *sa = 0;
+ ElfW(Addr) sa;
+ sa = 0;
symtab = (Elf32_Sym *) (pelf->dynamic_info[DT_SYMTAB] + pelf->loadaddr);
strtab = (char *) (pelf->dynamic_info[DT_STRTAB] + pelf->loadaddr);
sf = 0;
for (hn = 0; hn < pelf->nbucket; hn++) {
for (si = pelf->elf_buckets[hn]; si; si = pelf->chains[si]) {
- void *symbol_addr;
+ ElfW(Addr) symbol_addr;
symbol_addr = pelf->loadaddr + symtab[si].st_value;
- if (symbol_addr <= __address && (!sf || sa < symbol_addr)) {
+ if (symbol_addr <= (ElfW(Addr))__address && (!sf || sa < symbol_addr)) {
sa = symbol_addr;
sn = si;
sf = 1;
}
#if 0
- _dl_dprintf(2, "Symbol \"%s\" at 0x%p\n",
+ _dl_dprintf(2, "Symbol \"%s\" at %x\n",
strtab + symtab[si].st_name, symbol_addr);
#endif
}
@@ -593,9 +698,9 @@ int _dladdr(void *__address, Dl_info * __dlip)
if (sf) {
__dlip->dli_fname = pelf->libname;
- __dlip->dli_fbase = pelf->loadaddr;
+ __dlip->dli_fbase = (void *)pelf->loadaddr;
__dlip->dli_sname = strtab + symtab[sn].st_name;
- __dlip->dli_saddr = sa;
+ __dlip->dli_saddr = (void *)sa;
}
return 1;
}