From deec524084aa2faad66f7aae7e8b5ba1ab6789fd Mon Sep 17 00:00:00 2001 From: Eric Andersen Date: Sat, 14 Feb 2004 11:30:39 +0000 Subject: Joakim Tjernlund writes: Hi it is me again. This is the latest ldso patch. the NEW weak symbol handling works now with a little special handling in _dl_find_hash(). You get to chose if you want the new or old handling :) There was 2 missing _dl_check_if_named_library_is_loaded() calls in _dlopen(). I then disabled the _dl_check_if_named_library_is_loaded() in dl-elf.c since it is rendundant. Question, why does some _dl_linux_resolver(), like i386, have 2 calls to _dl_find_hash()? I think that is wrong, isn't it? I really hope you can check this out soon ... --- ldso/include/dl-elf.h | 13 ++++++++++++ ldso/include/dl-hash.h | 3 +-- ldso/ldso/arm/dl-sysdep.h | 8 +++++++ ldso/ldso/arm/elfinterp.c | 15 ++++++------- ldso/ldso/cris/dl-sysdep.h | 16 ++++++++++++++ ldso/ldso/cris/elfinterp.c | 16 +++++--------- ldso/ldso/dl-elf.c | 3 ++- ldso/ldso/dl-hash.c | 49 ++++++++++++++++++------------------------- ldso/ldso/dl-startup.c | 5 ++--- ldso/ldso/i386/dl-sysdep.h | 9 ++++++++ ldso/ldso/i386/elfinterp.c | 16 ++++++-------- ldso/ldso/ldso.c | 8 +++---- ldso/ldso/m68k/dl-sysdep.h | 8 +++++++ ldso/ldso/m68k/elfinterp.c | 6 +++--- ldso/ldso/mips/dl-sysdep.h | 2 ++ ldso/ldso/mips/elfinterp.c | 15 ++++++++----- ldso/ldso/powerpc/dl-sysdep.h | 13 ++++++++++++ ldso/ldso/powerpc/elfinterp.c | 32 +++++++--------------------- ldso/ldso/sh/dl-sysdep.h | 9 ++++++++ ldso/ldso/sh/elfinterp.c | 11 +++------- ldso/ldso/sh64/dl-sysdep.h | 8 +++++++ ldso/ldso/sh64/elfinterp.c | 12 +++-------- ldso/ldso/sparc/dl-sysdep.h | 8 +++++++ ldso/ldso/sparc/elfinterp.c | 7 +++---- ldso/libdl/libdl.c | 8 +++++-- 25 files changed, 177 insertions(+), 123 deletions(-) (limited to 'ldso') 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. -- cgit v1.2.3