/* Machine-dependent ELF dynamic relocation inline functions. IA-64 version.
- Copyright (C) 1995-1997, 2000-2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 1995-2016 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
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. */
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
#ifndef dl_machine_h
#define dl_machine_h 1
#include <string.h>
#include <link.h>
#include <errno.h>
+#include <dl-fptr.h>
#include <tls.h>
/* Translate a processor specific dynamic tag to the index
in l_info array. */
#define DT_IA_64(x) (DT_IA_64_##x - DT_LOPROC + DT_NUM)
-/* There are currently 123 dynamic symbols in ld.so.
- IA64_BOOT_FPTR_TABLE_LEN needs to be at least that big. */
-#define IA64_BOOT_FPTR_TABLE_LEN 200
-
-/* An FDESC is a function descriptor. */
-
-struct ia64_fdesc
- {
- Elf64_Addr ip; /* code entry point */
- Elf64_Addr gp; /* global pointer */
- };
-
-struct ia64_fdesc_table
- {
- struct ia64_fdesc_table *next;
- unsigned int len; /* # of entries in fdesc table */
- volatile unsigned int first_unused; /* index of first available entry */
- struct ia64_fdesc fdesc[0];
- };
-
-extern Elf64_Addr __ia64_make_fptr (const struct link_map *,
- const Elf64_Sym *, Elf64_Addr);
-
-static inline void
+static inline void __attribute__ ((always_inline))
__ia64_init_bootstrap_fdesc_table (struct link_map *map)
{
Elf64_Addr *boot_table;
/* careful: this will be called before got has been relocated... */
- asm (";; addl %0 = @gprel (__ia64_boot_fptr_table), gp" : "=r"(boot_table));
+ asm (";; addl %0 = @gprel (_dl_boot_fptr_table), gp" : "=r"(boot_table));
- map->l_mach.fptr_table_len = IA64_BOOT_FPTR_TABLE_LEN;
+ map->l_mach.fptr_table_len = ELF_MACHINE_BOOT_FPTR_TABLE_LEN;
map->l_mach.fptr_table = boot_table;
}
__ia64_init_bootstrap_fdesc_table (&bootstrap_map);
/* Return nonzero iff ELF header is compatible with the running host. */
-static inline int
+static inline int __attribute__ ((unused))
elf_machine_matches_host (const Elf64_Ehdr *ehdr)
{
return ehdr->e_machine == EM_IA_64;
/* Return the link-time address of _DYNAMIC. */
-static inline Elf64_Addr
+static inline Elf64_Addr __attribute__ ((unused, const))
elf_machine_dynamic (void)
{
Elf64_Addr *p;
/* Return the run-time load address of the shared object. */
-static inline Elf64_Addr
+static inline Elf64_Addr __attribute__ ((unused))
elf_machine_load_address (void)
{
Elf64_Addr ip;
/* Set up the loaded object described by L so its unrelocated PLT
entries will jump to the on-demand fixup code in dl-runtime.c. */
-static inline int
+static inline int __attribute__ ((unused, always_inline))
elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
{
extern void _dl_runtime_resolve (void);
/* This function will be called to perform the relocation. */
if (!profile)
- doit = (Elf64_Addr) ((struct ia64_fdesc *) &_dl_runtime_resolve)->ip;
+ doit = (Elf64_Addr) ELF_PTR_TO_FDESC (&_dl_runtime_resolve)->ip;
else
{
- if (_dl_name_match_p (GL(dl_profile), l))
+ if (GLRO(dl_profile) != NULL
+ && _dl_name_match_p (GLRO(dl_profile), l))
{
/* This is the object we are looking for. Say that we really
want profiling and the timers are started. */
GL(dl_profile_map) = l;
}
- doit = (Elf64_Addr) ((struct ia64_fdesc *) &_dl_runtime_profile)->ip;
+ doit = (Elf64_Addr) ELF_PTR_TO_FDESC (&_dl_runtime_profile)->ip;
}
reserve[1] = doit;
return lazy;
}
+/* Names of the architecture-specific auditing callback functions. */
+#define ARCH_LA_PLTENTER ia64_gnu_pltenter
+#define ARCH_LA_PLTEXIT ia64_gnu_pltexit
-/*
- This code is used in dl-runtime.c to call the `fixup' function
- and then redirect to the address it returns. `fixup()' takes two
- arguments, however profile_fixup() takes three.
-
- The ABI specifies that we will never see more than 8 input
- registers to a function call, thus it is safe to simply allocate
- those, and simpler than playing stack games.
- - 12/09/99 Jes
- */
-#define TRAMPOLINE_TEMPLATE(tramp_name, fixup_name) \
- extern void tramp_name (void); \
- asm ( \
-" .global " #tramp_name "#\n" \
-" .proc " #tramp_name "#\n" \
-#tramp_name ":\n" \
-" { .mmi\n" \
-" .prologue\n" \
-" .save ar.pfs, r40\n" \
-" alloc loc0 = ar.pfs, 8, 6, 3, 0\n" \
-" adds r2 = -144, r12\n" \
-" adds r3 = -128, r12\n" \
-" }\n" \
-" { .mii\n" \
-" .fframe 160\n" \
-" adds r12 = -160, r12\n" \
-" .save rp, r41\n" \
-" mov loc1 = b0\n" \
-" .body\n" \
-" mov out2 = b0 /* needed by fixup_profile */\n" \
-" ;;\n" \
-" }\n" \
-" { .mfb\n" \
-" mov loc2 = r8 /* preserve struct value register */\n" \
-" nop.f 0\n" \
-" nop.b 0\n" \
-" }\n" \
-" { .mii\n" \
-" mov loc3 = r9 /* preserve language specific register */\n" \
-" mov loc4 = r10 /* preserve language specific register */\n" \
-" mov loc5 = r11 /* preserve language specific register */\n" \
-" }\n" \
-" { .mmi\n" \
-" stf.spill [r2] = f8, 32\n" \
-" stf.spill [r3] = f9, 32\n" \
-" mov out0 = r16\n" \
-" ;;\n" \
-" }\n" \
-" { .mmi\n" \
-" stf.spill [r2] = f10, 32\n" \
-" stf.spill [r3] = f11, 32\n" \
-" shl out1 = r15, 4\n" \
-" ;;\n" \
-" }\n" \
-" { .mmi\n" \
-" stf.spill [r2] = f12, 32\n" \
-" stf.spill [r3] = f13, 32\n" \
-" shladd out1 = r15, 3, out1\n" \
-" ;;\n" \
-" }\n" \
-" { .mmb\n" \
-" stf.spill [r2] = f14\n" \
-" stf.spill [r3] = f15\n" \
-" br.call.sptk.many b0 = " #fixup_name "#\n" \
-" }\n" \
-" { .mii\n" \
-" ld8 r9 = [ret0], 8\n" \
-" adds r2 = 16, r12\n" \
-" adds r3 = 32, r12\n" \
-" ;;\n" \
-" }\n" \
-" { .mmi\n" \
-" ldf.fill f8 = [r2], 32\n" \
-" ldf.fill f9 = [r3], 32\n" \
-" mov b0 = loc1\n" \
-" ;;\n" \
-" }\n" \
-" { .mmi\n" \
-" ldf.fill f10 = [r2], 32\n" \
-" ldf.fill f11 = [r3], 32\n" \
-" mov b6 = r9\n" \
-" ;;\n" \
-" }\n" \
-" { .mmi\n" \
-" ldf.fill f12 = [r2], 32\n" \
-" ldf.fill f13 = [r3], 32\n" \
-" mov ar.pfs = loc0\n" \
-" ;;\n" \
-" }\n" \
-" { .mmi\n" \
-" ldf.fill f14 = [r2], 32\n" \
-" ldf.fill f15 = [r3], 32\n" \
-" .restore sp /* pop the unwind frame state */\n" \
-" adds r12 = 160, r12\n" \
-" ;;\n" \
-" }\n" \
-" { .mii\n" \
-" mov r9 = loc3 /* restore language specific register */\n" \
-" mov r10 = loc4 /* restore language specific register */\n" \
-" mov r11 = loc5 /* restore language specific register */\n" \
-" }\n" \
-" { .mii\n" \
-" ld8 gp = [ret0]\n" \
-" mov r8 = loc2 /* restore struct value register */\n" \
-" ;;\n" \
-" }\n" \
-" /* An alloc is needed for the break system call to work.\n" \
-" We don't care about the old value of the pfs register. */\n" \
-" { .mmb\n" \
-" .prologue\n" \
-" .body\n" \
-" alloc r2 = ar.pfs, 0, 0, 8, 0\n" \
-" br.sptk.many b6\n" \
-" ;;\n" \
-" }\n" \
-" .endp " #tramp_name "#\n");
-
-#ifndef PROF
-#define ELF_MACHINE_RUNTIME_TRAMPOLINE \
- TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup); \
- TRAMPOLINE_TEMPLATE (_dl_runtime_profile, profile_fixup);
-#else
-#define ELF_MACHINE_RUNTIME_TRAMPOLINE \
- TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup); \
- strong_alias (_dl_runtime_resolve, _dl_runtime_profile);
-#endif
-
+/* Undo the adds out0 = 16, sp below to get at the value we want in
+ __libc_stack_end. */
+#define DL_STACK_END(cookie) \
+ ((void *) (((long) (cookie)) - 16))
/* Initial entry point code for the dynamic linker.
The C function `_dl_start' is the real entry point;
"_start:\n" \
"0: { .mii\n" \
" .prologue\n" \
-" .save ar.pfs, r32\n" \
" .save rp, r0\n" \
+" .body\n" \
+" .prologue\n" \
+" .save ar.pfs, r32\n" \
" alloc loc0 = ar.pfs, 0, 3, 4, 0\n" \
" .body\n" \
" mov r2 = ip\n" \
" .proc _dl_start_user#\n" \
"_dl_start_user:\n" \
" .prologue\n" \
-" .save ar.pfs, r32\n" \
" .save rp, r0\n" \
+" .body\n" \
+" .prologue\n" \
+" .save ar.pfs, r32\n" \
" .body\n" \
" { .mii\n" \
-" /* Save the pointer to the user entry point fptr in loc2. */\n" \
-" mov loc2 = ret0\n" \
-" /* Store the highest stack address. */\n" \
-" addl r2 = @ltoff(__libc_stack_end#), gp\n" \
" addl r3 = @gprel(_dl_skip_args), gp\n" \
-" ;;\n" \
-" }\n" \
-" { .mmi\n" \
-" ld8 r2 = [r2]\n" \
-" ld4 r3 = [r3]\n" \
" adds r11 = 24, sp /* Load the address of argv. */\n" \
+" /* Save the pointer to the user entry point fptr in loc2. */\n" \
+" mov loc2 = ret0\n" \
" ;;\n" \
" }\n" \
" { .mii\n" \
-" st8 [r2] = sp\n" \
+" ld4 r3 = [r3]\n" \
" adds r10 = 16, sp /* Load the address of argc. */\n" \
" mov out2 = r11\n" \
" ;;\n" \
" }\n" \
" { .mmb\n" \
" st8 [r2] = r17 /* Load the new _dl_argv. */\n" \
-" br.call.sptk.many b0 = _dl_init_internal#\n" \
+" br.call.sptk.many b0 = _dl_init#\n" \
" ;;\n" \
" }\n" \
-" /* Pass our finializer function to the user,\n" \
+" /* Pass our finalizer function to the user,\n" \
" and jump to the user's entry point. */\n" \
" { .mmi\n" \
" ld8 r3 = [loc2], 8\n" \
/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or TLS
variable, so undefined references should not be allowed to define the
value.
- ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
+ ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve to one
of the main executable's symbols, as for a COPY reloc, which we don't
use. */
/* ??? Ignore *MSB for now. */
-#if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
#define elf_machine_type_class(type) \
(((type) == R_IA64_IPLTLSB || (type) == R_IA64_DTPMOD64LSB \
|| (type) == R_IA64_DTPREL64LSB || (type) == R_IA64_TPREL64LSB) \
* ELF_RTYPE_CLASS_PLT)
-#else
-#define elf_machine_type_class(type) \
- (((type) == R_IA64_IPLTLSB) * ELF_RTYPE_CLASS_PLT)
-#endif
/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
#define ELF_MACHINE_JMP_SLOT R_IA64_IPLTLSB
/* According to the IA-64 specific documentation, Rela is always used. */
#define ELF_MACHINE_NO_REL 1
+#define ELF_MACHINE_NO_RELA 0
/* Return the address of the entry point. */
-#define ELF_MACHINE_START_ADDRESS(map, start) \
- DL_STATIC_FUNCTION_ADDRESS (map, start)
-
-#define elf_machine_profile_fixup_plt(l, reloc, rel_addr, value) \
- elf_machine_fixup_plt (l, reloc, rel_addr, value)
-
-#define elf_machine_profile_plt(reloc_addr) ((Elf64_Addr) (reloc_addr))
+#define ELF_MACHINE_START_ADDRESS(map, start) \
+({ \
+ ElfW(Addr) addr; \
+ DL_DT_FUNCTION_ADDRESS(map, start, static, addr) \
+ addr; \
+})
/* Fixup a PLT entry to bounce directly to the function at VALUE. */
-static inline Elf64_Addr
+static inline struct fdesc __attribute__ ((always_inline))
elf_machine_fixup_plt (struct link_map *l, lookup_t t,
const Elf64_Rela *reloc,
- Elf64_Addr *reloc_addr, Elf64_Addr value)
+ Elf64_Addr *reloc_addr, struct fdesc value)
{
/* l is the link_map for the caller, t is the link_map for the object
* being called */
/* got has already been relocated in elf_get_dynamic_info() */
- reloc_addr[1] = t->l_info[DT_PLTGOT]->d_un.d_ptr;
+ reloc_addr[1] = value.gp;
/* we need a "release" here to ensure that the gp is visible before
the code entry point is updated: */
- ((volatile Elf64_Addr *) reloc_addr)[0] = value;
- return (Elf64_Addr) reloc_addr;
+ ((volatile Elf64_Addr *) reloc_addr)[0] = value.ip;
+ return value;
}
/* Return the final value of a plt relocation. */
-static inline Elf64_Addr
+static inline struct fdesc
elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
- Elf64_Addr value)
+ struct fdesc value)
{
/* No need to handle rel vs rela since IA64 is rela only */
- return value + reloc->r_addend;
+ return (struct fdesc) { value.ip + reloc->r_addend, value.gp };
}
#endif /* !dl_machine_h */
/* Perform the relocation specified by RELOC and SYM (which is fully
resolved). MAP is the object containing the reloc. */
-static inline void
+auto inline void
+__attribute ((always_inline))
elf_machine_rela (struct link_map *map,
const Elf64_Rela *reloc,
const Elf64_Sym *sym,
const struct r_found_version *version,
- Elf64_Addr *const reloc_addr)
+ void *const reloc_addr_arg,
+ int skip_ifunc)
{
+ Elf64_Addr *const reloc_addr = reloc_addr_arg;
const unsigned long int r_type = ELF64_R_TYPE (reloc->r_info);
Elf64_Addr value;
/* Already done in dynamic linker. */
if (map != &GL(dl_rtld_map))
# endif
- value += map->l_addr;
+ value += map->l_addr;
}
else
#endif
/* RESOLVE_MAP() will return NULL if it fail to locate the symbol. */
if ((sym_map = RESOLVE_MAP (&sym, version, r_type)))
- {
+ {
value = sym_map->l_addr + sym->st_value + reloc->r_addend;
if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_DIR64LSB))
;/* No adjustment. */
else if (r_type == R_IA64_IPLTLSB)
{
- elf_machine_fixup_plt (NULL, sym_map, reloc, reloc_addr, value);
+ elf_machine_fixup_plt (NULL, NULL, reloc, reloc_addr,
+ DL_FIXUP_MAKE_VALUE (sym_map, value));
return;
}
else if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_FPTR64LSB))
- value = __ia64_make_fptr (sym_map, sym, value);
+ value = _dl_make_fptr (sym_map, sym, value);
else if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_PCREL64LSB))
value -= (Elf64_Addr) reloc_addr & -16;
-#if defined USE_TLS && (!defined RTLD_BOOTSTRAP || defined USE___THREAD)
else if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_DTPMOD64LSB))
-# ifdef RTLD_BOOTSTRAP
+#ifdef RTLD_BOOTSTRAP
/* During startup the dynamic linker is always index 1. */
value = 1;
-# else
+#else
/* Get the information from the link map returned by the
resolv function. */
value = sym_map->l_tls_modid;
else if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_DTPREL64LSB))
value -= sym_map->l_addr;
-# endif
+#endif
else if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_TPREL64LSB))
{
-# ifndef RTLD_BOOTSTRAP
+#ifndef RTLD_BOOTSTRAP
CHECK_STATIC_TLS (map, sym_map);
-# endif
+#endif
value += sym_map->l_tls_offset - sym_map->l_addr;
}
-#endif
else
- assert (! "unexpected dynamic reloc type");
+ _dl_reloc_bad_type (map, r_type, 0);
}
else
value = 0;
reloc_addr[1] = 0;
}
else
- assert (! "unexpected dynamic reloc format");
+ _dl_reloc_bad_type (map, r_type, 0);
}
/* Let do-rel.h know that on IA-64 if l_addr is 0, all RELATIVE relocs
can be skipped. */
#define ELF_MACHINE_REL_RELATIVE 1
-static inline void
+auto inline void
+__attribute ((always_inline))
elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
- Elf64_Addr *const reloc_addr)
+ void *const reloc_addr_arg)
{
+ Elf64_Addr *const reloc_addr = reloc_addr_arg;
/* ??? Ignore MSB and Instruction format for now. */
assert (ELF64_R_TYPE (reloc->r_info) == R_IA64_REL64LSB);
}
/* Perform a RELATIVE reloc on the .got entry that transfers to the .plt. */
-static inline void
+auto inline void
+__attribute ((always_inline))
elf_machine_lazy_rel (struct link_map *map,
- Elf64_Addr l_addr, const Elf64_Rela *reloc)
+ Elf64_Addr l_addr, const Elf64_Rela *reloc,
+ int skip_ifunc)
{
Elf64_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
const unsigned long int r_type = ELF64_R_TYPE (reloc->r_info);
else if (r_type == R_IA64_NONE)
return;
else
- assert (! "unexpected PLT reloc type");
+ _dl_reloc_bad_type (map, r_type, 1);
}
#endif /* RESOLVE_MAP */