diff options
Diffstat (limited to 'sysdeps/powerpc')
-rw-r--r-- | sysdeps/powerpc/powerpc32/dl-machine.h | 1 | ||||
-rw-r--r-- | sysdeps/powerpc/powerpc64/dl-machine.c | 24 | ||||
-rw-r--r-- | sysdeps/powerpc/powerpc64/dl-machine.h | 54 |
3 files changed, 53 insertions, 26 deletions
diff --git a/sysdeps/powerpc/powerpc32/dl-machine.h b/sysdeps/powerpc/powerpc32/dl-machine.h index 28eb50f92d..1f8437ed9c 100644 --- a/sysdeps/powerpc/powerpc32/dl-machine.h +++ b/sysdeps/powerpc/powerpc32/dl-machine.h @@ -235,6 +235,7 @@ extern Elf32_Addr __elf_machine_fixup_plt (struct link_map *map, static inline Elf32_Addr elf_machine_fixup_plt (struct link_map *map, lookup_t t, + const ElfW(Sym) *refsym, const ElfW(Sym) *sym, const Elf32_Rela *reloc, Elf32_Addr *reloc_addr, Elf64_Addr finaladdr) { diff --git a/sysdeps/powerpc/powerpc64/dl-machine.c b/sysdeps/powerpc/powerpc64/dl-machine.c index 0eccc6621a..2cfd43b21b 100644 --- a/sysdeps/powerpc/powerpc64/dl-machine.c +++ b/sysdeps/powerpc/powerpc64/dl-machine.c @@ -24,11 +24,11 @@ void _dl_reloc_overflow (struct link_map *map, - const char *name, - Elf64_Addr *const reloc_addr, - const Elf64_Sym *refsym) + const char *name, + Elf64_Addr *const reloc_addr, + const Elf64_Sym *refsym) { - char buffer[128]; + char buffer[1024]; char *t; t = stpcpy (buffer, name); t = stpcpy (t, " reloc at 0x"); @@ -45,3 +45,19 @@ _dl_reloc_overflow (struct link_map *map, t = stpcpy (t, " out of range"); _dl_signal_error (0, map->l_name, NULL, buffer); } + +#if _CALL_ELF == 2 +void +_dl_error_localentry (struct link_map *map, const Elf64_Sym *refsym) +{ + char buffer[1024]; + char *t; + const char *strtab; + + strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]); + t = stpcpy (buffer, "expected localentry:0 `"); + t = stpcpy (t, strtab + refsym->st_name); + t = stpcpy (t, "'"); + _dl_signal_error (0, map->l_name, NULL, buffer); +} +#endif diff --git a/sysdeps/powerpc/powerpc64/dl-machine.h b/sysdeps/powerpc/powerpc64/dl-machine.h index 6391b3a558..aeb91b8f69 100644 --- a/sysdeps/powerpc/powerpc64/dl-machine.h +++ b/sysdeps/powerpc/powerpc64/dl-machine.h @@ -440,20 +440,30 @@ elf_machine_runtime_setup (struct link_map *map, int lazy, int profile) } #if _CALL_ELF == 2 -/* If the PLT entry whose reloc is 'reloc' resolves to a function in - the same object, return the target function's local entry point - offset if usable. */ +extern void attribute_hidden _dl_error_localentry (struct link_map *map, + const Elf64_Sym *refsym); + +/* If the PLT entry resolves to a function in the same object, return + the target function's local entry point offset if usable. */ static inline Elf64_Addr __attribute__ ((always_inline)) ppc64_local_entry_offset (struct link_map *map, lookup_t sym_map, - const Elf64_Rela *reloc) + const ElfW(Sym) *refsym, const ElfW(Sym) *sym) { - const Elf64_Sym *symtab; - const Elf64_Sym *sym; - /* If the target function is in a different object, we cannot use the local entry point. */ if (sym_map != map) - return 0; + { + /* Check that optimized plt call stubs for localentry:0 functions + are not being satisfied by a non-zero localentry symbol. */ + if (map->l_info[DT_PPC64(OPT)] + && (map->l_info[DT_PPC64(OPT)]->d_un.d_val & PPC64_OPT_LOCALENTRY) != 0 + && refsym->st_info == ELFW(ST_INFO) (STB_GLOBAL, STT_FUNC) + && (STO_PPC64_LOCAL_MASK & refsym->st_other) == 0 + && (STO_PPC64_LOCAL_MASK & sym->st_other) != 0) + _dl_error_localentry (map, refsym); + + return 0; + } /* If the linker inserted multiple TOCs, we cannot use the local entry point. */ @@ -461,16 +471,13 @@ ppc64_local_entry_offset (struct link_map *map, lookup_t sym_map, && (map->l_info[DT_PPC64(OPT)]->d_un.d_val & PPC64_OPT_MULTI_TOC)) return 0; - /* Otherwise, we can use the local entry point. Retrieve its offset - from the symbol's ELF st_other field. */ - symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]); - sym = &symtab[ELFW(R_SYM) (reloc->r_info)]; - /* If the target function is an ifunc then the local entry offset is for the resolver, not the final destination. */ if (__builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)) return 0; + /* Otherwise, we can use the local entry point. Retrieve its offset + from the symbol's ELF st_other field. */ return PPC64_LOCAL_ENTRY_OFFSET (sym->st_other); } #endif @@ -479,6 +486,7 @@ ppc64_local_entry_offset (struct link_map *map, lookup_t sym_map, routine. */ static inline Elf64_Addr __attribute__ ((always_inline)) elf_machine_fixup_plt (struct link_map *map, lookup_t sym_map, + const ElfW(Sym) *refsym, const ElfW(Sym) *sym, const Elf64_Rela *reloc, Elf64_Addr *reloc_addr, Elf64_Addr finaladdr) { @@ -534,7 +542,7 @@ elf_machine_fixup_plt (struct link_map *map, lookup_t sym_map, PPC_DCBST (&plt->fd_func); PPC_ISYNC; #else - finaladdr += ppc64_local_entry_offset (map, sym_map, reloc); + finaladdr += ppc64_local_entry_offset (map, sym_map, refsym, sym); *reloc_addr = finaladdr; #endif @@ -543,6 +551,7 @@ elf_machine_fixup_plt (struct link_map *map, lookup_t sym_map, static inline void __attribute__ ((always_inline)) elf_machine_plt_conflict (struct link_map *map, lookup_t sym_map, + const ElfW(Sym) *refsym, const ElfW(Sym) *sym, const Elf64_Rela *reloc, Elf64_Addr *reloc_addr, Elf64_Addr finaladdr) { @@ -565,7 +574,7 @@ elf_machine_plt_conflict (struct link_map *map, lookup_t sym_map, PPC_DCBST (&plt->fd_toc); PPC_SYNC; #else - finaladdr += ppc64_local_entry_offset (map, sym_map, reloc); + finaladdr += ppc64_local_entry_offset (map, sym_map, refsym, sym); *reloc_addr = finaladdr; #endif } @@ -604,11 +613,10 @@ elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc, #define dont_expect(X) __builtin_expect ((X), 0) -extern void _dl_reloc_overflow (struct link_map *map, - const char *name, - Elf64_Addr *const reloc_addr, - const Elf64_Sym *refsym) - attribute_hidden; +extern void attribute_hidden _dl_reloc_overflow (struct link_map *map, + const char *name, + Elf64_Addr *const reloc_addr, + const Elf64_Sym *refsym); auto inline void __attribute__ ((always_inline)) elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc, @@ -728,9 +736,11 @@ elf_machine_rela (struct link_map *map, /* Fall thru */ case R_PPC64_JMP_SLOT: #ifdef RESOLVE_CONFLICT_FIND_MAP - elf_machine_plt_conflict (map, sym_map, reloc, reloc_addr, value); + elf_machine_plt_conflict (map, sym_map, refsym, sym, + reloc, reloc_addr, value); #else - elf_machine_fixup_plt (map, sym_map, reloc, reloc_addr, value); + elf_machine_fixup_plt (map, sym_map, refsym, sym, + reloc, reloc_addr, value); #endif return; |