diff options
author | Alan Modra <amodra@bigpond.net.au> | 2009-10-30 00:39:38 -0700 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2009-10-30 00:39:38 -0700 |
commit | 77799d9d9b3f9c937bd6de035b724b9b272c9227 (patch) | |
tree | 097d09d8ef5885e1e72e7368de69da986ce9c8db /sysdeps/powerpc/powerpc32 | |
parent | 9fd76770c304ac30a344150d6a56bd6f873b2be0 (diff) |
Implement IFUNC for PPC.
Diffstat (limited to 'sysdeps/powerpc/powerpc32')
-rw-r--r-- | sysdeps/powerpc/powerpc32/dl-irel.h | 45 | ||||
-rw-r--r-- | sysdeps/powerpc/powerpc32/dl-machine.c | 6 | ||||
-rw-r--r-- | sysdeps/powerpc/powerpc32/dl-machine.h | 8 |
3 files changed, 56 insertions, 3 deletions
diff --git a/sysdeps/powerpc/powerpc32/dl-irel.h b/sysdeps/powerpc/powerpc32/dl-irel.h new file mode 100644 index 0000000000..3f204cd7ae --- /dev/null +++ b/sysdeps/powerpc/powerpc32/dl-irel.h @@ -0,0 +1,45 @@ +/* Machine-dependent ELF indirect relocation inline functions. + PowerPC version. + Copyright (C) 2009 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _DL_IREL_H +#define _DL_IREL_H + +#include <stdio.h> +#include <unistd.h> + +#define ELF_MACHINE_IRELA 1 + +static inline void +__attribute ((always_inline)) +elf_irela (const Elf32_Rela *reloc) +{ + unsigned int r_type = ELF32_R_TYPE (reloc->r_info); + + if (__builtin_expect (r_type == R_PPC_IRELATIVE, 1)) + { + Elf32_Addr *const reloc_addr = (void *) reloc->r_offset; + Elf32_Addr value = ((Elf32_Addr (*) (void)) reloc->r_addend) (); + *reloc_addr = value; + } + else + __libc_fatal ("unexpected reloc type in static binary"); +} + +#endif /* dl-irel.h */ diff --git a/sysdeps/powerpc/powerpc32/dl-machine.c b/sysdeps/powerpc/powerpc32/dl-machine.c index 71540bd185..ee4c3e0c1c 100644 --- a/sysdeps/powerpc/powerpc32/dl-machine.c +++ b/sysdeps/powerpc/powerpc32/dl-machine.c @@ -337,7 +337,7 @@ __elf_machine_runtime_setup (struct link_map *map, int lazy, int profile) } Elf32_Addr -__elf_machine_fixup_plt (struct link_map *map, const Elf32_Rela *reloc, +__elf_machine_fixup_plt (struct link_map *map, Elf32_Addr *reloc_addr, Elf32_Addr finaladdr) { Elf32_Sword delta = finaladdr - (Elf32_Word) reloc_addr; @@ -430,6 +430,10 @@ __process_machine_rela (struct link_map *map, *reloc_addr = finaladdr; return; + case R_PPC_IRELATIVE: + *reloc_addr = ((Elf32_Addr (*) (void)) finaladdr) (); + return; + case R_PPC_UADDR32: ((char *) reloc_addr)[0] = finaladdr >> 24; ((char *) reloc_addr)[1] = finaladdr >> 16; diff --git a/sysdeps/powerpc/powerpc32/dl-machine.h b/sysdeps/powerpc/powerpc32/dl-machine.h index a50ffdd1c2..6f8d0f506e 100644 --- a/sysdeps/powerpc/powerpc32/dl-machine.h +++ b/sysdeps/powerpc/powerpc32/dl-machine.h @@ -226,7 +226,6 @@ elf_machine_runtime_setup (struct link_map *map, /* Change the PLT entry whose reloc is 'reloc' to call the actual routine. */ extern Elf32_Addr __elf_machine_fixup_plt (struct link_map *map, - const Elf32_Rela *reloc, Elf32_Addr *reloc_addr, Elf32_Addr finaladdr); @@ -237,7 +236,7 @@ elf_machine_fixup_plt (struct link_map *map, lookup_t t, { if (map->l_info[DT_PPC(GOT)] == 0) /* Handle old style PLT. */ - return __elf_machine_fixup_plt (map, reloc, reloc_addr, finaladdr); + return __elf_machine_fixup_plt (map, reloc_addr, finaladdr); *reloc_addr = finaladdr; return finaladdr; @@ -317,6 +316,11 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc, value = reloc->r_addend; #endif + if (sym != NULL + && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0) + && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1)) + value = ((Elf32_Addr (*) (void)) value) (); + /* A small amount of code is duplicated here for speed. In libc, more than 90% of the relocs are R_PPC_RELATIVE; in the X11 shared libraries, 60% are R_PPC_RELATIVE, 24% are R_PPC_GLOB_DAT or |