diff options
Diffstat (limited to 'ldso')
-rw-r--r-- | ldso/include/dl-defs.h | 7 | ||||
-rw-r--r-- | ldso/include/dl-elf.h | 5 | ||||
-rw-r--r-- | ldso/include/dl-hash.h | 18 | ||||
-rw-r--r-- | ldso/ldso/bfin/elfinterp.c | 8 | ||||
-rw-r--r-- | ldso/ldso/dl-hash.c | 35 | ||||
-rw-r--r-- | ldso/libdl/libdl.c | 2 |
6 files changed, 61 insertions, 14 deletions
diff --git a/ldso/include/dl-defs.h b/ldso/include/dl-defs.h index 19eab074f..21a66a40f 100644 --- a/ldso/include/dl-defs.h +++ b/ldso/include/dl-defs.h @@ -181,4 +181,11 @@ typedef struct { #define __C_SYMBOL_PREFIX__ "_" #endif +/* Define this if you want to modify the VALUE returned by + _dl_find_hash for this reloc TYPE. TPNT is the module in which the + matching SYM was found. */ +#ifndef DL_FIND_HASH_VALUE +# define DL_FIND_HASH_VALUE(TPNT, TYPE, SYM) (DL_RELOC_ADDR ((SYM)->st_value, (TPNT)->loadaddr)) +#endif + #endif /* _LD_DEFS_H */ diff --git a/ldso/include/dl-elf.h b/ldso/include/dl-elf.h index 3e418622d..320a0f920 100644 --- a/ldso/include/dl-elf.h +++ b/ldso/include/dl-elf.h @@ -183,6 +183,11 @@ void __dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info[], #endif #define ELF_RTYPE_CLASS_PLT (0x1) +/* dlsym() calls _dl_find_hash with this value, that enables + DL_FIND_HASH_VALUE to return something different than the symbol + itself, e.g., a function descriptor. */ +#define ELF_RTYPE_CLASS_DLSYM 0x80000000 + /* Convert between the Linux flags for page protections and the ones specified in the ELF standard. */ diff --git a/ldso/include/dl-hash.h b/ldso/include/dl-hash.h index 5239467c1..e5f9f8806 100644 --- a/ldso/include/dl-hash.h +++ b/ldso/include/dl-hash.h @@ -105,8 +105,22 @@ extern struct elf_resolve * _dl_add_elf_hash_table(const char * libname, DL_LOADADDR_TYPE loadaddr, unsigned long * dynamic_info, unsigned long dynamic_addr, unsigned long dynamic_size); -extern char * _dl_find_hash(const char * name, struct dyn_elf * rpnt1, - struct elf_resolve *mytpnt, int type_class); +extern char * _dl_lookup_hash(const char * name, struct dyn_elf * rpnt, + struct elf_resolve *mytpnt, int type_class +#ifdef __FDPIC__ + , struct elf_resolve **tpntp +#endif + ); + +static __always_inline char *_dl_find_hash(const char *name, struct dyn_elf *rpnt, + struct elf_resolve *mytpnt, int type_class) +{ +#ifdef __FDPIC__ + return _dl_lookup_hash(name, rpnt, mytpnt, type_class, NULL); +#else + return _dl_lookup_hash(name, rpnt, mytpnt, type_class); +#endif +} extern int _dl_linux_dynamic_link(void); diff --git a/ldso/ldso/bfin/elfinterp.c b/ldso/ldso/bfin/elfinterp.c index 02d250d97..d003e2e71 100644 --- a/ldso/ldso/bfin/elfinterp.c +++ b/ldso/ldso/bfin/elfinterp.c @@ -72,11 +72,9 @@ _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry) got_entry = (struct funcdesc_value *) DL_RELOC_ADDR(tpnt->loadaddr, this_reloc->r_offset); /* Get the address to be used to fill in the GOT entry. */ - new_addr = _dl_find_hash_mod(symname, tpnt->symbol_scope, NULL, 0, - &new_tpnt); + new_addr = _dl_lookup_hash(symname, tpnt->symbol_scope, NULL, 0, &new_tpnt); if (!new_addr) { - new_addr = _dl_find_hash_mod(symname, NULL, NULL, 0, - &new_tpnt); + new_addr = _dl_lookup_hash(symname, NULL, NULL, 0, &new_tpnt); if (!new_addr) { _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname); @@ -188,7 +186,7 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope, } else { symbol_addr = (unsigned long) - _dl_find_hash_mod(symname, scope, NULL, 0, &symbol_tpnt); + _dl_lookup_hash(symname, scope, NULL, 0, &symbol_tpnt); /* * We want to allow undefined references to weak symbols - this might diff --git a/ldso/ldso/dl-hash.c b/ldso/ldso/dl-hash.c index c85035ba8..daa407597 100644 --- a/ldso/ldso/dl-hash.c +++ b/ldso/ldso/dl-hash.c @@ -257,7 +257,12 @@ _dl_lookup_sysv_hash(struct elf_resolve *tpnt, ElfW(Sym) *symtab, unsigned long * This function resolves externals, and this is either called when we process * 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 *rpnt, struct elf_resolve *mytpnt, int type_class) +char *_dl_lookup_hash(const char *name, struct dyn_elf *rpnt, + struct elf_resolve *mytpnt, int type_class +#ifdef __FDPIC__ + , struct elf_resolve **tpntp +#endif + ) { struct elf_resolve *tpnt = NULL; ElfW(Sym) *symtab; @@ -265,7 +270,8 @@ char *_dl_find_hash(const char *name, struct dyn_elf *rpnt, struct elf_resolve * unsigned long elf_hash_number = 0xffffffff; const ElfW(Sym) *sym = NULL; - char *weak_result = NULL; + const ElfW(Sym) *weak_sym = 0; + struct elf_resolve *weak_tpnt = 0; #ifdef __LDSO_GNU_HASH_SUPPORT__ unsigned long gnu_hash_number = _dl_gnu_hash((const unsigned char *)name); @@ -326,15 +332,32 @@ char *_dl_find_hash(const char *name, struct dyn_elf *rpnt, struct elf_resolve * #if 0 /* Perhaps we should support old style weak symbol handling * per what glibc does when you export LD_DYNAMIC_WEAK */ - if (!weak_result) - weak_result = (char *) DL_RELOC_ADDR(tpnt->loadaddr, sym->st_value); + if (!weak_sym) { + weak_tpnt = tpnt; + weak_sym = sym; + } break; #endif case STB_GLOBAL: - return (char*) DL_RELOC_ADDR(tpnt->loadaddr, sym->st_value); +#ifdef __FDPIC__ + if (tpntp) + *tpntp = tpnt; +#endif + return DL_FIND_HASH_VALUE (tpnt, type_class, sym); default: /* Local symbols not handled here */ break; } } - return weak_result; + if (weak_sym) { +#ifdef __FDPIC__ + if (tpntp) + *tpntp = weak_tpnt; +#endif + return DL_FIND_HASH_VALUE (weak_tpnt, type_class, weak_sym); + } +#ifdef __FDPIC__ + if (tpntp) + *tpntp = NULL; +#endif + return NULL; } diff --git a/ldso/libdl/libdl.c b/ldso/libdl/libdl.c index e4a49c83a..9a6714abf 100644 --- a/ldso/libdl/libdl.c +++ b/ldso/libdl/libdl.c @@ -500,7 +500,7 @@ void *dlsym(void *vhandle, const char *name) tpnt = NULL; if (handle == _dl_symbol_tables) tpnt = handle->dyn; /* Only search RTLD_GLOBAL objs if global object */ - ret = _dl_find_hash(name2, handle, tpnt, 0); + ret = _dl_find_hash(name2, handle, tpnt, ELF_RTYPE_CLASS_DLSYM); /* * Nothing found. |