diff options
Diffstat (limited to 'ldso')
-rw-r--r-- | ldso/ldso/dl-hash.c | 5 | ||||
-rw-r--r-- | ldso/ldso/mips/dl-sysdep.h | 18 | ||||
-rw-r--r-- | ldso/ldso/mips/elfinterp.c | 85 | ||||
-rw-r--r-- | ldso/ldso/mips/resolve.S | 51 |
4 files changed, 155 insertions, 4 deletions
diff --git a/ldso/ldso/dl-hash.c b/ldso/ldso/dl-hash.c index b44bd3a4b..a251aaff3 100644 --- a/ldso/ldso/dl-hash.c +++ b/ldso/ldso/dl-hash.c @@ -160,6 +160,11 @@ check_match (const ElfW(Sym) *sym, char *strtab, const char* undef_name, int typ /* undefined symbol itself */ return NULL; +#ifdef __mips__ + if (sym->st_shndx == SHN_UNDEF && !(sym->st_other & STO_MIPS_PLT)) + return NULL; +#endif + if (sym->st_value == 0) /* No value */ return NULL; diff --git a/ldso/ldso/mips/dl-sysdep.h b/ldso/ldso/mips/dl-sysdep.h index 728779250..8f303fba1 100644 --- a/ldso/ldso/mips/dl-sysdep.h +++ b/ldso/ldso/mips/dl-sysdep.h @@ -93,10 +93,11 @@ typedef struct #include <link.h> -#define ARCH_NUM 3 +#define ARCH_NUM 4 #define DT_MIPS_GOTSYM_IDX (DT_NUM + OS_NUM) #define DT_MIPS_LOCAL_GOTNO_IDX (DT_NUM + OS_NUM +1) #define DT_MIPS_SYMTABNO_IDX (DT_NUM + OS_NUM +2) +#define DT_MIPS_PLTGOT_IDX (DT_NUM + OS_NUM +3) #define ARCH_DYNAMIC_INFO(dpnt, dynamic, debug_addr) \ do { \ @@ -106,6 +107,8 @@ else if (dpnt->d_tag == DT_MIPS_LOCAL_GOTNO) \ dynamic[DT_MIPS_LOCAL_GOTNO_IDX] = dpnt->d_un.d_val; \ else if (dpnt->d_tag == DT_MIPS_SYMTABNO) \ dynamic[DT_MIPS_SYMTABNO_IDX] = dpnt->d_un.d_val; \ +else if (dpnt->d_tag == DT_MIPS_PLTGOT) \ + dynamic[DT_MIPS_PLTGOT_IDX] = dpnt->d_un.d_val; \ else if (dpnt->d_tag == DT_MIPS_RLD_MAP) \ *(ElfW(Addr) *)(dpnt->d_un.d_ptr) = (ElfW(Addr)) debug_addr; \ } while (0) @@ -114,6 +117,7 @@ else if (dpnt->d_tag == DT_MIPS_RLD_MAP) \ #define INIT_GOT(GOT_BASE,MODULE) \ do { \ unsigned long idx; \ + unsigned long *pltgot; \ \ /* Check if this is the dynamic linker itself */ \ if (MODULE->libtype == program_interpreter) \ @@ -123,6 +127,12 @@ do { \ GOT_BASE[0] = (unsigned long) _dl_runtime_resolve; \ GOT_BASE[1] = (unsigned long) MODULE; \ \ + pltgot = MODULE->dynamic_info[DT_MIPS_PLTGOT_IDX]; \ + if (pltgot) { \ + pltgot[0] = (unsigned long) _dl_runtime_pltresolve; \ + pltgot[1] = (unsigned long) MODULE; \ + } \ + \ /* Add load address displacement to all local GOT entries */ \ idx = 2; \ while (idx < MODULE->dynamic_info[DT_MIPS_LOCAL_GOTNO_IDX]) \ @@ -151,9 +161,9 @@ void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt, int lazy) #define OFFS_ALIGN (0x10000000000UL-0x1000) #endif /* O32 || N32 */ -#define elf_machine_type_class(type) ELF_RTYPE_CLASS_PLT -/* MIPS does not have COPY relocs */ -#define DL_NO_COPY_RELOCS +#define elf_machine_type_class(type) \ + ((((type) == R_MIPS_JUMP_SLOT) * ELF_RTYPE_CLASS_PLT) \ + | (((type) == R_MIPS_COPY) * ELF_RTYPE_CLASS_COPY)) #define OFFSET_GP_GOT 0x7ff0 diff --git a/ldso/ldso/mips/elfinterp.c b/ldso/ldso/mips/elfinterp.c index 1b03d9412..0ed2757b5 100644 --- a/ldso/ldso/mips/elfinterp.c +++ b/ldso/ldso/mips/elfinterp.c @@ -30,6 +30,7 @@ #include "ldso.h" extern int _dl_runtime_resolve(void); +extern int _dl_runtime_pltresolve(void); #define OFFSET_GP_GOT 0x7ff0 @@ -83,6 +84,61 @@ unsigned long __dl_runtime_resolve(unsigned long sym_index, return new_addr; } +unsigned long +__dl_runtime_pltresolve(struct elf_resolve *tpnt, int reloc_entry) +{ + int reloc_type; + ELF_RELOC *this_reloc; + char *strtab; + Elf32_Sym *symtab; + int symtab_index; + char *rel_addr; + char *new_addr; + char **got_addr; + unsigned long instr_addr; + char *symname; + + rel_addr = (char *)tpnt->dynamic_info[DT_JMPREL]; + this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry); + 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]; + strtab = (char *)tpnt->dynamic_info[DT_STRTAB]; + symname = strtab + symtab[symtab_index].st_name; + + /* Address of the jump instruction to fix up. */ + instr_addr = ((unsigned long)this_reloc->r_offset + + (unsigned long)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); + if (unlikely(!new_addr)) { + _dl_dprintf(2, "%s: can't resolve symbol '%s' in lib '%s'.\n", _dl_progname, symname, tpnt->libname); + _dl_exit(1); + } + +#if defined (__SUPPORT_LD_DEBUG__) + if ((unsigned long)got_addr < 0x40000000) { + if (_dl_debug_bindings) { + _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname); + if (_dl_debug_detail) + _dl_dprintf(_dl_debug_file, + "\n\tpatched: %x ==> %x @ %x", + *got_addr, new_addr, got_addr); + } + } + if (!_dl_debug_nofixups) { + *got_addr = new_addr; + } +#else + *got_addr = new_addr; +#endif + + return (unsigned long)new_addr; +} + void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size) { @@ -115,6 +171,7 @@ int _dl_parse_relocation_information(struct dyn_elf *xpnt, got = (unsigned long *) tpnt->dynamic_info[DT_PLTGOT]; for (i = 0; i < rel_size; i++, rpnt++) { + char *symname = NULL; reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset); reloc_type = ELF_R_TYPE(rpnt->r_info); @@ -128,6 +185,16 @@ int _dl_parse_relocation_information(struct dyn_elf *xpnt, old_val = *reloc_addr; #endif + if (reloc_type == R_MIPS_JUMP_SLOT || reloc_type == R_MIPS_COPY) { + symname = strtab + symtab[symtab_index].st_name; + symbol_addr = (unsigned long)_dl_find_hash(symname, + tpnt->symbol_scope, + tpnt, + elf_machine_type_class(reloc_type)); + if (unlikely(!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK)) + return 1; + } + switch (reloc_type) { #if _MIPS_SIM == _MIPS_SIM_ABI64 case (R_MIPS_64 << 8) | R_MIPS_REL32: @@ -148,6 +215,24 @@ int _dl_parse_relocation_information(struct dyn_elf *xpnt, *reloc_addr += (unsigned long) tpnt->loadaddr; } break; + case R_MIPS_JUMP_SLOT: + *reloc_addr = symbol_addr; + break; + case R_MIPS_COPY: + if (symbol_addr) { +#if defined (__SUPPORT_LD_DEBUG__) + if (_dl_debug_move) + _dl_dprintf(_dl_debug_file, + "\n%s move %d bytes from %x to %x", + symname, symtab[symtab_index].st_size, + symbol_addr, reloc_addr); +#endif + + _dl_memcpy((char *)reloc_addr, + (char *)symbol_addr, + symtab[symtab_index].st_size); + } + break; case R_MIPS_NONE: break; default: diff --git a/ldso/ldso/mips/resolve.S b/ldso/ldso/mips/resolve.S index f5d988a80..d7951a1b4 100644 --- a/ldso/ldso/mips/resolve.S +++ b/ldso/ldso/mips/resolve.S @@ -112,3 +112,54 @@ _dl_runtime_resolve: .end _dl_runtime_resolve .previous +/* Assembler veneer called from the PLT header code when using the + non-PIC ABI. + + Code in each PLT entry puts the caller's return address into t7 ($15), + the PLT entry index into t8 ($24), the address of _dl_runtime_pltresolve + into t9 ($25) and the address of .got.plt into gp ($28). __dl_runtime_pltresolve + needs a0 ($4) to hold the link map and a1 ($5) to hold the index into + .rel.plt (== PLT entry index * 4). */ + + .text + .align 2 + .globl _dl_runtime_pltresolve + .type _dl_runtime_pltresolve,@function + .ent _dl_runtime_pltresolve +_dl_runtime_pltresolve: + .frame $29, 40, $31 + .set noreorder + # Save arguments and sp value in stack. + subu $29, 40 + lw $10, 4($28) + # Modify t9 ($25) so as to point .cpload instruction. + addiu $25, 12 + # Compute GP. + .cpload $25 + .set reorder + + /* Store function arguments from registers to stack */ + sw $15, 36($29) + sw $4, 16($29) + sw $5, 20($29) + sw $6, 24($29) + sw $7, 28($29) + + /* Setup functions args and call __dl_runtime_pltresolve. */ + move $4, $10 + sll $5, $24, 3 + jal __dl_runtime_pltresolve + + /* Restore function arguments from stack to registers */ + lw $31, 36($29) + lw $4, 16($29) + lw $5, 20($29) + lw $6, 24($29) + lw $7, 28($29) + + /* Do a tail call to the original function */ + addiu $29, 40 + move $25, $2 + jr $25 + .end _dl_runtime_pltresolve + .previous |