mirror of
https://sourceware.org/git/glibc.git
synced 2025-07-30 22:43:12 +03:00
PowerPC64 ELFv2 ABI 2/6: Remove function descriptors
This patch adds support for the ELFv2 ABI feature to remove function descriptors. See this GCC patch for in-depth discussion: http://gcc.gnu.org/ml/gcc-patches/2013-11/msg01141.html This mostly involves two types of changes: updating assembler source files to the new logic, and updating the dynamic loader. After the refactoring in the previous patch, most of the assembler source changes can be handled simply by providing ELFv2 versions of the macros in sysdep.h. One somewhat non-obvious change is in __GI__setjmp: this used to "fall through" to the immediately following __setjmp ENTRY point. This is no longer safe in the ELFv2 since ENTRY defines both a global and a local entry point, and you cannot simply fall through to a global entry point as it requires r12 to be set up. Also, makecontext needs to be updated to set up registers according to the new ABI for calling into the context's start routine. The dynamic linker changes mostly consist of removing special code to handle function descriptors. We also need to support the new PLT and glink format used by the the ELFv2 linker, see: https://sourceware.org/ml/binutils/2013-10/msg00376.html In addition, the dynamic linker now verifies that the dynamic libraries it loads match its own ABI. The hack in VDSO_IFUNC_RET to "synthesize" a function descriptor for vDSO routines is also no longer necessary for ELFv2.
This commit is contained in:
committed by
Adhemerval Zanella
parent
d31beafa8e
commit
696caf1d00
33
ChangeLog
33
ChangeLog
@ -1,3 +1,36 @@
|
|||||||
|
2013-12-04 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
|
||||||
|
Alan Modra <amodra@gmail.com>
|
||||||
|
|
||||||
|
* sysdeps/powerpc/powerpc64/sysdep.h [_CALL_ELF == 2]
|
||||||
|
(PPC64_LOAD_FUNCPTR, DOT_LABEL, BODY_LABEL, ENTRY_2, END_2): New
|
||||||
|
versions of macros to support ELFv2 ABI.
|
||||||
|
(LOCALENTRY): New macro.
|
||||||
|
(ENTRY, EALIGN): Use it.
|
||||||
|
* sysdeps/powerpc/powerpc64/crti.S (_init, _fini): Use LOCALENTRY.
|
||||||
|
* sysdeps/powerpc/powerpc64/setjmp-common.S (__GI__setjmp): Do not
|
||||||
|
fall through into ENTRY entry point.
|
||||||
|
* libc/sysdeps/powerpc/powerpc64/dl-machine.h (Elf64_FuncDesc):
|
||||||
|
Only define if _CALL_ELF != 2.
|
||||||
|
|
||||||
|
(elf_machine_matches_host): Verify ABI version matches.
|
||||||
|
(RTLD_START): Use LOCALENTRY.
|
||||||
|
(elf_machine_type_class): Use SHN_UNDEF PLT handling for ELFv2 ABI.
|
||||||
|
(PLT_INITIAL_ENTRY_WORDS): New version for _CALL_ELF != 2.
|
||||||
|
(PLT_ENTRY_WORDS): New macro.
|
||||||
|
(GLINK_INITIAL_ENTRY_WORDS, GLINK_ENTRY_WORDS): Likewise.
|
||||||
|
(elf_machine_runtime_setup): Support ELFv2 ABI.
|
||||||
|
(elf_machine_fixup_plt): Likewise.
|
||||||
|
(elf_machine_plt_conflict): Likewise.
|
||||||
|
(resolve_ifunc): Likewise.
|
||||||
|
* sysdeps/powerpc/powerpc64/dl-irel.h (elf_irela): Likewise.
|
||||||
|
* sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h (VDSO_IFUNC_RET):
|
||||||
|
Likewise.
|
||||||
|
* sysdeps/unix/sysv/linux/powerpc/powerpc64/ldsodefs.h
|
||||||
|
(DL_ADDR_SYM_MATCH): Only define if _CALL_ELF != 2.
|
||||||
|
* sysdeps/unix/sysv/linux/powerpc/powerpc64/makecontext.S
|
||||||
|
(makecontext): Support ELFv2 ABI.
|
||||||
|
* elf/elf.h (EF_PPC64_ABI): Define.
|
||||||
|
|
||||||
2013-12-04 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
|
2013-12-04 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
|
||||||
|
|
||||||
* sysdeps/powerpc/powerpc64/sysdep.h [ASSEMBLER] (PPC64_LOAD_FUNCPTR):
|
* sysdeps/powerpc/powerpc64/sysdep.h [ASSEMBLER] (PPC64_LOAD_FUNCPTR):
|
||||||
|
@ -2272,6 +2272,12 @@ typedef Elf32_Addr Elf32_Conflict;
|
|||||||
#define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */
|
#define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */
|
||||||
#define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */
|
#define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */
|
||||||
|
|
||||||
|
/* e_flags bits specifying ABI.
|
||||||
|
1 for original function descriptor using ABI,
|
||||||
|
2 for revised ABI without function descriptors,
|
||||||
|
0 for unspecified or not using any features affected by the differences. */
|
||||||
|
#define EF_PPC64_ABI 3
|
||||||
|
|
||||||
/* PowerPC64 specific values for the Dyn d_tag field. */
|
/* PowerPC64 specific values for the Dyn d_tag field. */
|
||||||
#define DT_PPC64_GLINK (DT_LOPROC + 0)
|
#define DT_PPC64_GLINK (DT_LOPROC + 0)
|
||||||
#define DT_PPC64_OPD (DT_LOPROC + 1)
|
#define DT_PPC64_OPD (DT_LOPROC + 1)
|
||||||
|
@ -64,6 +64,7 @@
|
|||||||
ENTRY_2(_init)
|
ENTRY_2(_init)
|
||||||
.align ALIGNARG (2)
|
.align ALIGNARG (2)
|
||||||
BODY_LABEL (_init):
|
BODY_LABEL (_init):
|
||||||
|
LOCALENTRY(_init)
|
||||||
mflr 0
|
mflr 0
|
||||||
std 0, 16(r1)
|
std 0, 16(r1)
|
||||||
stdu r1, -112(r1)
|
stdu r1, -112(r1)
|
||||||
@ -81,6 +82,7 @@ BODY_LABEL (_init):
|
|||||||
ENTRY_2(_fini)
|
ENTRY_2(_fini)
|
||||||
.align ALIGNARG (2)
|
.align ALIGNARG (2)
|
||||||
BODY_LABEL (_fini):
|
BODY_LABEL (_fini):
|
||||||
|
LOCALENTRY(_fini)
|
||||||
mflr 0
|
mflr 0
|
||||||
std 0, 16(r1)
|
std 0, 16(r1)
|
||||||
stdu r1, -112(r1)
|
stdu r1, -112(r1)
|
||||||
|
@ -50,7 +50,11 @@ elf_irela (const Elf64_Rela *reloc)
|
|||||||
{
|
{
|
||||||
Elf64_Addr *const reloc_addr = (void *) reloc->r_offset;
|
Elf64_Addr *const reloc_addr = (void *) reloc->r_offset;
|
||||||
Elf64_Addr value = elf_ifunc_invoke(reloc->r_addend);
|
Elf64_Addr value = elf_ifunc_invoke(reloc->r_addend);
|
||||||
|
#if _CALL_ELF != 2
|
||||||
*(Elf64_FuncDesc *) reloc_addr = *(Elf64_FuncDesc *) value;
|
*(Elf64_FuncDesc *) reloc_addr = *(Elf64_FuncDesc *) value;
|
||||||
|
#else
|
||||||
|
*reloc_addr = value;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
__libc_fatal ("unexpected reloc type in static binary");
|
__libc_fatal ("unexpected reloc type in static binary");
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
in l_info array. */
|
in l_info array. */
|
||||||
#define DT_PPC64(x) (DT_PPC64_##x - DT_LOPROC + DT_NUM)
|
#define DT_PPC64(x) (DT_PPC64_##x - DT_LOPROC + DT_NUM)
|
||||||
|
|
||||||
|
#if _CALL_ELF != 2
|
||||||
/* A PowerPC64 function descriptor. The .plt (procedure linkage
|
/* A PowerPC64 function descriptor. The .plt (procedure linkage
|
||||||
table) and .opd (official procedure descriptor) sections are
|
table) and .opd (official procedure descriptor) sections are
|
||||||
arrays of these. */
|
arrays of these. */
|
||||||
@ -40,6 +41,7 @@ typedef struct
|
|||||||
Elf64_Addr fd_toc;
|
Elf64_Addr fd_toc;
|
||||||
Elf64_Addr fd_aux;
|
Elf64_Addr fd_aux;
|
||||||
} Elf64_FuncDesc;
|
} Elf64_FuncDesc;
|
||||||
|
#endif
|
||||||
|
|
||||||
#define ELF_MULT_MACHINES_SUPPORTED
|
#define ELF_MULT_MACHINES_SUPPORTED
|
||||||
|
|
||||||
@ -47,6 +49,18 @@ typedef struct
|
|||||||
static inline int
|
static inline int
|
||||||
elf_machine_matches_host (const Elf64_Ehdr *ehdr)
|
elf_machine_matches_host (const Elf64_Ehdr *ehdr)
|
||||||
{
|
{
|
||||||
|
/* Verify that the binary matches our ABI version. */
|
||||||
|
if ((ehdr->e_flags & EF_PPC64_ABI) != 0)
|
||||||
|
{
|
||||||
|
#if _CALL_ELF != 2
|
||||||
|
if ((ehdr->e_flags & EF_PPC64_ABI) != 1)
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
if ((ehdr->e_flags & EF_PPC64_ABI) != 2)
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
return ehdr->e_machine == EM_PPC64;
|
return ehdr->e_machine == EM_PPC64;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,6 +138,7 @@ elf_machine_dynamic (void)
|
|||||||
" .align 2\n" \
|
" .align 2\n" \
|
||||||
" " ENTRY_2(_start) "\n" \
|
" " ENTRY_2(_start) "\n" \
|
||||||
BODY_PREFIX "_start:\n" \
|
BODY_PREFIX "_start:\n" \
|
||||||
|
" " LOCALENTRY(_start) "\n" \
|
||||||
/* We start with the following on the stack, from top: \
|
/* We start with the following on the stack, from top: \
|
||||||
argc (4 bytes); \
|
argc (4 bytes); \
|
||||||
arguments for program (terminated by NULL); \
|
arguments for program (terminated by NULL); \
|
||||||
@ -165,6 +180,7 @@ DL_STARTING_UP_DEF \
|
|||||||
Changing these is strongly discouraged (not least because argc is \
|
Changing these is strongly discouraged (not least because argc is \
|
||||||
passed by value!). */ \
|
passed by value!). */ \
|
||||||
BODY_PREFIX "_dl_start_user:\n" \
|
BODY_PREFIX "_dl_start_user:\n" \
|
||||||
|
" " LOCALENTRY(_dl_start_user) "\n" \
|
||||||
/* the address of _start in r30. */ \
|
/* the address of _start in r30. */ \
|
||||||
" mr 30,3\n" \
|
" mr 30,3\n" \
|
||||||
/* &_dl_argc in 29, &_dl_argv in 27, and _dl_loaded in 28. */ \
|
/* &_dl_argc in 29, &_dl_argv in 27, and _dl_loaded in 28. */ \
|
||||||
@ -256,8 +272,22 @@ BODY_PREFIX "_dl_start_user:\n" \
|
|||||||
relocations behave "normally", ie. always use the real address
|
relocations behave "normally", ie. always use the real address
|
||||||
like PLT relocations. So always set ELF_RTYPE_CLASS_PLT. */
|
like PLT relocations. So always set ELF_RTYPE_CLASS_PLT. */
|
||||||
|
|
||||||
|
#if _CALL_ELF != 2
|
||||||
#define elf_machine_type_class(type) \
|
#define elf_machine_type_class(type) \
|
||||||
(ELF_RTYPE_CLASS_PLT | (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY))
|
(ELF_RTYPE_CLASS_PLT | (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY))
|
||||||
|
#else
|
||||||
|
/* And now that you have read that large comment, you can disregard it
|
||||||
|
all for ELFv2. ELFv2 does need the special SHN_UNDEF treatment. */
|
||||||
|
#define IS_PPC64_TLS_RELOC(R) \
|
||||||
|
(((R) >= R_PPC64_TLS && (R) <= R_PPC64_DTPREL16_HIGHESTA) \
|
||||||
|
|| ((R) >= R_PPC64_TPREL16_HIGH && (R) <= R_PPC64_DTPREL16_HIGHA))
|
||||||
|
|
||||||
|
#define elf_machine_type_class(type) \
|
||||||
|
((((type) == R_PPC64_JMP_SLOT \
|
||||||
|
|| (type) == R_PPC64_ADDR24 \
|
||||||
|
|| IS_PPC64_TLS_RELOC (type)) * ELF_RTYPE_CLASS_PLT) \
|
||||||
|
| (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY))
|
||||||
|
#endif
|
||||||
|
|
||||||
/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
|
/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
|
||||||
#define ELF_MACHINE_JMP_SLOT R_PPC64_JMP_SLOT
|
#define ELF_MACHINE_JMP_SLOT R_PPC64_JMP_SLOT
|
||||||
@ -266,8 +296,19 @@ BODY_PREFIX "_dl_start_user:\n" \
|
|||||||
#define ELF_MACHINE_NO_REL 1
|
#define ELF_MACHINE_NO_REL 1
|
||||||
|
|
||||||
/* Stuff for the PLT. */
|
/* Stuff for the PLT. */
|
||||||
|
#if _CALL_ELF != 2
|
||||||
#define PLT_INITIAL_ENTRY_WORDS 3
|
#define PLT_INITIAL_ENTRY_WORDS 3
|
||||||
|
#define PLT_ENTRY_WORDS 3
|
||||||
#define GLINK_INITIAL_ENTRY_WORDS 8
|
#define GLINK_INITIAL_ENTRY_WORDS 8
|
||||||
|
/* The first 32k entries of glink can set an index and branch using two
|
||||||
|
instructions; past that point, glink uses three instructions. */
|
||||||
|
#define GLINK_ENTRY_WORDS(I) (((I) < 0x8000)? 2 : 3)
|
||||||
|
#else
|
||||||
|
#define PLT_INITIAL_ENTRY_WORDS 2
|
||||||
|
#define PLT_ENTRY_WORDS 1
|
||||||
|
#define GLINK_INITIAL_ENTRY_WORDS 8
|
||||||
|
#define GLINK_ENTRY_WORDS(I) 1
|
||||||
|
#endif
|
||||||
|
|
||||||
#define PPC_DCBST(where) asm volatile ("dcbst 0,%0" : : "r"(where) : "memory")
|
#define PPC_DCBST(where) asm volatile ("dcbst 0,%0" : : "r"(where) : "memory")
|
||||||
#define PPC_DCBT(where) asm volatile ("dcbt 0,%0" : : "r"(where) : "memory")
|
#define PPC_DCBT(where) asm volatile ("dcbt 0,%0" : : "r"(where) : "memory")
|
||||||
@ -312,38 +353,45 @@ elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
|
|||||||
|
|
||||||
if (lazy)
|
if (lazy)
|
||||||
{
|
{
|
||||||
/* The function descriptor of the appropriate trampoline
|
|
||||||
routine is used to set the 1st and 2nd doubleword of the
|
|
||||||
plt_reserve. */
|
|
||||||
Elf64_FuncDesc *resolve_fd;
|
|
||||||
Elf64_Word glink_offset;
|
Elf64_Word glink_offset;
|
||||||
/* the plt_reserve area is the 1st 3 doublewords of the PLT */
|
|
||||||
Elf64_FuncDesc *plt_reserve = (Elf64_FuncDesc *) plt;
|
|
||||||
Elf64_Word offset;
|
Elf64_Word offset;
|
||||||
|
Elf64_Addr dlrr;
|
||||||
|
|
||||||
resolve_fd = (Elf64_FuncDesc *) (profile ? _dl_profile_resolve
|
dlrr = (Elf64_Addr) (profile ? _dl_profile_resolve
|
||||||
: _dl_runtime_resolve);
|
: _dl_runtime_resolve);
|
||||||
if (profile && GLRO(dl_profile) != NULL
|
if (profile && GLRO(dl_profile) != NULL
|
||||||
&& _dl_name_match_p (GLRO(dl_profile), map))
|
&& _dl_name_match_p (GLRO(dl_profile), map))
|
||||||
/* This is the object we are looking for. Say that we really
|
/* This is the object we are looking for. Say that we really
|
||||||
want profiling and the timers are started. */
|
want profiling and the timers are started. */
|
||||||
GL(dl_profile_map) = map;
|
GL(dl_profile_map) = map;
|
||||||
|
|
||||||
|
#if _CALL_ELF != 2
|
||||||
/* We need to stuff the address/TOC of _dl_runtime_resolve
|
/* We need to stuff the address/TOC of _dl_runtime_resolve
|
||||||
into doublewords 0 and 1 of plt_reserve. Then we need to
|
into doublewords 0 and 1 of plt_reserve. Then we need to
|
||||||
stuff the map address into doubleword 2 of plt_reserve.
|
stuff the map address into doubleword 2 of plt_reserve.
|
||||||
This allows the GLINK0 code to transfer control to the
|
This allows the GLINK0 code to transfer control to the
|
||||||
correct trampoline which will transfer control to fixup
|
correct trampoline which will transfer control to fixup
|
||||||
in dl-machine.c. */
|
in dl-machine.c. */
|
||||||
plt_reserve->fd_func = resolve_fd->fd_func;
|
{
|
||||||
plt_reserve->fd_toc = resolve_fd->fd_toc;
|
/* The plt_reserve area is the 1st 3 doublewords of the PLT. */
|
||||||
plt_reserve->fd_aux = (Elf64_Addr) map;
|
Elf64_FuncDesc *plt_reserve = (Elf64_FuncDesc *) plt;
|
||||||
|
Elf64_FuncDesc *resolve_fd = (Elf64_FuncDesc *) dlrr;
|
||||||
|
plt_reserve->fd_func = resolve_fd->fd_func;
|
||||||
|
plt_reserve->fd_toc = resolve_fd->fd_toc;
|
||||||
|
plt_reserve->fd_aux = (Elf64_Addr) map;
|
||||||
#ifdef RTLD_BOOTSTRAP
|
#ifdef RTLD_BOOTSTRAP
|
||||||
/* When we're bootstrapping, the opd entry will not have
|
/* When we're bootstrapping, the opd entry will not have
|
||||||
been relocated yet. */
|
been relocated yet. */
|
||||||
plt_reserve->fd_func += l_addr;
|
plt_reserve->fd_func += l_addr;
|
||||||
plt_reserve->fd_toc += l_addr;
|
plt_reserve->fd_toc += l_addr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/* When we don't have function descriptors, the first doubleword
|
||||||
|
of the PLT holds the address of _dl_runtime_resolve, and the
|
||||||
|
second doubleword holds the map address. */
|
||||||
|
plt[0] = dlrr;
|
||||||
|
plt[1] = (Elf64_Addr) map;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Set up the lazy PLT entries. */
|
/* Set up the lazy PLT entries. */
|
||||||
@ -354,14 +402,8 @@ elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
|
|||||||
{
|
{
|
||||||
|
|
||||||
plt[offset] = (Elf64_Xword) &glink[glink_offset];
|
plt[offset] = (Elf64_Xword) &glink[glink_offset];
|
||||||
offset += 3;
|
offset += PLT_ENTRY_WORDS;
|
||||||
/* The first 32k entries of glink can set an index and
|
glink_offset += GLINK_ENTRY_WORDS (i);
|
||||||
branch using two instructions; Past that point,
|
|
||||||
glink uses three instructions. */
|
|
||||||
if (i < 0x8000)
|
|
||||||
glink_offset += 2;
|
|
||||||
else
|
|
||||||
glink_offset += 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now, we've modified data. We need to write the changes from
|
/* Now, we've modified data. We need to write the changes from
|
||||||
@ -389,6 +431,7 @@ elf_machine_fixup_plt (struct link_map *map, lookup_t sym_map,
|
|||||||
const Elf64_Rela *reloc,
|
const Elf64_Rela *reloc,
|
||||||
Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
|
Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
|
||||||
{
|
{
|
||||||
|
#if _CALL_ELF != 2
|
||||||
Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
|
Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
|
||||||
Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
|
Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
|
||||||
Elf64_Addr offset = 0;
|
Elf64_Addr offset = 0;
|
||||||
@ -426,6 +469,9 @@ elf_machine_fixup_plt (struct link_map *map, lookup_t sym_map,
|
|||||||
plt->fd_func = rel->fd_func + offset;
|
plt->fd_func = rel->fd_func + offset;
|
||||||
PPC_DCBST (&plt->fd_func);
|
PPC_DCBST (&plt->fd_func);
|
||||||
PPC_ISYNC;
|
PPC_ISYNC;
|
||||||
|
#else
|
||||||
|
*reloc_addr = finaladdr;
|
||||||
|
#endif
|
||||||
|
|
||||||
return finaladdr;
|
return finaladdr;
|
||||||
}
|
}
|
||||||
@ -433,6 +479,7 @@ elf_machine_fixup_plt (struct link_map *map, lookup_t sym_map,
|
|||||||
static inline void __attribute__ ((always_inline))
|
static inline void __attribute__ ((always_inline))
|
||||||
elf_machine_plt_conflict (Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
|
elf_machine_plt_conflict (Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
|
||||||
{
|
{
|
||||||
|
#if _CALL_ELF != 2
|
||||||
Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
|
Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
|
||||||
Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
|
Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
|
||||||
|
|
||||||
@ -443,6 +490,9 @@ elf_machine_plt_conflict (Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
|
|||||||
PPC_DCBST (&plt->fd_aux);
|
PPC_DCBST (&plt->fd_aux);
|
||||||
PPC_DCBST (&plt->fd_toc);
|
PPC_DCBST (&plt->fd_toc);
|
||||||
PPC_SYNC;
|
PPC_SYNC;
|
||||||
|
#else
|
||||||
|
*reloc_addr = finaladdr;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the final value of a plt relocation. */
|
/* Return the final value of a plt relocation. */
|
||||||
@ -512,6 +562,7 @@ auto inline Elf64_Addr __attribute__ ((always_inline))
|
|||||||
resolve_ifunc (Elf64_Addr value,
|
resolve_ifunc (Elf64_Addr value,
|
||||||
const struct link_map *map, const struct link_map *sym_map)
|
const struct link_map *map, const struct link_map *sym_map)
|
||||||
{
|
{
|
||||||
|
#if _CALL_ELF != 2
|
||||||
#ifndef RESOLVE_CONFLICT_FIND_MAP
|
#ifndef RESOLVE_CONFLICT_FIND_MAP
|
||||||
/* The function we are calling may not yet have its opd entry relocated. */
|
/* The function we are calling may not yet have its opd entry relocated. */
|
||||||
Elf64_FuncDesc opd;
|
Elf64_FuncDesc opd;
|
||||||
@ -528,6 +579,7 @@ resolve_ifunc (Elf64_Addr value,
|
|||||||
opd.fd_aux = func->fd_aux;
|
opd.fd_aux = func->fd_aux;
|
||||||
value = (Elf64_Addr) &opd;
|
value = (Elf64_Addr) &opd;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
return ((Elf64_Addr (*) (unsigned long int)) value) (GLRO(dl_hwcap));
|
return ((Elf64_Addr (*) (unsigned long int)) value) (GLRO(dl_hwcap));
|
||||||
}
|
}
|
||||||
|
@ -55,9 +55,10 @@ END (setjmp)
|
|||||||
HAVE_CLEANUP_JMP_BUF is defined. */
|
HAVE_CLEANUP_JMP_BUF is defined. */
|
||||||
ENTRY (__GI__setjmp)
|
ENTRY (__GI__setjmp)
|
||||||
std r2,40(r1) /* Save the callers TOC in the save area. */
|
std r2,40(r1) /* Save the callers TOC in the save area. */
|
||||||
cfi_endproc
|
CALL_MCOUNT 1
|
||||||
END_2 (__GI__setjmp)
|
li r4,0 /* Set second argument to 0. */
|
||||||
/* Fall thru. */
|
b JUMPTARGET (GLUE(__sigsetjmp,_ent))
|
||||||
|
END (__GI__setjmp)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ENTRY (_setjmp)
|
ENTRY (_setjmp)
|
||||||
|
@ -74,6 +74,8 @@
|
|||||||
#endif
|
#endif
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
#if _CALL_ELF != 2
|
||||||
|
|
||||||
/* Macro to prepare for calling via a function pointer. */
|
/* Macro to prepare for calling via a function pointer. */
|
||||||
.macro PPC64_LOAD_FUNCPTR PTR
|
.macro PPC64_LOAD_FUNCPTR PTR
|
||||||
ld r12,0(\PTR)
|
ld r12,0(\PTR)
|
||||||
@ -115,13 +117,37 @@ name##: OPD_ENT (name); \
|
|||||||
.size name,.-BODY_LABEL(name); \
|
.size name,.-BODY_LABEL(name); \
|
||||||
.size BODY_LABEL(name),.-BODY_LABEL(name);
|
.size BODY_LABEL(name),.-BODY_LABEL(name);
|
||||||
#endif
|
#endif
|
||||||
|
#define LOCALENTRY(name)
|
||||||
|
|
||||||
|
#else /* _CALL_ELF */
|
||||||
|
|
||||||
|
/* Macro to prepare for calling via a function pointer. */
|
||||||
|
.macro PPC64_LOAD_FUNCPTR PTR
|
||||||
|
mr r12,\PTR
|
||||||
|
mtctr r12
|
||||||
|
.endm
|
||||||
|
|
||||||
|
#define DOT_LABEL(X) X
|
||||||
|
#define BODY_LABEL(X) X
|
||||||
|
#define ENTRY_2(name) \
|
||||||
|
.globl name; \
|
||||||
|
.type name,@function;
|
||||||
|
#define END_2(name) \
|
||||||
|
.size name,.-name;
|
||||||
|
#define LOCALENTRY(name) \
|
||||||
|
1: addis r2,r12,.TOC.-1b@ha; \
|
||||||
|
addi r2,r2,.TOC.-1b@l; \
|
||||||
|
.localentry name,.-name;
|
||||||
|
|
||||||
|
#endif /* _CALL_ELF */
|
||||||
|
|
||||||
#define ENTRY(name) \
|
#define ENTRY(name) \
|
||||||
.section ".text"; \
|
.section ".text"; \
|
||||||
ENTRY_2(name) \
|
ENTRY_2(name) \
|
||||||
.align ALIGNARG(2); \
|
.align ALIGNARG(2); \
|
||||||
BODY_LABEL(name): \
|
BODY_LABEL(name): \
|
||||||
cfi_startproc;
|
cfi_startproc; \
|
||||||
|
LOCALENTRY(name)
|
||||||
|
|
||||||
#define EALIGN_W_0 /* No words to insert. */
|
#define EALIGN_W_0 /* No words to insert. */
|
||||||
#define EALIGN_W_1 nop
|
#define EALIGN_W_1 nop
|
||||||
@ -140,7 +166,8 @@ BODY_LABEL(name): \
|
|||||||
.align ALIGNARG(alignt); \
|
.align ALIGNARG(alignt); \
|
||||||
EALIGN_W_##words; \
|
EALIGN_W_##words; \
|
||||||
BODY_LABEL(name): \
|
BODY_LABEL(name): \
|
||||||
cfi_startproc;
|
cfi_startproc; \
|
||||||
|
LOCALENTRY(name)
|
||||||
|
|
||||||
/* Local labels stripped out by the linker. */
|
/* Local labels stripped out by the linker. */
|
||||||
#undef L
|
#undef L
|
||||||
@ -295,6 +322,8 @@ LT_LABELSUFFIX(name,_name_end): ; \
|
|||||||
|
|
||||||
#else /* !__ASSEMBLER__ */
|
#else /* !__ASSEMBLER__ */
|
||||||
|
|
||||||
|
#if _CALL_ELF != 2
|
||||||
|
|
||||||
#define PPC64_LOAD_FUNCPTR(ptr) \
|
#define PPC64_LOAD_FUNCPTR(ptr) \
|
||||||
"ld 12,0(" #ptr ");\n" \
|
"ld 12,0(" #ptr ");\n" \
|
||||||
"ld 2,8(" #ptr ");\n" \
|
"ld 2,8(" #ptr ");\n" \
|
||||||
@ -335,5 +364,26 @@ LT_LABELSUFFIX(name,_name_end): ; \
|
|||||||
".size " #name ",.-" BODY_PREFIX #name ";\n" \
|
".size " #name ",.-" BODY_PREFIX #name ";\n" \
|
||||||
".size " BODY_PREFIX #name ",.-" BODY_PREFIX #name ";"
|
".size " BODY_PREFIX #name ",.-" BODY_PREFIX #name ";"
|
||||||
#endif
|
#endif
|
||||||
|
#define LOCALENTRY(name)
|
||||||
|
|
||||||
|
#else /* _CALL_ELF */
|
||||||
|
|
||||||
|
#define PPC64_LOAD_FUNCPTR(ptr) \
|
||||||
|
"mr 12," #ptr ";\n" \
|
||||||
|
"mtctr 12;"
|
||||||
|
|
||||||
|
#define DOT_PREFIX ""
|
||||||
|
#define BODY_PREFIX ""
|
||||||
|
#define ENTRY_2(name) \
|
||||||
|
".type " #name ",@function;\n" \
|
||||||
|
".globl " #name ";"
|
||||||
|
#define END_2(name) \
|
||||||
|
".size " #name ",.-" #name ";"
|
||||||
|
#define LOCALENTRY(name) \
|
||||||
|
"1: addis 2,12,.TOC.-1b@ha;\n" \
|
||||||
|
"addi 2,2,.TOC.-1b@l;\n" \
|
||||||
|
".localentry " #name ",.-" #name ";"
|
||||||
|
|
||||||
|
#endif /* _CALL_ELF */
|
||||||
|
|
||||||
#endif /* __ASSEMBLER__ */
|
#endif /* __ASSEMBLER__ */
|
||||||
|
@ -41,7 +41,7 @@ extern void *__vdso_sigtramp32;
|
|||||||
extern void *__vdso_sigtramp_rt32;
|
extern void *__vdso_sigtramp_rt32;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__PPC64__) || defined(__powerpc64__)
|
#if (defined(__PPC64__) || defined(__powerpc64__)) && _CALL_ELF != 2
|
||||||
/* The correct solution is for _dl_vdso_vsym to return the address of the OPD
|
/* The correct solution is for _dl_vdso_vsym to return the address of the OPD
|
||||||
for the kernel VDSO function. That address would then be stored in the
|
for the kernel VDSO function. That address would then be stored in the
|
||||||
__vdso_* variables and returned as the result of the IFUNC resolver function.
|
__vdso_* variables and returned as the result of the IFUNC resolver function.
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
|
|
||||||
/* Now define our stuff. */
|
/* Now define our stuff. */
|
||||||
|
|
||||||
|
#if _CALL_ELF != 2
|
||||||
|
|
||||||
static __always_inline bool
|
static __always_inline bool
|
||||||
_dl_ppc64_is_opd_sym (const struct link_map *l, const ElfW(Sym) *sym)
|
_dl_ppc64_is_opd_sym (const struct link_map *l, const ElfW(Sym) *sym)
|
||||||
{
|
{
|
||||||
@ -73,4 +75,6 @@ _dl_ppc64_addr_sym_match (const struct link_map *l, const ElfW(Sym) *sym,
|
|||||||
#define DL_ADDR_SYM_MATCH(L, SYM, MATCHSYM, ADDR) \
|
#define DL_ADDR_SYM_MATCH(L, SYM, MATCHSYM, ADDR) \
|
||||||
_dl_ppc64_addr_sym_match (L, SYM, MATCHSYM, ADDR)
|
_dl_ppc64_addr_sym_match (L, SYM, MATCHSYM, ADDR)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* ldsodefs.h */
|
#endif /* ldsodefs.h */
|
||||||
|
@ -111,6 +111,7 @@ L(parmloop):
|
|||||||
|
|
||||||
L(noparms):
|
L(noparms):
|
||||||
|
|
||||||
|
#if _CALL_ELF != 2
|
||||||
/* Load the function address and TOC from the function descriptor
|
/* Load the function address and TOC from the function descriptor
|
||||||
and store them in the ucontext as NIP and r2. Store the 3rd
|
and store them in the ucontext as NIP and r2. Store the 3rd
|
||||||
field of the function descriptor into the ucontext as r11 in case
|
field of the function descriptor into the ucontext as r11 in case
|
||||||
@ -121,6 +122,12 @@ L(noparms):
|
|||||||
std r0,(SIGCONTEXT_GP_REGS+(PT_NIP*8))(r3)
|
std r0,(SIGCONTEXT_GP_REGS+(PT_NIP*8))(r3)
|
||||||
std r10,(SIGCONTEXT_GP_REGS+(PT_R2*8))(r3)
|
std r10,(SIGCONTEXT_GP_REGS+(PT_R2*8))(r3)
|
||||||
std r9,(SIGCONTEXT_GP_REGS+(PT_R11*8))(r3)
|
std r9,(SIGCONTEXT_GP_REGS+(PT_R11*8))(r3)
|
||||||
|
#else
|
||||||
|
/* In the ELFv2 ABI, the function pointer is already the address.
|
||||||
|
Store it as NIP and r12 as required by the ABI. */
|
||||||
|
std r4,(SIGCONTEXT_GP_REGS+(PT_NIP*8))(r3)
|
||||||
|
std r4,(SIGCONTEXT_GP_REGS+(PT_R12*8))(r3)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* If the target function returns we need to do some cleanup. We use a
|
/* If the target function returns we need to do some cleanup. We use a
|
||||||
code trick to get the address of our cleanup function into the link
|
code trick to get the address of our cleanup function into the link
|
||||||
|
Reference in New Issue
Block a user