mirror of
git://sourceware.org/git/glibc.git
synced 2024-11-21 01:12:26 +08:00
Implement IFUNC for PPC.
This commit is contained in:
parent
9fd76770c3
commit
77799d9d9b
22
ChangeLog
22
ChangeLog
@ -1,4 +1,24 @@
|
||||
2009-10-30 Ulrich Drepper <drepper@redhat.com>
|
||||
2009-07-30 Alan Modra <amodra@bigpond.net.au>
|
||||
|
||||
* elf/elf.h (R_PPC_NUM, R_PPC64_NUM): Delete unused and incorrect.
|
||||
(R_PPC_REL16*): Correct comments.
|
||||
(R_PPC_IRELATIVE, R_PPC64_IRELATIVE, R_PPC64_JMP_IREL): Define.
|
||||
(R_PPC64_REL16, R_PPC64_REL16_LO, R_PPC64_REL16_HI,
|
||||
R_PPC64_REL16_HA): Define.
|
||||
* sysdeps/powerpc/powerpc32/dl-irel.h: New file.
|
||||
* sysdeps/powerpc/powerpc64/dl-irel.h: New file.
|
||||
* sysdeps/powerpc/powerpc32/dl-machine.c (__elf_machine_fixup_plt):
|
||||
Delete unused "reloc" param.
|
||||
(__process_machine_rela): Handle R_PPC_IRELATIVE.
|
||||
* sysdeps/powerpc/powerpc32/dl-machine.h (__elf_machine_fixup_plt):
|
||||
Delete "reloc" param.
|
||||
(elf_machine_rela): Handle STT_GNU_IFUNC functions and
|
||||
R_PPC_IRELATIVE.
|
||||
* sysdeps/powerpc/powerpc64/dl-machine.h (resolve_ifunc): New function.
|
||||
(elf_machine_rela): Handle STT_GNU_IFUNC functions and new ifunc
|
||||
relocations.
|
||||
|
||||
d2009-10-30 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
[BZ #10315]
|
||||
* sysdeps/gnu/netinet/udp.h: Define UDP_CORK, UDP_ENCAP,
|
||||
|
23
elf/elf.h
23
elf/elf.h
@ -2041,9 +2041,6 @@ typedef Elf32_Addr Elf32_Conflict;
|
||||
#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */
|
||||
#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */
|
||||
|
||||
/* Keep this the last entry. */
|
||||
#define R_PPC_NUM 95
|
||||
|
||||
/* The remaining relocs are from the Embedded ELF ABI, and are not
|
||||
in the SVR4 ELF ABI. */
|
||||
#define R_PPC_EMB_NADDR32 101
|
||||
@ -2071,11 +2068,14 @@ typedef Elf32_Addr Elf32_Conflict;
|
||||
#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */
|
||||
#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */
|
||||
|
||||
/* GNU extension to support local ifunc. */
|
||||
#define R_PPC_IRELATIVE 248
|
||||
|
||||
/* GNU relocs used in PIC code sequences. */
|
||||
#define R_PPC_REL16 249 /* word32 (sym-.) */
|
||||
#define R_PPC_REL16_LO 250 /* half16 (sym-.)@l */
|
||||
#define R_PPC_REL16_HI 251 /* half16 (sym-.)@h */
|
||||
#define R_PPC_REL16_HA 252 /* half16 (sym-.)@ha */
|
||||
#define R_PPC_REL16 249 /* half16 (sym+add-.) */
|
||||
#define R_PPC_REL16_LO 250 /* half16 (sym+add-.)@l */
|
||||
#define R_PPC_REL16_HI 251 /* half16 (sym+add-.)@h */
|
||||
#define R_PPC_REL16_HA 252 /* half16 (sym+add-.)@ha */
|
||||
|
||||
/* This is a phony reloc to handle any old fashioned TOC16 references
|
||||
that may still be in object files. */
|
||||
@ -2197,8 +2197,13 @@ typedef Elf32_Addr Elf32_Conflict;
|
||||
#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */
|
||||
#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */
|
||||
|
||||
/* Keep this the last entry. */
|
||||
#define R_PPC64_NUM 107
|
||||
/* GNU extension to support local ifunc. */
|
||||
#define R_PPC64_JMP_IREL 247
|
||||
#define R_PPC64_IRELATIVE 248
|
||||
#define R_PPC64_REL16 249 /* half16 (sym+add-.) */
|
||||
#define R_PPC64_REL16_LO 250 /* half16 (sym+add-.)@l */
|
||||
#define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */
|
||||
#define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */
|
||||
|
||||
/* PowerPC64 specific values for the Dyn d_tag field. */
|
||||
#define DT_PPC64_GLINK (DT_LOPROC + 0)
|
||||
|
45
sysdeps/powerpc/powerpc32/dl-irel.h
Normal file
45
sysdeps/powerpc/powerpc32/dl-irel.h
Normal file
@ -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 */
|
@ -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;
|
||||
|
@ -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
|
||||
|
58
sysdeps/powerpc/powerpc64/dl-irel.h
Normal file
58
sysdeps/powerpc/powerpc64/dl-irel.h
Normal file
@ -0,0 +1,58 @@
|
||||
/* Machine-dependent ELF indirect relocation inline functions.
|
||||
PowerPC64 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
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Elf64_Addr fd_func;
|
||||
Elf64_Addr fd_toc;
|
||||
Elf64_Addr fd_aux;
|
||||
} Elf64_FuncDesc;
|
||||
|
||||
static inline void
|
||||
__attribute ((always_inline))
|
||||
elf_irela (const Elf64_Rela *reloc)
|
||||
{
|
||||
unsigned int r_type = ELF64_R_TYPE (reloc->r_info);
|
||||
|
||||
if (__builtin_expect (r_type == R_PPC64_IRELATIVE, 1))
|
||||
{
|
||||
Elf64_Addr *const reloc_addr = (void *) reloc->r_offset;
|
||||
Elf64_Addr value = ((Elf64_Addr (*) (void)) reloc->r_addend) ();
|
||||
*reloc_addr = value;
|
||||
}
|
||||
else if (__builtin_expect (r_type == R_PPC64_JMP_IREL, 1))
|
||||
{
|
||||
Elf64_Addr *const reloc_addr = (void *) reloc->r_offset;
|
||||
Elf64_Addr value = ((Elf64_Addr (*) (void)) reloc->r_addend) ();
|
||||
*(Elf64_FuncDesc *) reloc_addr = *(Elf64_FuncDesc *) value;
|
||||
}
|
||||
else
|
||||
__libc_fatal ("unexpected reloc type in static binary");
|
||||
}
|
||||
|
||||
#endif /* dl-irel.h */
|
@ -526,6 +526,29 @@ elf_machine_tprel (struct link_map *map,
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Call function at address VALUE (an OPD entry) to resolve ifunc relocs. */
|
||||
auto inline Elf64_Addr __attribute__ ((always_inline))
|
||||
resolve_ifunc (Elf64_Addr value,
|
||||
const struct link_map *map, const struct link_map *sym_map)
|
||||
{
|
||||
/* The function we are calling may not yet have its opd entry relocated. */
|
||||
Elf64_FuncDesc opd;
|
||||
if (map != sym_map
|
||||
#if !defined RTLD_BOOTSTRAP && defined SHARED
|
||||
/* Bootstrap map doesn't have l_relocated set for it. */
|
||||
&& sym_map != &GL(dl_rtld_map)
|
||||
#endif
|
||||
&& !sym_map->l_relocated)
|
||||
{
|
||||
Elf64_FuncDesc *func = (Elf64_FuncDesc *) value;
|
||||
opd.fd_func = func->fd_func + sym_map->l_addr;
|
||||
opd.fd_toc = func->fd_toc + sym_map->l_addr;
|
||||
opd.fd_aux = func->fd_aux;
|
||||
value = (Elf64_Addr) &opd;
|
||||
}
|
||||
return ((Elf64_Addr (*) (void)) value) ();
|
||||
}
|
||||
|
||||
/* Perform the relocation specified by RELOC and SYM (which is fully
|
||||
resolved). MAP is the object containing the reloc. */
|
||||
auto inline void __attribute__ ((always_inline))
|
||||
@ -550,11 +573,17 @@ elf_machine_rela (struct link_map *map,
|
||||
if (__builtin_expect (r_type == R_PPC64_NONE, 0))
|
||||
return;
|
||||
|
||||
/* We need SYM_MAP even in the absence of TLS, for elf_machine_fixup_plt. */
|
||||
/* We need SYM_MAP even in the absence of TLS, for elf_machine_fixup_plt
|
||||
and STT_GNU_IFUNC. */
|
||||
struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
|
||||
Elf64_Addr value = ((sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value)
|
||||
+ reloc->r_addend);
|
||||
|
||||
if (sym != NULL
|
||||
&& __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)
|
||||
&& __builtin_expect (sym->st_shndx != SHN_UNDEF, 1))
|
||||
value = resolve_ifunc (value, map, sym_map);
|
||||
|
||||
/* For relocs that don't edit code, return.
|
||||
For relocs that might edit instructions, break from the switch. */
|
||||
switch (r_type)
|
||||
@ -564,6 +593,14 @@ elf_machine_rela (struct link_map *map,
|
||||
*reloc_addr = value;
|
||||
return;
|
||||
|
||||
case R_PPC64_IRELATIVE:
|
||||
value = resolve_ifunc (value, map, sym_map);
|
||||
*reloc_addr = value;
|
||||
return;
|
||||
|
||||
case R_PPC64_JMP_IREL:
|
||||
value = resolve_ifunc (value, map, sym_map);
|
||||
/* Fall thru */
|
||||
case R_PPC64_JMP_SLOT:
|
||||
#ifdef RESOLVE_CONFLICT_FIND_MAP
|
||||
elf_machine_plt_conflict (reloc_addr, value);
|
||||
|
Loading…
Reference in New Issue
Block a user