diff options
-rw-r--r-- | ldso/ldso/m68k/elfinterp.c | 326 | ||||
-rw-r--r-- | ldso/ldso/m68k/resolve.S | 24 |
2 files changed, 208 insertions, 142 deletions
diff --git a/ldso/ldso/m68k/elfinterp.c b/ldso/ldso/m68k/elfinterp.c index 80fa1c9ec..204e0e93a 100644 --- a/ldso/ldso/m68k/elfinterp.c +++ b/ldso/ldso/m68k/elfinterp.c @@ -50,20 +50,20 @@ _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) int reloc_type; ELF_RELOC *this_reloc; char *strtab; - Elf32_Sym *symtab; + ElfW(Sym) *symtab; int symtab_index; - ELF_RELOC *rel_addr; + char *rel_addr; char *new_addr; char **got_addr; - unsigned int instr_addr; + ElfW(Addr) instr_addr; char *symname; - rel_addr = (ELF_RELOC *)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); + rel_addr = (char *)tpnt->dynamic_info[DT_JMPREL]; + 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 = (Elf32_Sym *)(intptr_t)tpnt->dynamic_info[DT_SYMTAB]; + symtab = (ElfW(Sym) *)tpnt->dynamic_info[DT_SYMTAB]; strtab = (char *)tpnt->dynamic_info[DT_STRTAB]; symname = strtab + symtab[symtab_index].st_name; @@ -74,7 +74,7 @@ _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) } /* Address of the jump instruction to fix up. */ - instr_addr = ((int)this_reloc->r_offset + (int)tpnt->loadaddr); + instr_addr = (this_reloc->r_offset + tpnt->loadaddr); got_addr = (char **)instr_addr; /* Get the address of the GOT entry. */ @@ -90,159 +90,223 @@ _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname); if (_dl_debug_detail) _dl_dprintf(_dl_debug_file, - "\n\tpatched: %x ==> %x @ %x", + "\tpatched: %x ==> %x @ %x\n", *got_addr, new_addr, got_addr); } } - if (!_dl_debug_nofixups) { - *got_addr = new_addr; - } -#else - *got_addr = new_addr; + if (!_dl_debug_nofixups) #endif + *got_addr = new_addr; - return (unsigned int)new_addr; + return (unsigned int)new_addr; } -void -_dl_parse_lazy_relocation_information(struct dyn_elf *arg_rpnt, - unsigned long rel_addr, unsigned long rel_size) +static int +_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope, + unsigned long rel_addr, unsigned long rel_size, + int (*reloc_fnc)(struct elf_resolve *tpnt, struct dyn_elf *scope, + ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)) { - int i; + unsigned int i; char *strtab; - int reloc_type; + ElfW(Sym) *symtab; + ELF_RELOC *rpnt; int symtab_index; - Elf32_Sym *symtab; - Elf32_Rela *rpnt; - unsigned int *reloc_addr; - struct elf_resolve *tpnt = arg_rpnt->dyn; - /* Now parse the relocation information. */ - rpnt = (Elf32_Rela *)rel_addr; - rel_size = rel_size / sizeof (Elf32_Rela); + /* Parse the relocation information. */ + rpnt = (ELF_RELOC *)rel_addr; + rel_size /= sizeof(ELF_RELOC); - symtab = (Elf32_Sym *)tpnt->dynamic_info[DT_SYMTAB]; + symtab = (ElfW(Sym) *)tpnt->dynamic_info[DT_SYMTAB]; strtab = (char *)tpnt->dynamic_info[DT_STRTAB]; for (i = 0; i < rel_size; i++, rpnt++) { - reloc_addr = (int *) (tpnt->loadaddr + (int) rpnt->r_offset); - reloc_type = ELF32_R_TYPE (rpnt->r_info); - symtab_index = ELF32_R_SYM (rpnt->r_info); + int res; + + symtab_index = ELF_R_SYM(rpnt->r_info); + + debug_sym(symtab, strtab, symtab_index); + debug_reloc(symtab, strtab, rpnt); + + res = reloc_fnc(tpnt, scope, rpnt, symtab, strtab); + + if (res == 0) + continue; - switch (reloc_type) - { + _dl_dprintf(2, "\n%s: ", _dl_progname); + + if (symtab_index) + _dl_dprintf(2, "symbol '%s': ", + strtab + symtab[symtab_index].st_name); + + if (unlikely(res < 0)) { + int reloc_type = ELF_R_TYPE(rpnt->r_info); + + _dl_dprintf(2, "can't handle reloc type " +#if defined (__SUPPORT_LD_DEBUG__) + "%s\n", _dl_reltypes(reloc_type)); +#else + "%x\n", reloc_type); +#endif + _dl_exit(-res); + } else if (unlikely(res > 0)) { + _dl_dprintf(2, "can't resolve symbol\n"); + return res; + } + } + + return 0; +} + +static int +_dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, + ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab) +{ + int reloc_type; + int symtab_index; + char *symname; + ElfW(Sym) *sym; + ElfW(Addr) *reloc_addr; + ElfW(Addr) symbol_addr; +#if defined (__SUPPORT_LD_DEBUG__) + ElfW(Addr) old_val; +#endif + + 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]; + symbol_addr = 0; + symname = strtab + sym->st_name; + + if (symtab_index) { + symbol_addr = (ElfW(Addr))_dl_find_hash(symname, scope, tpnt, + elf_machine_type_class(reloc_type)); + /* + * 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 defined (__SUPPORT_LD_DEBUG__) + old_val = *reloc_addr; +#endif + + switch (reloc_type) { case R_68K_NONE: break; + case R_68K_8: + *(char *) reloc_addr = symbol_addr + rpnt->r_addend; + break; + case R_68K_16: + *(short *) reloc_addr = symbol_addr + rpnt->r_addend; + break; + case R_68K_32: + *reloc_addr = symbol_addr + rpnt->r_addend; + break; + case R_68K_PC8: + *(char *) reloc_addr = (symbol_addr + rpnt->r_addend + - (unsigned int) reloc_addr); + break; + case R_68K_PC16: + *(short *) reloc_addr = (symbol_addr + rpnt->r_addend + - (unsigned int) reloc_addr); + break; + case R_68K_PC32: + *reloc_addr = (symbol_addr + rpnt->r_addend + - (unsigned int) reloc_addr); + break; + case R_68K_GLOB_DAT: case R_68K_JMP_SLOT: - *reloc_addr += (unsigned int) tpnt->loadaddr; - break; + *reloc_addr = symbol_addr; + break; + case R_68K_RELATIVE: + *reloc_addr = ((unsigned int) tpnt->loadaddr + /* Compatibility kludge. */ + + (rpnt->r_addend ? : *reloc_addr)); + break; + case R_68K_COPY: + _dl_memcpy ((void *) reloc_addr, + (void *) symbol_addr, + symtab[symtab_index].st_size); + break; + default: - _dl_dprintf (2, "%s: (LAZY) can't handle reloc type ", _dl_progname); + return -1; /* Calls _dl_exit(1). */ + } + #if defined (__SUPPORT_LD_DEBUG__) - _dl_dprintf (2, "%s ", _dl_reltypes_tab[reloc_type]); + if (_dl_debug_reloc && _dl_debug_detail) + _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x\n", + old_val, *reloc_addr, reloc_addr); #endif - if (symtab_index) - _dl_dprintf (2, "'%s'", strtab + symtab[symtab_index].st_name); - _dl_dprintf (2, "\n"); - _dl_exit (1); - } - } + + return 0; } -int -_dl_parse_relocation_information(struct dyn_elf *arg_rpnt, - unsigned long rel_addr, unsigned long rel_size) +#if 0 +static int +_dl_do_lazy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, + ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab) { - int i; - char *strtab; int reloc_type; - int goof = 0; - Elf32_Sym *symtab; - Elf32_Rela *rpnt; - unsigned int *reloc_addr; - unsigned int symbol_addr; int symtab_index; - struct elf_resolve *tpnt = arg_rpnt->dyn; - /* Now parse the relocation information */ + ElfW(Addr) *reloc_addr; +#if defined (__SUPPORT_LD_DEBUG__) + ElfW(Addr) old_val; +#endif - rpnt = (Elf32_Rela *)rel_addr; - rel_size = rel_size / sizeof (Elf32_Rela); + (void)scope; + symtab_index = ELF_R_SYM(rpnt->r_info); + (void)strtab; - symtab = (Elf32_Sym *)tpnt->dynamic_info[DT_SYMTAB]; - strtab = (char *)tpnt->dynamic_info[DT_STRTAB]; + reloc_addr = (ElfW(Addr)*)(tpnt->loadaddr + rpnt->r_offset); + reloc_type = ELF_R_TYPE(rpnt->r_info); - for (i = 0; i < rel_size; i++, rpnt++) { - reloc_addr = (int *) (tpnt->loadaddr + (int) 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) { - symbol_addr = (unsigned int) - _dl_find_hash (strtab + symtab[symtab_index].st_name, - tpnt->symbol_scope, tpnt, - elf_machine_type_class(reloc_type)); - - /* 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 (!symbol_addr - && ELF32_ST_BIND (symtab[symtab_index].st_info) != STB_WEAK) - { - _dl_dprintf (2, "%s: can't resolve symbol '%s'\n", - _dl_progname, strtab + symtab[symtab_index].st_name); - _dl_exit (1); - } - } - switch (reloc_type) - { - case R_68K_NONE: - break; - case R_68K_8: - *(char *) reloc_addr = symbol_addr + rpnt->r_addend; - break; - case R_68K_16: - *(short *) reloc_addr = symbol_addr + rpnt->r_addend; - break; - case R_68K_32: - *reloc_addr = symbol_addr + rpnt->r_addend; - break; - case R_68K_PC8: - *(char *) reloc_addr = (symbol_addr + rpnt->r_addend - - (unsigned int) reloc_addr); - break; - case R_68K_PC16: - *(short *) reloc_addr = (symbol_addr + rpnt->r_addend - - (unsigned int) reloc_addr); - break; - case R_68K_PC32: - *reloc_addr = (symbol_addr + rpnt->r_addend - - (unsigned int) reloc_addr); - break; - case R_68K_GLOB_DAT: - case R_68K_JMP_SLOT: - *reloc_addr = symbol_addr; - break; - case R_68K_RELATIVE: - *reloc_addr = ((unsigned int) tpnt->loadaddr - /* Compatibility kludge. */ - + (rpnt->r_addend ? : *reloc_addr)); - break; - case R_68K_COPY: - _dl_memcpy ((void *) reloc_addr, - (void *) symbol_addr, - symtab[symtab_index].st_size); - break; - default: - _dl_dprintf (2, "%s: can't handle reloc type ", _dl_progname); #if defined (__SUPPORT_LD_DEBUG__) - _dl_dprintf (2, "%s ", _dl_reltypes_tab[reloc_type]); + old_val = *reloc_addr; #endif - if (symtab_index) - _dl_dprintf (2, "'%s'", strtab + symtab[symtab_index].st_name); - _dl_dprintf (2, "\n"); - _dl_exit (1); - } + + switch (reloc_type) { + case R_68K_NONE: + break; + case R_68K_JMP_SLOT: + *reloc_addr += (unsigned int) tpnt->loadaddr; + break; + default: + _dl_exit(1); } - return goof; + +#if defined (__SUPPORT_LD_DEBUG__) + if (_dl_debug_reloc && _dl_debug_detail) + _dl_dprintf(_dl_debug_file, "\tpatched_lazy: %x ==> %x @ %x\n", + old_val, *reloc_addr, reloc_addr); +#endif + + return 0; +} +#endif + +void +_dl_parse_lazy_relocation_information(struct dyn_elf *rpnt, + unsigned long rel_addr, + unsigned long rel_size) +{ + _dl_parse_relocation_information(rpnt, rel_addr, rel_size); +/* + (void)_dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc); +*/ +} + +int +_dl_parse_relocation_information(struct dyn_elf *rpnt, + unsigned long rel_addr, + unsigned long rel_size) +{ + return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc); } diff --git a/ldso/ldso/m68k/resolve.S b/ldso/ldso/m68k/resolve.S index 9de314dfb..d9a2929d6 100644 --- a/ldso/ldso/m68k/resolve.S +++ b/ldso/ldso/m68k/resolve.S @@ -8,14 +8,16 @@ .globl _dl_linux_resolve .type _dl_linux_resolve,@function _dl_linux_resolve: - moveml %a0/%a1,%sp@- -#ifdef __PIC__ - bsrl _dl_linux_resolver@PLTPC -#else - jbsr _dl_linux_resolver -#endif - moveml %sp@+,%a0/%a1 - addql #8,%sp - jmp @(%d0) -.LFE2: - .size _dl_linux_resolve,.LFE2-_dl_linux_resolve + # Save %a0 (struct return address) and %a1. + move.l %a0, -(%sp) + move.l %a1, -(%sp) + # Call the real address resolver. + jbsr _dl_linux_resolver + # Restore register %a0 and %a1. + move.l (%sp)+, %a1 + move.l (%sp)+, %a0 + # Pop parameters + addq.l #8, %sp + # Call real function. + jmp (%d0) +.size _dl_linux_resolve,.-_dl_linux_resolve |