diff options
author | Eric Andersen <andersen@codepoet.org> | 2002-05-02 13:36:53 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2002-05-02 13:36:53 +0000 |
commit | 4a5a81ac165c040935a8807a580db49d381dc443 (patch) | |
tree | 7fcd5458f95399731b537e1cfd22538ee2d03c19 /ldso/ldso/mips/elfinterp.c | |
parent | 776eae615326f6439734b05fa39c335bf2dc681b (diff) |
Patch from Steven J. Hill <sjhill@realitydiluted.com>:
I am very pleased to announce that the MIPS dynamic linker/loader
for uClibc is now working. It works on big and little endian
platforms.
A few minor changes were needed to avoid breaking ldd, and since this
makes some non-trivial changes, I have tested on x86, arm, and powerpc
to be sure thoese arches didn't get broken. Excellent work Steven!
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; } |