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); +} |