summaryrefslogtreecommitdiff
path: root/ldso/ldso
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 /ldso/ldso
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.
Diffstat (limited to 'ldso/ldso')
-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
6 files changed, 91 insertions, 51 deletions
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