diff options
-rw-r--r-- | ldso/ldso/powerpc/elfinterp.c | 204 |
1 files changed, 87 insertions, 117 deletions
diff --git a/ldso/ldso/powerpc/elfinterp.c b/ldso/ldso/powerpc/elfinterp.c index 635296142..c930f717b 100644 --- a/ldso/ldso/powerpc/elfinterp.c +++ b/ldso/ldso/powerpc/elfinterp.c @@ -3,6 +3,7 @@ * * Copyright (C) 2001-2002 David A. Schleef * Copyright (C) 2003-2004 Erik Andersen + * Copyright (C) 2004 Joakim Tjernlund * * All rights reserved. * @@ -251,72 +252,7 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) return finaladdr; } -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, Elf32_Sym *symtab, char *strtab)) -{ - unsigned int i; - char *strtab; - Elf32_Sym *symtab; - ELF_RELOC *rpnt; - int symtab_index; - - /* Now parse the relocation information */ - rpnt = (ELF_RELOC *)(intptr_t) (rel_addr + tpnt->loadaddr); - rel_size = rel_size / sizeof(ELF_RELOC); - - symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); - strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); - - for (i = 0; i < rel_size; i++, rpnt++) { - int res; - - symtab_index = ELF32_R_SYM(rpnt->r_info); - - /* When the dynamic linker bootstrapped itself, it resolved some symbols. - Make sure we do not do them again */ - if (!symtab_index && tpnt->libtype == program_interpreter) - continue; - if (symtab_index && tpnt->libtype == program_interpreter && - _dl_symbol(strtab + symtab[symtab_index].st_name)) - continue; - -#if defined (__SUPPORT_LD_DEBUG__) - debug_sym(symtab,strtab,symtab_index); - debug_reloc(symtab,strtab,rpnt); -#endif - - res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab); - - if (res==0) continue; - - _dl_dprintf(2, "\n%s: ",_dl_progname); - - if (symtab_index) - _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name); - - if (res <0) - { - int reloc_type = ELF32_R_TYPE(rpnt->r_info); -#if defined (__SUPPORT_LD_DEBUG__) - _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type)); -#else - _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type); -#endif - _dl_exit(-res); - } - else if (res >0) - { - _dl_dprintf(2, "can't resolve symbol\n"); - return res; - } - } - return 0; -} - -static int +static inline int _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope, ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab) { @@ -325,6 +261,7 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope, char *symname; Elf32_Addr *reloc_addr; Elf32_Addr finaladdr; + struct dyn_elf *sym_scope; unsigned long symbol_addr; #if defined (__SUPPORT_LD_DEBUG__) @@ -336,13 +273,22 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope, *reloc_addr = tpnt->loadaddr + rpnt->r_addend; return 0; } - if (reloc_type == R_PPC_NONE || reloc_type == R_PPC_COPY) /* R_PPC_COPY is handled later */ + if (reloc_type == R_PPC_NONE) return 0; symtab_index = ELF32_R_SYM(rpnt->r_info); symname = strtab + symtab[symtab_index].st_name; - - symbol_addr = (unsigned long) _dl_find_hash(symname, scope, - (reloc_type == R_PPC_JMP_SLOT ? tpnt : NULL), symbolrel); +#if 0 + sym_scope = scope->dyn->symbol_scope; +#else + sym_scope = scope;/* Funny, this works too and appears to be much faster. */ +#endif + if (reloc_type == R_PPC_COPY) { + sym_scope = scope->next; + tpnt = NULL; /* To be or not to be ...*/ + } + symbol_addr = (unsigned long) _dl_find_hash(symname, sym_scope, + (reloc_type == R_PPC_JMP_SLOT ? tpnt : NULL), + (reloc_type == R_PPC_COPY ? copyrel : symbolrel)); /* * We want to allow undefined references to weak symbols - this might * have been intentional. We should not be linking local symbols @@ -398,7 +344,6 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope, break; } case R_PPC_COPY: - /* This does not work yet, R_PPC_COPY is handled later, see if statemet above */ if (symbol_addr) { #if defined (__SUPPORT_LD_DEBUG__) if(_dl_debug_move) @@ -423,7 +368,8 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope, { Elf32_Sword delta = finaladdr - (Elf32_Word)reloc_addr; if(delta<<6>>6 != delta){ - _dl_dprintf(2, "%s: symbol '%s' R_PPC_REL24 is out of range.\n\tCompile shared libraries with -fPIC!\n", + _dl_dprintf(2, "%s: symbol '%s' R_PPC_REL24 is out of range.\n\t" + "Compile shared libraries with -fPIC!\n", _dl_progname, symname); _dl_exit(1); } @@ -452,48 +398,6 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope, return 0; } -/* This is done as a separate step, because there are cases where - information is first copied and later initialized. This results in - the wrong information being copied. Someone at Sun was complaining about - a bug in the handling of _COPY by SVr4, and this may in fact be what he - was talking about. Sigh. */ -static int -_dl_do_copy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope, - ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab) -{ - int reloc_type; - int symtab_index; - unsigned long *reloc_addr; - unsigned long symbol_addr; - int goof = 0; - char *symname; - - reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset); - reloc_type = ELF32_R_TYPE(rpnt->r_info); - if (reloc_type != R_PPC_COPY) - return 0; - symtab_index = ELF32_R_SYM(rpnt->r_info); - symbol_addr = 0; - symname = strtab + symtab[symtab_index].st_name; - - if (symtab_index) { - symbol_addr = (unsigned long) _dl_find_hash(symname, scope, NULL, copyrel); - if (!symbol_addr) goof++; - } - if (!goof) { -#if defined (__SUPPORT_LD_DEBUG__) - if(_dl_debug_move) - _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x", - symname, symtab[symtab_index].st_size, - symbol_addr, symtab[symtab_index].st_value); -#endif - _dl_memcpy((char *) reloc_addr, - (char *) (symbol_addr + (unsigned long)rpnt->r_addend), symtab[symtab_index].st_size); - } - - return goof; -} - void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size, int type) { @@ -538,16 +442,82 @@ void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt, PPC_ISYNC; } +static inline 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, Elf32_Sym *symtab, char *strtab)) +{ + unsigned int i; + char *strtab; + Elf32_Sym *symtab; + ELF_RELOC *rpnt; + int symtab_index; + + /* Now parse the relocation information */ + rpnt = (ELF_RELOC *)(intptr_t) (rel_addr + tpnt->loadaddr); + rel_size = rel_size / sizeof(ELF_RELOC); + + symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr); + strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr); + + for (i = 0; i < rel_size; i++, rpnt++) { + int res; + + symtab_index = ELF32_R_SYM(rpnt->r_info); + + /* When the dynamic linker bootstrapped itself, it resolved some symbols. + Make sure we do not do them again */ + if (!symtab_index && tpnt->libtype == program_interpreter) + continue; + if (symtab_index && tpnt->libtype == program_interpreter && + _dl_symbol(strtab + symtab[symtab_index].st_name)) + continue; + +#if defined (__SUPPORT_LD_DEBUG__) + debug_sym(symtab,strtab,symtab_index); + debug_reloc(symtab,strtab,rpnt); +#endif + + res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab); + + if (res==0) continue; + + _dl_dprintf(2, "\n%s: ",_dl_progname); + + if (symtab_index) + _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name); + + if (res <0) + { + int reloc_type = ELF32_R_TYPE(rpnt->r_info); +#if defined (__SUPPORT_LD_DEBUG__) + _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type)); +#else + _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type); +#endif + _dl_exit(-res); + } + else if (res >0) + { + _dl_dprintf(2, "can't resolve symbol\n"); + return res; + } + } + return 0; +} + int _dl_parse_relocation_information(struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size, int type) { - return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc); + return _dl_parse(rpnt->dyn, rpnt, rel_addr, rel_size, _dl_do_reloc); } +/* Should be a static inline instead, but that conflicts with ld_elf.h */ int _dl_parse_copy_information(struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size, int type) { - return _dl_parse(rpnt->dyn, rpnt->next, rel_addr, rel_size, _dl_do_copy_reloc); + /* Not used! */ + return 0; } - |