diff options
| -rw-r--r-- | ldso/ldso/cris/elfinterp.c | 455 | 
1 files changed, 226 insertions, 229 deletions
| diff --git a/ldso/ldso/cris/elfinterp.c b/ldso/ldso/cris/elfinterp.c index 3c376a6a8..5d2599d0b 100644 --- a/ldso/ldso/cris/elfinterp.c +++ b/ldso/ldso/cris/elfinterp.c @@ -41,19 +41,20 @@ static const char *_dl_reltypes_tab[] = {  	[8]		"R_CRIS_GNU_VTENTRY", "R_CRIS_COPY", "R_CRIS_GLOB_DAT", "R_CRIS_JUMP_SLOT",  	[16]	"R_CRIS_RELATIVE", "R_CRIS_16_GOT", "R_CRIS_32_GOT", "R_CRIS_16_GOTPLT",  	[32]	"R_CRIS_32_GOTPLT", "R_CRIS_32_GOTREL", "R_CRIS_32_PLT_GOTREL", "R_CRIS_32_PLT_PCREL", +  }; +  static const char *  _dl_reltypes(int type) -{  -	static char buf[22]; +{  	const char *str; -   -	if (type >= (sizeof(_dl_reltypes_tab) / sizeof(_dl_reltypes_tab[0])) || -		NULL == (str = _dl_reltypes_tab[type])) {  -    		str = _dl_simple_ltoa(buf, (unsigned long)(type)); -	} +	static char buf[22]; +	if (type >= (sizeof(_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) || +		NULL == (str = _dl_reltypes_tab[type])) +		str = _dl_simple_ltoa(buf, (unsigned long) (type)); +	  	return str;  } @@ -62,7 +63,8 @@ debug_sym(Elf32_Sym *symtab, char *strtab, int symtab_index)  {   	if (_dl_debug_symbols) {   		if (symtab_index) { -			_dl_dprintf(_dl_debug_file, "\n%s\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x", +			_dl_dprintf(_dl_debug_file,  +				"\n%s\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x",  				strtab + symtab[symtab_index].st_name,  				symtab[symtab_index].st_value,  				symtab[symtab_index].st_size, @@ -71,12 +73,12 @@ debug_sym(Elf32_Sym *symtab, char *strtab, int symtab_index)  				symtab[symtab_index].st_shndx);  		}    	} -}  -     +} +  static void  debug_reloc(Elf32_Sym *symtab, char *strtab, ELF_RELOC *rpnt) -{    -	if (_dl_debug_reloc) {  +{ +	if (_dl_debug_reloc) {  		int symtab_index;  		const char *sym; @@ -84,65 +86,68 @@ debug_reloc(Elf32_Sym *symtab, char *strtab, ELF_RELOC *rpnt)  		sym = symtab_index ? strtab + symtab[symtab_index].st_name : "sym=0x0";  		if (_dl_debug_symbols) -			_dl_printf(_dl_debug_file, "\n\t"); +			_dl_dprintf(_dl_debug_file, "\n\t");  		else -			_dl_printf(_dl_debug_file, "\n%s\n\t", sym); -         +			_dl_dprintf(_dl_debug_file, "\n%s\n\t", sym); +  #ifdef ELF_USES_RELOCA -		_dl_dprintf(_dl_debug_file, "\n%s\toffset=%x\taddend=%x", -			_dl_reltypes(ELF32_R_TYPE(rpnt->r_info)), rpnt->r_offset, rpnt->r_addend); +		_dl_dprintf(_dl_debug_file, "%s\toffset=%x\taddend=%x", +			_dl_reltypes(ELF32_R_TYPE(rpnt->r_info)), +			rpnt->r_offset, +			rpnt->r_addend);  #else -		_dl_dprintf(_dl_debug_file, "\n%s\toffset=%x", _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)), +		_dl_dprintf(_dl_debug_file, "%s\toffset%x\n", +			_dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),  			rpnt->r_offset);  #endif  	}  } -#endif +#endif /* __SUPPORT_LD_DEBUG__ */ -/* Defined in resolve.S */ -extern int _dl_linux_resolve(void); +/* Defined in resolve.S. */ +extern int _dl_linux_resolv(void);  unsigned long -_dl_linux_resolver(struct elf_resolve *tpnt, int reloc_offset) +_dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)  { -    	int reloc_type;  	int symtab_index;  	char *strtab;  	char *symname;  	char *new_addr; +	char *rel_addr;  	char **got_addr; -	ELF_RELOC *reloc;  	Elf32_Sym *symtab; -	Elf32_Addr instr_addr; -	 -	reloc = (ELF_RELOC *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr) + (reloc_offset >> 3); +	ELF_RELOC *this_reloc; +	unsigned long instr_addr; -	reloc_type = ELF32_R_TYPE(reloc->r_info); -	symtab_index = ELF32_R_SYM(reloc->r_info); +	rel_addr = (char *) (tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr); -	symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); -	strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); +	this_reloc = (ELF_RELOC *) (intptr_t)(rel_addr + (reloc_entry >> 3)); +	reloc_type = ELF32_R_TYPE(this_reloc->r_info); +	symtab_index = ELF32_R_SYM(this_reloc->r_info); + +	symtab = (Elf32_Sym *) (intptr_t)(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_CRIS_JUMP_SLOT) { -		_dl_dprintf(2, "%s: Incorrect relocation type for jump relocations.\n", _dl_progname); +		_dl_dprintf(2, "%s: Incorrect relocation type for jump relocations.\n", +			_dl_progname);  		_dl_exit(1);  	}  	/* Fetch the address of the jump instruction to fix up. */ -	instr_addr = ((Elf32_Addr) reloc->r_offset + (Elf32_Addr) tpnt->loadaddr); +	instr_addr = ((unsigned long) this_reloc->r_offset + (unsigned long) tpnt->loadaddr);  	got_addr = (char **) instr_addr; -#ifdef DL_DEBUG_SYMBOLS -	_dl_dprintf(_dl_debug_file, "Resolving symbol: %s\n", symname); -#endif -  	/* Fetch the address of the GOT entry. */  	new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, resolver); -	 +  	if (!new_addr) { -		if ((new_addr = _dl_find_hash(symname, NULL, NULL, resolver))) +		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); @@ -162,248 +167,240 @@ _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_offset)  	return (unsigned long) new_addr;  } -void -_dl_parse_lazy_relocation_information(struct elf_resolve *tpnt, unsigned long rel_addr, unsigned long rel_size, int type) +static int +_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope, unsigned long rel_addr, +	unsigned long rel_size, int (*reloc_fnc)(struct elf_resolve *tpnt, struct dyn_elf *scope,  +	                            ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))  { -	int i; -	int reloc_type;  	int symtab_index; +	int res; +	unsigned int i;  	char *strtab; -	char *symname;  	Elf32_Sym *symtab;  	ELF_RELOC *rpnt; -	Elf32_Addr *reloc_addr; -	/* Parse relocation information. */ -	rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr); -	rel_size = rel_size / sizeof(ELF_RELOC); -	symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); +	/* Parse the relocation information. */ +	rpnt = (ELF_RELOC *) (intptr_t) (rel_addr + tpnt->loadaddr); +	rel_size /= sizeof(ELF_RELOC); + +	symtab = (Elf32_Sym *) (intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);  	strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);  	for (i = 0; i < rel_size; i++, rpnt++) { -		reloc_addr = (Elf32_Addr *) (tpnt->loadaddr + (Elf32_Addr) rpnt->r_offset); -		reloc_type = ELF32_R_TYPE(rpnt->r_info);  		symtab_index = ELF32_R_SYM(rpnt->r_info); -		symname = strtab + symtab[symtab_index].st_name; -		/* -		 * Make sure we don't resolv the same symbols as we did -		 * when ld.so bootstrapped itself. +		/*  +		 * Make sure the same symbols that the linker resolved when it +		 * bootstapped itself isn't resolved again.  		 */  		if (!symtab_index && tpnt->libtype == program_interpreter) -		 	continue; +			continue; +  		if (symtab_index && tpnt->libtype == program_interpreter && -			_dl_symbol(symname)) +			_dl_symbol(strtab + symtab[symtab_index].st_name))  			continue;  #if defined (__SUPPORT_LD_DEBUG__) -	{ -		unsigned long old_val = *reloc_addr; - +		debug_sym(symtab, strtab, symtab_index); +		debug_reloc(symtab, strtab, rpnt);  #endif -		switch (reloc_type) { -			case R_CRIS_NONE: -				break; -			case R_CRIS_JUMP_SLOT: -				*reloc_addr += (Elf32_Addr) tpnt->loadaddr; -				break; -			default: -				_dl_dprintf(2, "%s: Can't handle relocation type (lazy).\n", -					_dl_progname); -#ifdef __SUPPORT_LD_DEBUG__ -					_dl_dprintf(_dl_debug_file, "%s ", _dl_reltypes(reloc_type)); -#endif -				if (symtab_index) -					_dl_dprintf(2, "'%s'\n", symname); -				_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); -	} +		/* Pass over to actual relocation function. */ +		res = reloc_fnc(tpnt, scope, rpnt, symtab, strtab); + +		if (res == 0) +			continue; + +		_dl_dprintf(2, "\n%s: ", _dl_progname); + +		if (symtab_index) +			_dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name); + +		if (res < 0) { +			int reloc_type = ELF32_R_TYPE(rpnt->r_info); + +#if defined (__SUPPORT_LD_DEBUG__) +			_dl_dprintf(2, "can't handle relocation type '%s'\n", _dl_reltypes(reloc_type)); +#else +			_dl_dprintf(2, "can't handle relocation type %x\n", reloc_type);  #endif +			_dl_exit(-res); +		} +		else if (res > 0) { +			_dl_dprintf(2, "can't resolv symbol\n"); +			return res; +		}  	} + +	return 0;  } -int -_dl_parse_relocation_information(struct elf_resolve *tpnt, unsigned long rel_addr, unsigned long rel_size, int type) +static int +_dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, ELF_RELOC *rpnt, +	Elf32_Sym *symtab, char *strtab)  { -	int i; -	int goof;  	int reloc_type;  	int symtab_index; -	char *strtab;  	char *symname; -	Elf32_Sym *symtab; -	ELF_RELOC *rpnt; -	Elf32_Addr *reloc_addr; -	Elf32_Addr symbol_addr; - -	goof = 0; -	rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr); -	rel_size = rel_size / sizeof(ELF_RELOC); - -	symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); -	strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); -	 -	for (i = 0; i < rel_size; i++, rpnt++) { -		reloc_addr = (Elf32_Addr *) (tpnt->loadaddr + (Elf32_Addr) 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; +	unsigned long *reloc_addr; +	unsigned symbol_addr; +#if defined (__SUPPORT_LD_DEBUG__) +	unsigned long old_val; +#endif -		if (!symtab_index && tpnt->libtype == program_interpreter) -			continue; +	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) { -			if (tpnt->libtype == program_interpreter && -				_dl_symbol(strtab + symtab[symtab_index].st_name)) -				continue; - -			if (symtab[symtab_index].st_shndx != SHN_UNDEF && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_LOCAL) -				symbol_addr = (Elf32_Addr) tpnt->loadaddr; -			else -				symbol_addr = (Elf32_Addr) _dl_find_hash(symname, tpnt->symbol_scope, -					(reloc_type == R_CRIS_JUMP_SLOT ? tpnt : NULL), 0); - -			/* -			 * We want to allow undefined references to weak symbols - this -			 * might have been intentional. We should not be linking local -			 * symbols here, so all bases should be covered. -			 */ -			if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) { -				_dl_dprintf(2, "%s: Can't resolve '%s'\n", _dl_progname, symname); -				goof++; -			} -			 -			symbol_addr += rpnt->r_addend; -		} +	if (symtab_index) { +		symbol_addr = (unsigned long) _dl_find_hash(symname, scope, +			(reloc_type == R_CRIS_JUMP_SLOT ? tpnt : NULL), symbolrel); -#if defined(__SUPPORT_LD_DEBUG__) -	{ -		unsigned long old_val = *reloc_addr; -		debug_sym(symtab,strtab,symtab_index); -		debug_reloc(symtab,strtab,rpnt); -#endif -		 -		switch (reloc_type) { -			case R_CRIS_GLOB_DAT: -			case R_CRIS_JUMP_SLOT: -			case R_CRIS_32: -				*reloc_addr = symbol_addr; -				break; -			case R_CRIS_RELATIVE: -				*reloc_addr = (Elf32_Addr) tpnt->loadaddr + rpnt->r_addend; -				break; -			case R_CRIS_COPY: -				*reloc_addr = symbol_addr; -				break; -			case R_CRIS_8: -				*(char *) reloc_addr = symbol_addr; -				break; -			case R_CRIS_16: -				*(short *) reloc_addr = symbol_addr; -				break; -			case R_CRIS_8_PCREL: -				*(char *) reloc_addr = symbol_addr + rpnt->r_addend - (Elf32_Addr) reloc_addr - 1; -				break; -			case R_CRIS_16_PCREL: -				*(short *) reloc_addr = symbol_addr + rpnt->r_addend - (Elf32_Addr) reloc_addr - 2; -				break; -			case R_CRIS_32_PCREL: -				*reloc_addr = symbol_addr + rpnt->r_addend - (Elf32_Addr) reloc_addr - 4; -				break; -			case R_CRIS_NONE: -				break; -			default: -				_dl_dprintf(2, "%s: Can't handle relocation type ", _dl_progname); -#ifdef __SUPPORT_LD_DEBUG__ -				_dl_dprintf(_dl_debug_file, "%s\n", _dl_reltypes(reloc_type)); +		if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) { +#if defined (__SUPPORT_LD_DEBUG__) +			_dl_dprintf(2, "\tglobal symbol '%s' already defined in '%s'\n", +				symname, tpnt->libname);  #endif -				if (symtab_index) { -					_dl_dprintf(2, "'%s'\n", symname); -					return -1; -				} +			return 0;  		} -#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 defined (__SUPPORT_LD_DEBUG__) +	old_val = *reloc_addr;  #endif + +	switch (reloc_type) { +		case R_CRIS_NONE: +			break; +		case R_CRIS_GLOB_DAT: +		case R_CRIS_JUMP_SLOT: +		case R_CRIS_32: +		case R_CRIS_COPY: +			*reloc_addr = symbol_addr; +			break; +		case R_CRIS_RELATIVE: +			*reloc_addr = (unsigned long) tpnt->loadaddr + rpnt->r_addend; +			break; +		default: +			return -1;	/* Call _dl_exit(1). */  	} -	return goof; + +#if defined (__SUPPORT_LD_DEBUG__) +	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;  } -/* - * This is done as a seperate step, because there are cases where - * information is first copied and later initialized. This results - * in the wrong information being copied. - */ -int -_dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr, unsigned long rel_size, int type) +static int +_dl_do_lazy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, ELF_RELOC *rpnt, +	Elf32_Sym *symtab, char *strtab)  { -	int i;  	int reloc_type; -	int goof; -	int symtab_index; -	char *strtab; -	char *symname; -	struct elf_resolve *tpnt; -	Elf32_Sym *symtab; -	ELF_RELOC *rpnt; -	Elf32_Addr *reloc_addr; -	Elf32_Addr symbol_addr; +	unsigned long *reloc_addr; +#if defined (__SUPPORT_LD_DEBUG__) +	unsigned long old_val; +#endif -	goof = 0; -	tpnt = xpnt->dyn; +	/* Don't care about these, just keep the compiler happy. */ +	(void) scope; +	(void) symtab; +	(void) strtab; -	rpnt = (ELF_RELOC *) (rel_addr + tpnt->loadaddr); -	rel_size = rel_size / sizeof(ELF_RELOC); +	reloc_addr = (unsigned long *)(intptr_t)(tpnt->loadaddr + (unsigned long) rpnt->r_offset); +	reloc_type = ELF32_R_TYPE(rpnt->r_info); -	symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); -	strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); -	symtab_index = ELF32_R_SYM(rpnt->r_info); -	symname = strtab + symtab[symtab_index].st_name; +#if defined (__SUPPORT_LD_DEBUG__) +	old_val = *reloc_addr; +#endif -	for (i = 0; i < rel_size; i++, rpnt++) { -		reloc_addr = (Elf32_Addr *) (tpnt->loadaddr + (Elf32_Addr) rpnt->r_offset); -		reloc_type = ELF32_R_TYPE(rpnt->r_info); +	switch (reloc_type) { +		case R_CRIS_NONE: +			break; +		case R_CRIS_JUMP_SLOT: +			*reloc_addr += (unsigned long) tpnt->loadaddr; +			break; +		default: +			return -1;	/* Calls _dl_exit(1). */ +	} -		if (reloc_type != R_CRIS_COPY) -			continue; +#if defined (__SUPPORT_LD_DEBUG__) +	if (_dl_debug_reloc && _dl_debug_detail) +		_dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr); +#endif -		symtab_index = ELF32_R_SYM(rpnt->r_info); -		symbol_addr = 0; +	return 0; +} -		if (!symtab_index && tpnt->libtype == program_interpreter) -			continue; +static int +_dl_do_copy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, ELF_RELOC *rpnt, +	Elf32_Sym *symtab, char *strtab) +{ +	int goof; +	int reloc_type; +	int symtab_index; +	char *symname; +	unsigned long *reloc_addr; +	unsigned long symbol_addr; -		if (symtab_index) { -			if (tpnt->libtype == program_interpreter && _dl_symbol(symname)) -				continue; +	reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset); +	reloc_type = ELF32_R_TYPE(rpnt->r_info); -			symbol_addr = (Elf32_Addr) _dl_find_hash(symname, xpnt->next, NULL, 1); +	if (reloc_type != R_CRIS_COPY) +		return 0; +	 +	symtab_index = ELF32_R_SYM(rpnt->r_info); +	symbol_addr = 0; +	symname = strtab + symtab[symtab_index].st_name; +	goof = 0; -			if (!symbol_addr) { -				_dl_dprintf(2, "%s: Can't resolv symbol '%s'\n", _dl_progname, symname); -				goof++; -			} -		} +	if (symtab_index) { +		symbol_addr = (unsigned long) _dl_find_hash(symname, scope, NULL, copyrel); -		if (!goof) { -#if defined(__SUPPORT_LD_DEBUG__) -			if (_dl_debug_move) -				_dl_dprintf(_dl_debug_file, "\n%s move %x bytes from %x to %x", -					strtab + symtab[symtab_index].st_name, -					symtab[symtab_index].st_size, -					symbol_addr, symtab[symtab_index].st_value); +		if (!symbol_addr) +			goof++; +	} + +	if (!goof) { +#if defined (__SUPPORT_LD_DEBUG__) +		if (_dl_debug_move) +			_dl_dprintf(_dl_debug_file, "\n%s move %x bytes from %x to %x", +				symname, symtab[symtab_index].st_size, symbol_addr, symtab[symtab_index].st_value);  #endif -			_dl_memcpy((char *) symtab[symtab_index].st_value, (char *) symbol_addr, -				symtab[symtab_index].st_size); -		} +			_dl_memcpy((char *) symtab[symtab_index].st_value, +				(char *) symbol_addr, symtab[symtab_index].st_size);  	}  	return goof;  } + +/* External interface to the generic part of the dynamic linker. */ + +int +_dl_parse_relocation_information(struct elf_resolve *tpnt, unsigned long rel_addr, +	unsigned long rel_size, int type) +{ +	/* Keep the compiler happy. */ +	(void) type; +	return _dl_parse(tpnt, tpnt->symbol_scope, rel_addr, rel_size, _dl_do_reloc); +} +void +_dl_parse_lazy_relocation_information(struct elf_resolve *tpnt, unsigned long rel_addr, +	unsigned long rel_size, int type) +{ +	/* Keep the compiler happy. */ +	(void) type; +	_dl_parse(tpnt, NULL, rel_addr, rel_size, _dl_do_lazy_reloc); +} + +int +_dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr, +	unsigned long rel_size, int type) +{ +	/* Keep the compiler happy. */ +	(void) type; +	return _dl_parse(xpnt->dyn, xpnt->next, rel_addr, rel_size, _dl_do_copy_reloc); +} | 
