diff options
Diffstat (limited to 'ldso/ldso/mips/elfinterp.c')
-rw-r--r-- | ldso/ldso/mips/elfinterp.c | 105 |
1 files changed, 100 insertions, 5 deletions
diff --git a/ldso/ldso/mips/elfinterp.c b/ldso/ldso/mips/elfinterp.c index c38a7ffa2..e6c3781b8 100644 --- a/ldso/ldso/mips/elfinterp.c +++ b/ldso/ldso/mips/elfinterp.c @@ -1,6 +1,7 @@ +/* vi: set sw=4 ts=4: */ + /* Run an ELF binary on a linux system. - Copyright (C) 1993, Eric Youngdale. Copyright (C) 2002, Steven J. Hill (sjhill@realitydiluted.com) This program is free software; you can redistribute it and/or modify @@ -32,18 +33,112 @@ extern int _dl_linux_resolve(void); -void _dl_init_got(unsigned long *got, struct elf_resolve *tpnt) +#define OFFSET_GP_GOT 0x7ff0 + +unsigned long _dl_linux_resolver(unsigned long sym_index, + unsigned long old_gpreg) { + unsigned long *got = (unsigned long *) (old_gpreg - OFFSET_GP_GOT); + struct elf_resolve *tpnt = (struct elf_resolve *) got[1]; + Elf32_Sym *sym; + char *strtab; + unsigned long local_gotno; + unsigned long gotsym; + unsigned long value; + + gotsym = tpnt->mips_gotsym; + local_gotno = tpnt->mips_local_gotno; + + sym = ((Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr)) + + sym_index; + + strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); + + value = (unsigned long) _dl_find_hash(strtab + sym->st_name, + tpnt->symbol_scope, tpnt, 1); + + *(got + local_gotno + sym_index - gotsym) = value; + +#ifdef DL_DEBUG + _dl_dprintf(2, "---RESOLVER---\n"); + _dl_dprintf(2, "SYMTAB INDEX: %i\n", sym_index); + _dl_dprintf(2, " GOTSYM: %i\n", gotsym); + _dl_dprintf(2, " LOCAL GOTNO: %i\n", local_gotno); + _dl_dprintf(2, " VALUE: %x\n", value); + _dl_dprintf(2, " SYMBOL: %s\n\n", strtab + sym->st_name); +#endif + + return value; +} + +void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt, + unsigned long rel_addr, unsigned long rel_size, int type) +{ + /* Nothing to do */ return; } -unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) +int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr, + unsigned long rel_size, int type) { + /* Nothing to do */ return 0; } - + int _dl_parse_relocation_information(struct elf_resolve *tpnt, unsigned long rel_addr, unsigned long rel_size, int type) { - return 1; + Elf32_Sym *symtab; + Elf32_Rel *rpnt; + char *strtab; + unsigned long *got; + unsigned long *reloc_addr; + unsigned long symbol_addr; + int i, reloc_type, symtab_index; + + /* Now parse the relocation information */ + rel_size = rel_size / sizeof(Elf32_Rel); + rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr); + + symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); + strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); + got = (unsigned long *) (tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr); + + for (i = 0; i < rel_size; i++, rpnt++) { + reloc_addr = (unsigned long *) (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; + + if (!symtab_index && tpnt->libtype == program_interpreter) + continue; + + switch (reloc_type) { + case R_MIPS_REL32: + if (symtab_index) { + if (symtab_index < tpnt->mips_gotsym) + *reloc_addr += + symtab[symtab_index].st_value + + (unsigned long) tpnt->loadaddr; + else { + *reloc_addr += got[symtab_index + tpnt->mips_local_gotno - + tpnt->mips_gotsym]; + } + } + else { + *reloc_addr += (unsigned long) tpnt->loadaddr; + } + break; + case R_MIPS_NONE: + break; + default: + _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname); + if (symtab_index) + _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name); + _dl_exit(1); + }; + + }; + return 0; } |