summaryrefslogtreecommitdiff
path: root/ldso/ldso/mips/elfinterp.c
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2002-05-02 13:36:53 +0000
committerEric Andersen <andersen@codepoet.org>2002-05-02 13:36:53 +0000
commit4a5a81ac165c040935a8807a580db49d381dc443 (patch)
tree7fcd5458f95399731b537e1cfd22538ee2d03c19 /ldso/ldso/mips/elfinterp.c
parent776eae615326f6439734b05fa39c335bf2dc681b (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.c105
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;
}