diff options
| -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. | 
