summaryrefslogtreecommitdiff
path: root/ldso
diff options
context:
space:
mode:
Diffstat (limited to 'ldso')
-rw-r--r--ldso/include/dl-elf.h13
-rw-r--r--ldso/include/dl-hash.h3
-rw-r--r--ldso/ldso/arm/dl-sysdep.h8
-rw-r--r--ldso/ldso/arm/elfinterp.c15
-rw-r--r--ldso/ldso/cris/dl-sysdep.h16
-rw-r--r--ldso/ldso/cris/elfinterp.c16
-rw-r--r--ldso/ldso/dl-elf.c3
-rw-r--r--ldso/ldso/dl-hash.c49
-rw-r--r--ldso/ldso/dl-startup.c5
-rw-r--r--ldso/ldso/i386/dl-sysdep.h9
-rw-r--r--ldso/ldso/i386/elfinterp.c16
-rw-r--r--ldso/ldso/ldso.c8
-rw-r--r--ldso/ldso/m68k/dl-sysdep.h8
-rw-r--r--ldso/ldso/m68k/elfinterp.c6
-rw-r--r--ldso/ldso/mips/dl-sysdep.h2
-rw-r--r--ldso/ldso/mips/elfinterp.c15
-rw-r--r--ldso/ldso/powerpc/dl-sysdep.h13
-rw-r--r--ldso/ldso/powerpc/elfinterp.c32
-rw-r--r--ldso/ldso/sh/dl-sysdep.h9
-rw-r--r--ldso/ldso/sh/elfinterp.c11
-rw-r--r--ldso/ldso/sh64/dl-sysdep.h8
-rw-r--r--ldso/ldso/sh64/elfinterp.c12
-rw-r--r--ldso/ldso/sparc/dl-sysdep.h8
-rw-r--r--ldso/ldso/sparc/elfinterp.c7
-rw-r--r--ldso/libdl/libdl.c8
25 files changed, 177 insertions, 123 deletions
diff --git a/ldso/include/dl-elf.h b/ldso/include/dl-elf.h
index 4cab5505f..b0a475319 100644
--- a/ldso/include/dl-elf.h
+++ b/ldso/include/dl-elf.h
@@ -92,6 +92,19 @@ extern int _dl_fixup(struct dyn_elf *rpnt, int flag);
# define UNSUPPORTED_RELOC_STR "RELA"
#endif
+/* Reloc type classes as returned by elf_machine_type_class().
+ ELF_RTYPE_CLASS_PLT means this reloc should not be satisfied by
+ some PLT symbol, ELF_RTYPE_CLASS_COPY means this reloc should not be
+ satisfied by any symbol in the executable. Some architectures do
+ not support copy relocations. In this case we define the macro to
+ zero so that the code for handling them gets automatically optimized
+ out. */
+#define ELF_RTYPE_CLASS_PLT 1
+#ifndef DL_NO_COPY_RELOCS
+# define ELF_RTYPE_CLASS_COPY 2
+#else
+# define ELF_RTYPE_CLASS_COPY 0
+#endif
/* Convert between the Linux flags for page protections and the
diff --git a/ldso/include/dl-hash.h b/ldso/include/dl-hash.h
index 2d41e009a..767c2ac46 100644
--- a/ldso/include/dl-hash.h
+++ b/ldso/include/dl-hash.h
@@ -67,9 +67,8 @@ extern struct elf_resolve * _dl_add_elf_hash_table(const char * libname,
char * loadaddr, unsigned long * dynamic_info,
unsigned long dynamic_addr, unsigned long dynamic_size);
-enum caller_type{symbolrel=0,copyrel=1,resolver=2};
extern char * _dl_find_hash(const char * name, struct dyn_elf * rpnt1,
- struct elf_resolve * f_tpnt, enum caller_type);
+ int type_class);
extern int _dl_linux_dynamic_link(void);
diff --git a/ldso/ldso/arm/dl-sysdep.h b/ldso/ldso/arm/dl-sysdep.h
index 04e504eda..96aa62678 100644
--- a/ldso/ldso/arm/dl-sysdep.h
+++ b/ldso/ldso/arm/dl-sysdep.h
@@ -122,3 +122,11 @@ static inline unsigned long arm_modulus(unsigned long m, unsigned long p) {
#define PAGE_ALIGN 0xfffff000
#define ADDR_ALIGN 0xfff
#define OFFS_ALIGN 0x7ffff000
+
+/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
+ PLT entries should not be allowed to define the value.
+ ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
+ of the main executable's symbols, as for a COPY reloc. */
+#define elf_machine_type_class(type) \
+ ((((type) == R_ARM_JUMP_SLOT) * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_ARM_COPY) * ELF_RTYPE_CLASS_COPY))
diff --git a/ldso/ldso/arm/elfinterp.c b/ldso/ldso/arm/elfinterp.c
index 4af05354d..5ab1f148d 100644
--- a/ldso/ldso/arm/elfinterp.c
+++ b/ldso/ldso/arm/elfinterp.c
@@ -118,6 +118,7 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
int reloc_type;
ELF_RELOC *this_reloc;
char *strtab;
+ char *symname;
Elf32_Sym *symtab;
ELF_RELOC *rel_addr;
int symtab_index;
@@ -133,6 +134,7 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
+ symname = strtab + symtab[symtab_index].st_name;
if (reloc_type != R_ARM_JUMP_SLOT) {
@@ -147,11 +149,11 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
got_addr = (char **) instr_addr;
/* Get the address of the GOT entry */
- new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name,
- tpnt->symbol_scope, tpnt, resolver);
+ new_addr = _dl_find_hash(symname,
+ tpnt->symbol_scope, ELF_RTYPE_CLASS_PLT);
if (!new_addr) {
_dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
- _dl_progname, strtab + symtab[symtab_index].st_name);
+ _dl_progname, symname);
_dl_exit(1);
};
#if defined (__SUPPORT_LD_DEBUG__)
@@ -159,8 +161,7 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
{
if (_dl_debug_bindings)
{
- _dl_dprintf(_dl_debug_file, "\nresolve function: %s",
- strtab + symtab[symtab_index].st_name);
+ _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
if(_dl_debug_detail) _dl_dprintf(_dl_debug_file,
"\tpatch %x ==> %x @ %x", *got_addr, new_addr, got_addr);
}
@@ -283,7 +284,7 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
if (symtab_index) {
symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name,
- scope, (reloc_type == R_ARM_JUMP_SLOT ? tpnt : NULL), symbolrel);
+ scope, elf_machine_type_class(reloc_type));
/*
* We want to allow undefined references to weak symbols - this might
@@ -424,7 +425,7 @@ _dl_do_copy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
symbol_addr = (unsigned long) _dl_find_hash(strtab +
symtab[symtab_index].st_name, scope,
- NULL, copyrel);
+ ELF_RTYPE_CLASS_COPY);
if (!symbol_addr) goof++;
}
if (!goof) {
diff --git a/ldso/ldso/cris/dl-sysdep.h b/ldso/ldso/cris/dl-sysdep.h
index 7066863f6..baad524ee 100644
--- a/ldso/ldso/cris/dl-sysdep.h
+++ b/ldso/ldso/cris/dl-sysdep.h
@@ -110,3 +110,19 @@ cris_mod(unsigned long m, unsigned long p)
#define PAGE_ALIGN 0xffffe000
#define ADDR_ALIGN 0x1fff
#define OFFS_ALIGN 0xffffe000
+
+/* The union of reloc-type-classes where the reloc TYPE is a member.
+
+ TYPE is in the class ELF_RTYPE_CLASS_PLT if it can describe a
+ relocation for a PLT entry, that is, for which a PLT entry should not
+ be allowed to define the value. The GNU linker for CRIS can merge a
+ .got.plt entry (R_CRIS_JUMP_SLOT) with a .got entry (R_CRIS_GLOB_DAT),
+ so we need to match both these reloc types.
+
+ TYPE is in the class ELF_RTYPE_CLASS_NOCOPY if it should not be allowed
+ to resolve to one of the main executable's symbols, as for a COPY
+ reloc. */
+#define elf_machine_type_class(type) \
+ ((((((type) == R_CRIS_JUMP_SLOT)) \
+ || ((type) == R_CRIS_GLOB_DAT)) * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_CRIS_COPY) * ELF_RTYPE_CLASS_COPY))
diff --git a/ldso/ldso/cris/elfinterp.c b/ldso/ldso/cris/elfinterp.c
index 71e1ff7d3..3e1b554e5 100644
--- a/ldso/ldso/cris/elfinterp.c
+++ b/ldso/ldso/cris/elfinterp.c
@@ -142,16 +142,10 @@ _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
got_addr = (char **) instr_addr;
/* Fetch the address of the GOT entry. */
- new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, resolver);
-
+ new_addr = _dl_find_hash(symname, tpnt->symbol_scope, ELF_RTYPE_CLASS_PLT);
if (!new_addr) {
- new_addr = _dl_find_hash(symname, NULL, NULL, resolver);
-
- if (new_addr)
- return (unsigned long) new_addr;
-
- _dl_dprintf(2, "%s: Can't resolv symbol '%s'\n", _dl_progname, symname);
- _dl_exit(1);
+ _dl_dprintf(2, "%s: Can't resolv symbol '%s'\n", _dl_progname, symname);
+ _dl_exit(1);
}
#if defined (__SUPPORT_LD_DEBUG__)
@@ -261,7 +255,7 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, ELF_RELOC *rpnt,
}
else {
symbol_addr = (unsigned long) _dl_find_hash(symname, scope,
- (reloc_type == R_CRIS_JUMP_SLOT ? tpnt : NULL), symbolrel);
+ elf_machine_type_class(reloc_type));
}
if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
@@ -366,7 +360,7 @@ _dl_do_copy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, ELF_RELOC *rp
goof = 0;
if (symtab_index) {
- symbol_addr = (unsigned long) _dl_find_hash(symname, scope, NULL, copyrel);
+ symbol_addr = (unsigned long) _dl_find_hash(symname, scope, ELF_RTYPE_CLASS_COPY);
if (!symbol_addr)
goof++;
diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c
index 5a1c89230..e14a23ddc 100644
--- a/ldso/ldso/dl-elf.c
+++ b/ldso/ldso/dl-elf.c
@@ -255,12 +255,13 @@ struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt,
if (pnt1) {
libname = pnt1 + 1;
}
-
+#if 0
/* Critical step! Weed out duplicates early to avoid
* function aliasing, which wastes memory, and causes
* really bad things to happen with weaks and globals. */
if ((tpnt1=_dl_check_if_named_library_is_loaded(libname, trace_loaded_objects))!=NULL)
return tpnt1;
+#endif
#if defined (__SUPPORT_LD_DEBUG__)
if(_dl_debug) _dl_dprintf(_dl_debug_file, "\tfind library='%s'; searching\n", libname);
diff --git a/ldso/ldso/dl-hash.c b/ldso/ldso/dl-hash.c
index f69f0c171..57fb995ab 100644
--- a/ldso/ldso/dl-hash.c
+++ b/ldso/ldso/dl-hash.c
@@ -154,7 +154,7 @@ struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
* relocations or when we call an entry in the PLT table for the first time.
*/
char *_dl_find_hash(const char *name, struct dyn_elf *rpnt1,
- struct elf_resolve *f_tpnt, enum caller_type caller_type)
+ int type_class)
{
struct elf_resolve *tpnt;
int si;
@@ -163,23 +163,12 @@ char *_dl_find_hash(const char *name, struct dyn_elf *rpnt1,
Elf32_Sym *symtab;
unsigned long elf_hash_number, hn;
char *weak_result;
- struct dyn_elf *rpnt, first;
+ struct dyn_elf *rpnt;
const ElfW(Sym) *sym;
weak_result = 0;
elf_hash_number = _dl_elf_hash(name);
- /* A quick little hack to make sure that any symbol in the executable
- will be preferred to one in a shared library. This is necessary so
- that any shared library data symbols referenced in the executable
- will be seen at the same address by the executable, shared libraries
- and dynamically loaded code. -Rob Ryan (robr@cmu.edu) */
- if (_dl_symbol_tables && rpnt1) {
- first = (*_dl_symbol_tables);
- first.next = rpnt1;
- rpnt1 = (&first);
- }
-
/*
* The passes are so that we can first search the regular symbols
* for whatever module was specified, and then search anything
@@ -187,39 +176,35 @@ char *_dl_find_hash(const char *name, struct dyn_elf *rpnt1,
* starting the first dlopened module, and anything above that
* is just the next one in the chain.
*/
+ if (rpnt1 == NULL)
+ rpnt1 = _dl_symbol_tables;
+
for (pass = 0; (1 == 1); pass++) {
/*
* If we are just starting to search for RTLD_GLOBAL, setup
* the pointer for the start of the search.
*/
- if (pass == 1) {
+ if (pass == 1)
rpnt1 = _dl_handles;
- }
/*
* Anything after this, we need to skip to the next module.
*/
- else if (pass >= 2) {
+ else if (pass >= 2)
rpnt1 = rpnt1->next_handle;
- }
/*
- * Make sure we still have a module, and make sure that this
- * module was loaded with RTLD_GLOBAL.
+ * Make sure we still have a module.
*/
- if (pass != 0) {
if (rpnt1 == NULL)
break;
- //if ((rpnt1->flags & RTLD_GLOBAL) == 0)
- //continue;
- }
- for (rpnt = (rpnt1 ? rpnt1 : _dl_symbol_tables); rpnt; rpnt = rpnt->next) {
+ for (rpnt = rpnt1; rpnt; rpnt = rpnt->next) {
tpnt = rpnt->dyn;
/* Don't search the executable when resolving a copy reloc. */
- if (tpnt->libtype == elf_executable && caller_type == copyrel)
+ if ((type_class & ELF_RTYPE_CLASS_COPY) && tpnt->libtype == elf_executable)
continue;
/*
@@ -236,19 +221,25 @@ char *_dl_find_hash(const char *name, struct dyn_elf *rpnt1,
continue;
if (ELF32_ST_TYPE(sym->st_info) > STT_FUNC)
continue;
- if (sym->st_shndx == SHN_UNDEF && caller_type != copyrel)
+ if (type_class & (sym->st_shndx == SHN_UNDEF))
continue;
if (_dl_strcmp(strtab + sym->st_name, name) != 0)
continue;
switch (ELF32_ST_BIND(sym->st_info)) {
case STB_WEAK:
-//Disable this to match current glibc behavior. Of course,
-//this doesn't actually work yet and will cause segfaults...
-#if 1
+#ifndef __LIBDL_SHARED__
+/*
+Due to a special hack in libdl.c, one must handle the _dl_ symbols
+according to the OLD weak symbol scheme. This stuff can be deleted
+once that hack has been fixed.
+*/
+
+ if(_dl_symbol((char *)name)) {
if (!weak_result)
weak_result = (char *)tpnt->loadaddr + sym->st_value;
break;
+ }
#endif
case STB_GLOBAL:
return (char*)tpnt->loadaddr + sym->st_value;
diff --git a/ldso/ldso/dl-startup.c b/ldso/ldso/dl-startup.c
index e9191e8a4..3a0c31419 100644
--- a/ldso/ldso/dl-startup.c
+++ b/ldso/ldso/dl-startup.c
@@ -513,11 +513,10 @@ found_got:
/* We only do a partial dynamic linking right now. The user
is not supposed to define any symbols that start with a
'_dl', so we can do this with confidence. */
- if (!symname || symname[0] != '_' ||
- symname[1] != 'd' || symname[2] != 'l' || symname[3] != '_')
- {
+ if (!symname || !_dl_symbol(symname)) {
continue;
}
+
symbol_addr = load_addr + symtab[symtab_index].st_value;
if (!symbol_addr) {
diff --git a/ldso/ldso/i386/dl-sysdep.h b/ldso/ldso/i386/dl-sysdep.h
index f39a1966c..d7475d630 100644
--- a/ldso/ldso/i386/dl-sysdep.h
+++ b/ldso/ldso/i386/dl-sysdep.h
@@ -79,3 +79,12 @@ extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_ent
#define PAGE_ALIGN 0xfffff000
#define ADDR_ALIGN 0xfff
#define OFFS_ALIGN 0x7ffff000
+
+/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
+ TLS variable, so undefined references should not be allowed to
+ define the value.
+ ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
+ of the main executable's symbols, as for a COPY reloc. */
+#define elf_machine_type_class(type) \
+ ((((type) == R_386_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_386_COPY) * ELF_RTYPE_CLASS_COPY))
diff --git a/ldso/ldso/i386/elfinterp.c b/ldso/ldso/i386/elfinterp.c
index 867365236..362df3c96 100644
--- a/ldso/ldso/i386/elfinterp.c
+++ b/ldso/ldso/i386/elfinterp.c
@@ -133,7 +133,7 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
symname= strtab + symtab[symtab_index].st_name;
- if (reloc_type != R_386_JMP_SLOT) {
+ if (unlikely(reloc_type != R_386_JMP_SLOT)) {
_dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n",
_dl_progname);
_dl_exit(1);
@@ -145,15 +145,11 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
got_addr = (char **) instr_addr;
/* Get the address of the GOT entry */
- new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, resolver);
- if (!new_addr) {
- new_addr = _dl_find_hash(symname, NULL, NULL, resolver);
- if (new_addr) {
- return (unsigned long) new_addr;
- }
+ new_addr = _dl_find_hash(symname, tpnt->symbol_scope, ELF_RTYPE_CLASS_PLT);
+ if (unlikely(!new_addr)) {
_dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
_dl_exit(1);
- }
+ };
#if defined (__SUPPORT_LD_DEBUG__)
if ((unsigned long) got_addr < 0x40000000)
@@ -263,7 +259,7 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
if (symtab_index) {
symbol_addr = (unsigned long) _dl_find_hash(symname, scope,
- (reloc_type == R_386_JMP_SLOT ? tpnt : NULL), symbolrel);
+ elf_machine_type_class(reloc_type));
/*
* We want to allow undefined references to weak symbols - this might
@@ -377,7 +373,7 @@ _dl_do_copy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
symname = strtab + symtab[symtab_index].st_name;
if (symtab_index) {
- symbol_addr = (unsigned long) _dl_find_hash(symname, scope, NULL, copyrel);
+ symbol_addr = (unsigned long) _dl_find_hash(symname, scope, ELF_RTYPE_CLASS_COPY);
if (!symbol_addr) goof++;
}
if (!goof) {
diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c
index 71fadd4dd..2e0fa757f 100644
--- a/ldso/ldso/ldso.c
+++ b/ldso/ldso/ldso.c
@@ -609,12 +609,12 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *app_tpnt
up each symbol individually. */
- _dl_brkp = (unsigned long *) (intptr_t) _dl_find_hash("___brk_addr", NULL, NULL, symbolrel);
+ _dl_brkp = (unsigned long *) (intptr_t) _dl_find_hash("___brk_addr", NULL, 0);
if (_dl_brkp) {
*_dl_brkp = brk_addr;
}
- _dl_envp = (unsigned long *) (intptr_t) _dl_find_hash("__environ", NULL, NULL, symbolrel);
+ _dl_envp = (unsigned long *) (intptr_t) _dl_find_hash("__environ", NULL, 0);
if (_dl_envp) {
*_dl_envp = (unsigned long) envp;
@@ -638,10 +638,10 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *app_tpnt
}
#endif
- _dl_atexit = (int (*)(void *)) (intptr_t) _dl_find_hash("atexit", NULL, NULL, symbolrel);
+ _dl_atexit = (int (*)(void *)) (intptr_t) _dl_find_hash("atexit", NULL, 0);
#if defined (__SUPPORT_LD_DEBUG__)
_dl_on_exit = (int (*)(void (*)(int, void *),void*))
- (intptr_t) _dl_find_hash("on_exit", NULL, NULL, symbolrel);
+ (intptr_t) _dl_find_hash("on_exit", NULL, 0);
#endif
/* Notify the debugger we have added some objects. */
diff --git a/ldso/ldso/m68k/dl-sysdep.h b/ldso/ldso/m68k/dl-sysdep.h
index 2cbc7d46b..d8936f530 100644
--- a/ldso/ldso/m68k/dl-sysdep.h
+++ b/ldso/ldso/m68k/dl-sysdep.h
@@ -86,3 +86,11 @@ extern unsigned int _dl_linux_resolver (int, int, struct elf_resolve *, int);
#define PAGE_ALIGN 0xfffff000
#define ADDR_ALIGN 0xfff
#define OFFS_ALIGN 0x7ffff000
+
+/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
+ PLT entries should not be allowed to define the value.
+ ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
+ of the main executable's symbols, as for a COPY reloc. */
+#define elf_machine_type_class(type) \
+ ((((type) == R_68K_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_68K_COPY) * ELF_RTYPE_CLASS_COPY))
diff --git a/ldso/ldso/m68k/elfinterp.c b/ldso/ldso/m68k/elfinterp.c
index 1bcbec389..a03352976 100644
--- a/ldso/ldso/m68k/elfinterp.c
+++ b/ldso/ldso/m68k/elfinterp.c
@@ -98,7 +98,7 @@ unsigned int _dl_linux_resolver (int dummy1, int dummy2,
/* Get the address of the GOT entry. */
new_addr = _dl_find_hash (strtab + symtab[symtab_index].st_name,
- tpnt->symbol_scope, tpnt, resolver);
+ tpnt->symbol_scope, ELF_RTYPE_CLASS_PLT);
if (!new_addr)
{
_dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
@@ -218,7 +218,7 @@ int _dl_parse_relocation_information(struct dyn_elf *rpnt,
symbol_addr = (unsigned int)
_dl_find_hash (strtab + symtab[symtab_index].st_name,
tpnt->symbol_scope,
- reloc_type == R_68K_JMP_SLOT ? tpnt : NULL, symbolrel);
+ elf_machine_type_class(reloc_type));
/* We want to allow undefined references to weak symbols -
this might have been intentional. We should not be
@@ -342,7 +342,7 @@ int _dl_parse_copy_information(struct dyn_elf *xpnt,
{
symbol_addr = (unsigned int)
_dl_find_hash (strtab + symtab[symtab_index].st_name,
- xpnt->next, NULL, copyrel);
+ xpnt->next, ELF_RTYPE_CLASS_COPY);
if (!symbol_addr)
{
_dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
diff --git a/ldso/ldso/mips/dl-sysdep.h b/ldso/ldso/mips/dl-sysdep.h
index 17ce7cf71..879cb8340 100644
--- a/ldso/ldso/mips/dl-sysdep.h
+++ b/ldso/ldso/mips/dl-sysdep.h
@@ -134,3 +134,5 @@ unsigned long _dl_linux_resolver(unsigned long sym_index,
#define PAGE_ALIGN 0xfffff000
#define ADDR_ALIGN 0xfff
#define OFFS_ALIGN 0x7ffff000
+
+#define elf_machine_type_class(type) ELF_RTYPE_CLASS_PLT
diff --git a/ldso/ldso/mips/elfinterp.c b/ldso/ldso/mips/elfinterp.c
index 59eca691b..5d3355b88 100644
--- a/ldso/ldso/mips/elfinterp.c
+++ b/ldso/ldso/mips/elfinterp.c
@@ -128,8 +128,13 @@ unsigned long _dl_linux_resolver(unsigned long sym_index,
strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
symname = strtab + sym->st_name;
- new_addr = (unsigned long) _dl_find_hash(strtab + sym->st_name,
- tpnt->symbol_scope, tpnt, resolver);
+ new_addr = (unsigned long) _dl_find_hash(symname,
+ tpnt->symbol_scope, ELF_RTYPE_CLASS_PLT);
+ if (!new_addr) {
+ _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
+ _dl_progname, symname);
+ _dl_exit (1);
+ }
/* Address of jump instruction to fix up */
instr_addr = (unsigned long) (got + local_gotno + sym_index - gotsym);
@@ -279,12 +284,12 @@ void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt)
*got_entry = sym->st_value + (unsigned long) tpnt->loadaddr;
else {
*got_entry = (unsigned long) _dl_find_hash(strtab +
- sym->st_name, tpnt->symbol_scope, NULL, copyrel);
+ sym->st_name, tpnt->symbol_scope, ELF_RTYPE_CLASS_COPY);
}
}
else if (sym->st_shndx == SHN_COMMON) {
*got_entry = (unsigned long) _dl_find_hash(strtab +
- sym->st_name, tpnt->symbol_scope, NULL, copyrel);
+ sym->st_name, tpnt->symbol_scope, ELF_RTYPE_CLASS_COPY);
}
else if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC &&
*got_entry != sym->st_value)
@@ -295,7 +300,7 @@ void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt)
}
else {
*got_entry = (unsigned long) _dl_find_hash(strtab +
- sym->st_name, tpnt->symbol_scope, NULL, copyrel);
+ sym->st_name, tpnt->symbol_scope, ELF_RTYPE_CLASS_COPY);
}
got_entry++;
diff --git a/ldso/ldso/powerpc/dl-sysdep.h b/ldso/ldso/powerpc/dl-sysdep.h
index 8768c9ac4..1a78b1b8b 100644
--- a/ldso/ldso/powerpc/dl-sysdep.h
+++ b/ldso/ldso/powerpc/dl-sysdep.h
@@ -125,3 +125,16 @@ void _dl_init_got(unsigned long *lpnt,struct elf_resolve *tpnt);
#define PAGE_ALIGN 0xfffff000
#define ADDR_ALIGN 0xfff
#define OFFS_ALIGN 0x7ffff000
+
+/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
+ PLT entries should not be allowed to define the value.
+ ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
+ of the main executable's symbols, as for a COPY reloc. */
+/* We never want to use a PLT entry as the destination of a
+ reloc, when what is being relocated is a branch. This is
+ partly for efficiency, but mostly so we avoid loops. */
+#define elf_machine_type_class(type) \
+ ((((type) == R_PPC_JMP_SLOT \
+ || (type) == R_PPC_REL24 \
+ || (type) == R_PPC_ADDR24) * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_PPC_COPY) * ELF_RTYPE_CLASS_COPY))
diff --git a/ldso/ldso/powerpc/elfinterp.c b/ldso/ldso/powerpc/elfinterp.c
index eb2f986b8..fec92e6fc 100644
--- a/ldso/ldso/powerpc/elfinterp.c
+++ b/ldso/ldso/powerpc/elfinterp.c
@@ -209,8 +209,8 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
#endif
/* Get the address of the GOT entry */
- finaladdr = (Elf32_Addr) _dl_find_hash(strtab + symtab[symtab_index].st_name,
- tpnt->symbol_scope, tpnt, resolver);
+ finaladdr = (Elf32_Addr) _dl_find_hash(symname,
+ tpnt->symbol_scope, ELF_RTYPE_CLASS_PLT);
if (!finaladdr) {
_dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
_dl_exit(1);
@@ -223,11 +223,8 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
delta = finaladdr - (Elf32_Word)reloc_addr;
if (delta<<6>>6 == delta) {
*reloc_addr = OPCODE_B(delta);
-#if 0
- /* this will almost never be true */
- } else if (finaladdr <= 0x01fffffc || finaladdr >= 0xfe000000) {
+ } else if (finaladdr <= 0x01fffffc) {
*reloc_addr = OPCODE_BA (finaladdr);
-#endif
} else {
/* Warning: we don't handle double-sized PLT entries */
Elf32_Word *plt, *data_words, index, offset;
@@ -261,7 +258,6 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
char *symname;
Elf32_Addr *reloc_addr;
Elf32_Addr finaladdr;
- struct dyn_elf *sym_scope;
unsigned long symbol_addr;
#if defined (__SUPPORT_LD_DEBUG__)
@@ -278,19 +274,8 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
symtab_index = ELF32_R_SYM(rpnt->r_info);
symname = strtab + symtab[symtab_index].st_name;
-#if 1
- sym_scope = scope->dyn->symbol_scope;
-#else
- /* Funny, this works too and appears to be much faster. */
- sym_scope = scope;
-#endif
- if (reloc_type == R_PPC_COPY) {
- sym_scope = scope->next;
- tpnt = NULL; /* To be or not to be ...*/
- }
- symbol_addr = (unsigned long) _dl_find_hash(symname, sym_scope,
- (reloc_type == R_PPC_JMP_SLOT ? tpnt : NULL),
- (reloc_type == R_PPC_COPY ? copyrel : symbolrel));
+ symbol_addr = (unsigned long) _dl_find_hash(symname, scope->dyn->symbol_scope,
+ elf_machine_type_class(reloc_type));
/*
* We want to allow undefined references to weak symbols - this might
* have been intentional. We should not be linking local symbols
@@ -320,11 +305,8 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
if (delta<<6>>6 == delta) {
*reloc_addr = OPCODE_B(delta);
-#if 0
- /* this will almost never be true */
- } else if (finaladdr <= 0x01fffffc || finaladdr >= 0xfe000000) {
+ } else if (finaladdr <= 0x01fffffc) {
*reloc_addr = OPCODE_BA (finaladdr);
-#endif
} else {
/* Warning: we don't handle double-sized PLT entries */
Elf32_Word *plt, *data_words, index, offset;
@@ -384,7 +366,7 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
_dl_dprintf(2, "%s ", _dl_reltypes(reloc_type));
#endif
if (symtab_index)
- _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
+ _dl_dprintf(2, "'%s'\n", symname);
return -1;
};
diff --git a/ldso/ldso/sh/dl-sysdep.h b/ldso/ldso/sh/dl-sysdep.h
index cd110895c..83cc9b391 100644
--- a/ldso/ldso/sh/dl-sysdep.h
+++ b/ldso/ldso/sh/dl-sysdep.h
@@ -142,3 +142,12 @@ _dl_urem(unsigned int n, unsigned int base)
#define PAGE_ALIGN 0xfffff000
#define ADDR_ALIGN 0xfff
#define OFFS_ALIGN 0x7ffff000
+
+/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
+ TLS variable, so undefined references should not be allowed to
+ define the value.
+ ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
+ of the main executable's symbols, as for a COPY reloc. */
+#define elf_machine_type_class(type) \
+ ((((type) == R_SH_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_SH_COPY) * ELF_RTYPE_CLASS_COPY))
diff --git a/ldso/ldso/sh/elfinterp.c b/ldso/ldso/sh/elfinterp.c
index a2edffea2..e0032601c 100644
--- a/ldso/ldso/sh/elfinterp.c
+++ b/ldso/ldso/sh/elfinterp.c
@@ -149,13 +149,8 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
/* Get the address of the GOT entry */
- new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, resolver);
+ new_addr = _dl_find_hash(symname, tpnt->symbol_scope, ELF_RTYPE_CLASS_PLT);
if (!new_addr) {
- new_addr = _dl_find_hash(symname, NULL, NULL, resolver);
- if (new_addr) {
- return (unsigned long) new_addr;
- }
-
_dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
_dl_exit(1);
}
@@ -270,7 +265,7 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
symbol_addr = (unsigned long) _dl_find_hash(symname, scope,
- (reloc_type == R_SH_JMP_SLOT ? tpnt : NULL), symbolrel);
+ elf_machine_type_class(reloc_type));
/*
* We want to allow undefined references to weak symbols - this might
@@ -385,7 +380,7 @@ _dl_do_copy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
if (symtab_index) {
- symbol_addr = (unsigned long) _dl_find_hash(symname, scope, NULL, copyrel);
+ symbol_addr = (unsigned long) _dl_find_hash(symname, scope, ELF_RTYPE_CLASS_COPY);
if (!symbol_addr) goof++;
}
if (!goof) {
diff --git a/ldso/ldso/sh64/dl-sysdep.h b/ldso/ldso/sh64/dl-sysdep.h
index 241cde93e..f654b8333 100644
--- a/ldso/ldso/sh64/dl-sysdep.h
+++ b/ldso/ldso/sh64/dl-sysdep.h
@@ -168,3 +168,11 @@ extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_ent
#define ADDR_ALIGN 0xfff
#define OFFS_ALIGN 0x7ffff000
+/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
+ TLS variable, so undefined references should not be allowed to
+ define the value.
+ ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
+ of the main executable's symbols, as for a COPY reloc. */
+#define elf_machine_type_class(type) \
+ ((((type) == R_SH_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_SH_COPY) * ELF_RTYPE_CLASS_COPY))
diff --git a/ldso/ldso/sh64/elfinterp.c b/ldso/ldso/sh64/elfinterp.c
index fce53dbc3..d4f45d52f 100644
--- a/ldso/ldso/sh64/elfinterp.c
+++ b/ldso/ldso/sh64/elfinterp.c
@@ -190,13 +190,8 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
/* Get the address of the GOT entry */
- new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, resolver);
+ new_addr = _dl_find_hash(symname, tpnt->symbol_scope, ELF_RTYPE_CLASS_PLT);
if (!new_addr) {
- new_addr = _dl_find_hash(symname, NULL, NULL, resolver);
-
- if (new_addr)
- return (unsigned long)new_addr;
-
_dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
_dl_progname, symname);
_dl_exit(1);
@@ -319,8 +314,7 @@ static int _dl_do_reloc(struct elf_resolve *tpnt,struct dyn_elf *scope,
int stb;
symbol_addr = (unsigned long)_dl_find_hash(symname, scope,
- (reloc_type == R_SH_JMP_SLOT ? tpnt : NULL),
- symbolrel);
+ elf_machine_type_class(reloc_type));
/*
* We want to allow undefined references to weak symbols - this
@@ -492,7 +486,7 @@ static int _dl_do_copy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
if (symtab_index) {
symbol_addr = (unsigned long)
- _dl_find_hash(symname, scope, NULL, copyrel);
+ _dl_find_hash(symname, scope, ELF_RTYPE_CLASS_COPY);
if (!symbol_addr)
goof++;
diff --git a/ldso/ldso/sparc/dl-sysdep.h b/ldso/ldso/sparc/dl-sysdep.h
index 1930a937f..72a85538e 100644
--- a/ldso/ldso/sparc/dl-sysdep.h
+++ b/ldso/ldso/sparc/dl-sysdep.h
@@ -110,3 +110,11 @@ extern unsigned int _dl_linux_resolver(unsigned int reloc_entry,
#define PAGE_ALIGN 0xfffff000
#define ADDR_ALIGN 0xfff
#define OFFS_ALIGN 0x7ffff000
+
+/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
+ PLT entries should not be allowed to define the value.
+ ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
+ of the main executable's symbols, as for a COPY reloc. */
+#define elf_machine_type_class(type) \
+ ((((type) == R_SPARC_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_SPARC_COPY) * ELF_RTYPE_CLASS_COPY))
diff --git a/ldso/ldso/sparc/elfinterp.c b/ldso/ldso/sparc/elfinterp.c
index e9e55c090..ada72bfe5 100644
--- a/ldso/ldso/sparc/elfinterp.c
+++ b/ldso/ldso/sparc/elfinterp.c
@@ -109,7 +109,7 @@ unsigned int _dl_linux_resolver(unsigned int reloc_entry, unsigned int * plt)
/* Get the address of the GOT entry */
new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name,
- tpnt->symbol_scope, tpnt, resolver);
+ tpnt->symbol_scope, ELF_RTYPE_CLASS_PLT);
if(!new_addr) {
_dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
_dl_progname, strtab + symtab[symtab_index].st_name);
@@ -225,8 +225,7 @@ int _dl_parse_relocation_information(struct dyn_elf *rpnt,
symbol_addr = (unsigned int)
_dl_find_hash(strtab + symtab[symtab_index].st_name,
- tpnt->symbol_scope,
- (reloc_type == R_SPARC_JMP_SLOT ? tpnt : NULL), symbolrel);
+ tpnt->symbol_scope, elf_machine_type_class(reloc_type);
if(!symbol_addr &&
ELF32_ST_BIND(symtab [symtab_index].st_info) == STB_GLOBAL) {
@@ -343,7 +342,7 @@ int _dl_parse_copy_information(struct dyn_elf *xpnt,
symbol_addr = (unsigned int)
_dl_find_hash(strtab + symtab[symtab_index].st_name,
- xpnt->next, NULL, copyrel);
+ xpnt->next, ELF_RTYPE_CLASS_COPY);
if(!symbol_addr) {
_dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
_dl_progname, strtab + symtab[symtab_index].st_name);
diff --git a/ldso/libdl/libdl.c b/ldso/libdl/libdl.c
index f3bc89abd..5d7c22b85 100644
--- a/ldso/libdl/libdl.c
+++ b/ldso/libdl/libdl.c
@@ -30,7 +30,7 @@ static void __attribute__ ((unused)) foobar(void)
static int __attribute__ ((unused)) foobar1 = (int) foobar; /* Use as pointer */
extern void _dl_dprintf(int, const char *, ...) __attribute__ ((__weak__, __alias__ ("foobar")));
-extern char *_dl_find_hash(const char *, struct dyn_elf *, struct elf_resolve *, enum caller_type)
+extern char *_dl_find_hash(const char *, struct dyn_elf *, int)
__attribute__ ((__weak__, __alias__ ("foobar")));
extern struct elf_resolve * _dl_load_shared_library(int, struct dyn_elf **, struct elf_resolve *, char *, int)
__attribute__ ((__weak__, __alias__ ("foobar")));
@@ -179,6 +179,7 @@ void *_dlopen(const char *libname, int flag)
if(_dl_debug)
_dl_dprintf(_dl_debug_file, "Trying to dlopen '%s'\n", (char*)libname);
#endif
+ if (!(tpnt = _dl_check_if_named_library_is_loaded((char *)libname, 0)))
tpnt = _dl_load_shared_library(0, &rpnt, tfrom, (char*)libname, 0);
if (tpnt == NULL) {
_dl_unmap_cache();
@@ -220,6 +221,9 @@ void *_dlopen(const char *libname, int flag)
dpnt->d_un.d_val);
name = _dl_get_last_path_component(lpntstr);
+ if ((tpnt1 = _dl_check_if_named_library_is_loaded(name, 0)))
+ continue;
+
#ifdef __SUPPORT_LD_DEBUG__
if(_dl_debug)
_dl_dprintf(_dl_debug_file, "Trying to load '%s', needed by '%s'\n",
@@ -381,7 +385,7 @@ void *_dlsym(void *vhandle, const char *name)
}
}
- ret = _dl_find_hash((char*)name, handle, NULL, copyrel);
+ ret = _dl_find_hash((char*)name, handle, 0);
/*
* Nothing found.