diff options
Diffstat (limited to 'ldso/ldso/sparc/elfinterp.c')
| -rw-r--r-- | ldso/ldso/sparc/elfinterp.c | 116 |
1 files changed, 62 insertions, 54 deletions
diff --git a/ldso/ldso/sparc/elfinterp.c b/ldso/ldso/sparc/elfinterp.c index 9b425fcee..bb61be9eb 100644 --- a/ldso/ldso/sparc/elfinterp.c +++ b/ldso/ldso/sparc/elfinterp.c @@ -52,7 +52,6 @@ extern int _dl_linux_resolve(void); unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) { - int reloc_type; ELF_RELOC *this_reloc; char *strtab; ElfW(Sym) *symtab; @@ -70,25 +69,18 @@ _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) reloc_entry = (reloc_entry >> 10) - 0xc; this_reloc = (ELF_RELOC *)(rel_addr + reloc_entry); - reloc_type = ELF_R_TYPE(this_reloc->r_info); symtab_index = ELF_R_SYM(this_reloc->r_info); symtab = (ElfW(Sym) *)tpnt->dynamic_info[DT_SYMTAB]; strtab = (char *)tpnt->dynamic_info[DT_STRTAB]; symname = strtab + symtab[symtab_index].st_name; - if (unlikely(reloc_type != R_SPARC_JMP_SLOT)) { - _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n", - _dl_progname); - _dl_exit(1); - } - /* Address of the jump instruction to fix up. */ instr_addr = (this_reloc->r_offset + tpnt->loadaddr); got_addr = (char **)instr_addr; /* Get the address of the GOT entry */ - new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT); + new_addr = _dl_find_hash(symname, &_dl_loaded_modules->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, NULL); if (unlikely(!new_addr)) { _dl_dprintf(2, "%s: Can't resolve symbol '%s'\n", _dl_progname, symname); _dl_exit(1); @@ -107,17 +99,17 @@ _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) if (!_dl_debug_nofixups) #endif { - got_addr[1] = (char *) (0x03000000 | (((unsigned int) new_addr >> 10) & 0x3fffff)); - got_addr[2] = (char *) (0x81c06000 | ((unsigned int) new_addr & 0x3ff)); + got_addr[1] = (char *) (OPCODE_SETHI_G1 | (((unsigned int) new_addr >> 10) & 0x3fffff)); + got_addr[2] = (char *) (OPCODE_JMP_G1 | ((unsigned int) new_addr & 0x3ff)); } return (unsigned long)new_addr; } static int -_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope, +_dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size, - int (*reloc_fnc)(struct elf_resolve *tpnt, struct dyn_elf *scope, + int (*reloc_fnc)(struct elf_resolve *tpnt, struct r_scope_elem *scope, ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)) { unsigned int i; @@ -172,13 +164,14 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope, } static int -_dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, +_dl_do_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope, ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab) { int reloc_type; int symtab_index; char *symname; - ElfW(Sym) *sym; + struct elf_resolve *tls_tpnt = NULL; + struct symbol_ref sym_ref; ElfW(Addr) *reloc_addr; ElfW(Addr) symbol_addr; #if defined (__SUPPORT_LD_DEBUG__) @@ -188,22 +181,36 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, reloc_addr = (ElfW(Addr)*)(tpnt->loadaddr + (unsigned long)rpnt->r_offset); reloc_type = ELF_R_TYPE(rpnt->r_info); symtab_index = ELF_R_SYM(rpnt->r_info); - sym = &symtab[symtab_index]; + sym_ref.sym = &symtab[symtab_index]; + sym_ref.tpnt = NULL; symbol_addr = 0; - symname = strtab + sym->st_name; + symname = strtab + sym_ref.sym->st_name; if (symtab_index) { symbol_addr = (ElfW(Addr))_dl_find_hash(symname, scope, tpnt, - elf_machine_type_class(reloc_type)); + elf_machine_type_class(reloc_type), &sym_ref); /* * 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 (unlikely(!symbol_addr && ELF_ST_BIND(sym->st_info) != STB_WEAK)) { - _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname); - _dl_exit(1); + if (unlikely(!symbol_addr && (ELF_ST_TYPE(sym_ref.sym->st_info) != STT_TLS) + && (ELF_ST_BIND(sym_ref.sym->st_info) != STB_WEAK))) { + /* This may be non-fatal if called from dlopen. */ + return 1; + } + if (_dl_trace_prelink) { + _dl_debug_lookup (symname, tpnt, &symtab[symtab_index], + &sym_ref, elf_machine_type_class(reloc_type)); + } + tls_tpnt = sym_ref.tpnt; + } else { + /* Relocs against STN_UNDEF are usually treated as using a + * symbol value of zero, and using the module containing the + * reloc itself. */ + symbol_addr = sym_ref.sym->st_value; + tls_tpnt = tpnt; } #if defined (__SUPPORT_LD_DEBUG__) @@ -216,21 +223,6 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, case R_SPARC_NONE: break; -#if 0 /* these dont really seem to be useful */ - case R_SPARC_8: - *(char *) reloc_addr = symbol_addr; - break; - case R_SPARC_16: - *(short *) reloc_addr = symbol_addr; - break; - case R_SPARC_DISP8: - *(char *) reloc_addr = (symbol_addr) - (Elf32_Addr) reloc_addr; - break; - case R_SPARC_DISP16: - *(short *) reloc_addr = (symbol_addr) - (Elf32_Addr) reloc_addr; - break; -#endif - case R_SPARC_DISP32: *reloc_addr = symbol_addr - (unsigned int) reloc_addr; break; @@ -240,7 +232,7 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, symbol_addr = tpnt->loadaddr + rpnt->r_addend; else symbol_addr += rpnt->r_addend; - *reloc_addr = (*reloc_addr & ~0x3ff)|(symbol_addr & 0x3ff); + *reloc_addr = (*reloc_addr & ~0x3ff) | (symbol_addr & 0x3ff); break; case R_SPARC_GLOB_DAT: @@ -249,17 +241,8 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, break; case R_SPARC_JMP_SLOT: -/* -value = symbol_addr; -value += reloc->r_addend; -disp = value - reloc_addr; -reloc_addr[1] = OPCODE_JMP_G1 | (value & 0x3ff); -reloc_addr[0] = OPCODE_SETHI_G1 | (value >> 10); - reloc_addr[1] = OPCODE_JMP_G1 | ((symbol_addr-(Elf32_Addr)reloc_addr) & 0x3ff); - reloc_addr[0] = OPCODE_SETHI_G1 | ((symbol_addr-(Elf32_Addr)reloc_addr) >> 10); -*/ - reloc_addr[1] = 0x03000000 | ((symbol_addr >> 10) & 0x3fffff); - reloc_addr[2] = 0x81c06000 | (symbol_addr & 0x3ff); + reloc_addr[1] = OPCODE_SETHI_G1 | (( symbol_addr >> 10 ) & 0x3fffff); + reloc_addr[2] = OPCODE_JMP_G1 | ( symbol_addr & 0x3ff ); break; case R_SPARC_RELATIVE: @@ -285,16 +268,39 @@ reloc_addr[0] = OPCODE_SETHI_G1 | (value >> 10); if (_dl_debug_move) _dl_dprintf(_dl_debug_file, "\t%s move %d bytes from %x to %x\n", - symname, sym->st_size, + symname, sym_ref.sym->st_size, symbol_addr, reloc_addr); #endif _dl_memcpy((char *)reloc_addr, (char *)symbol_addr, - sym->st_size); - } else + sym_ref.sym->st_size); + } +#if defined (__SUPPORT_LD_DEBUG__) + else _dl_dprintf(_dl_debug_file, "no symbol_addr to copy !?\n"); +#endif + break; +#if defined USE_TLS && USE_TLS + case R_SPARC_TLS_DTPMOD32: + *reloc_addr = tls_tpnt->l_tls_modid; break; + + case R_SPARC_TLS_DTPOFF32: + /* During relocation all TLS symbols are defined and used. + * Therefore the offset is already correct. */ + *reloc_addr = sym_ref.sym->st_value + rpnt->r_addend; + break; + + case R_SPARC_TLS_TPOFF32: + /* The offset is negative, forward from the thread pointer. + * We know the offset of the object the symbol is contained in. + * It is a negative value which will be added to the + * thread pointer. */ + CHECK_STATIC_TLS ((struct link_map *) tls_tpnt); + *reloc_addr = sym_ref.sym->st_value - tls_tpnt->l_tls_offset + rpnt->r_addend; + break; +#endif default: return -1; /* Calls _dl_exit(1). */ } @@ -311,7 +317,7 @@ reloc_addr[0] = OPCODE_SETHI_G1 | (value >> 10); #undef __SPARC_LAZY_RELOC_WORKS #ifdef __SPARC_LAZY_RELOC_WORKS static int -_dl_do_lazy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, +_dl_do_lazy_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope, ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab) { int reloc_type; @@ -359,14 +365,16 @@ _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt, #ifdef __SPARC_LAZY_RELOC_WORKS (void)_dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc); #else - _dl_parse_relocation_information(rpnt, rel_addr, rel_size); + _dl_parse_relocation_information(rpnt, &_dl_loaded_modules->symbol_scope, + rel_addr, rel_size); #endif } int _dl_parse_relocation_information(struct dyn_elf *rpnt, + struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size) { - return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc); + return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size, _dl_do_reloc); } |
