Blame sysdeps/x86_64/dl-machine.h

Packit 6c4009
/* Machine-dependent ELF dynamic relocation inline functions.  x86-64 version.
Packit 6c4009
   Copyright (C) 2001-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Andreas Jaeger <aj@suse.de>.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#ifndef dl_machine_h
Packit 6c4009
#define dl_machine_h
Packit 6c4009
Packit 6c4009
#define ELF_MACHINE_NAME "x86_64"
Packit 6c4009
Packit 6c4009
#include <sys/param.h>
Packit 6c4009
#include <sysdep.h>
Packit 6c4009
#include <tls.h>
Packit 6c4009
#include <dl-tlsdesc.h>
Packit Service 3b0880
#include <cpu-features.c>
Packit 6c4009
Packit 6c4009
/* Return nonzero iff ELF header is compatible with the running host.  */
Packit 6c4009
static inline int __attribute__ ((unused))
Packit 6c4009
elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
Packit 6c4009
{
Packit 6c4009
  return ehdr->e_machine == EM_X86_64;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Return the link-time address of _DYNAMIC.  Conveniently, this is the
Packit 6c4009
   first element of the GOT.  This must be inlined in a function which
Packit 6c4009
   uses global data.  */
Packit 6c4009
static inline ElfW(Addr) __attribute__ ((unused))
Packit 6c4009
elf_machine_dynamic (void)
Packit 6c4009
{
Packit 6c4009
  /* This produces an IP-relative reloc which is resolved at link time. */
Packit 6c4009
  extern const ElfW(Addr) _GLOBAL_OFFSET_TABLE_[] attribute_hidden;
Packit 6c4009
  return _GLOBAL_OFFSET_TABLE_[0];
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Return the run-time load address of the shared object.  */
Packit 6c4009
static inline ElfW(Addr) __attribute__ ((unused))
Packit 6c4009
elf_machine_load_address (void)
Packit 6c4009
{
Packit 6c4009
  /* Compute the difference between the runtime address of _DYNAMIC as seen
Packit 6c4009
     by an IP-relative reference, and the link-time address found in the
Packit 6c4009
     special unrelocated first GOT entry.  */
Packit 6c4009
  extern ElfW(Dyn) _DYNAMIC[] attribute_hidden;
Packit 6c4009
  return (ElfW(Addr)) &_DYNAMIC - elf_machine_dynamic ();
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Set up the loaded object described by L so its unrelocated PLT
Packit 6c4009
   entries will jump to the on-demand fixup code in dl-runtime.c.  */
Packit 6c4009
Packit 6c4009
static inline int __attribute__ ((unused, always_inline))
Packit 6c4009
elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
Packit 6c4009
{
Packit 6c4009
  Elf64_Addr *got;
Packit 6c4009
  extern void _dl_runtime_resolve_fxsave (ElfW(Word)) attribute_hidden;
Packit 6c4009
  extern void _dl_runtime_resolve_xsave (ElfW(Word)) attribute_hidden;
Packit 6c4009
  extern void _dl_runtime_resolve_xsavec (ElfW(Word)) attribute_hidden;
Packit 6c4009
  extern void _dl_runtime_profile_sse (ElfW(Word)) attribute_hidden;
Packit 6c4009
  extern void _dl_runtime_profile_avx (ElfW(Word)) attribute_hidden;
Packit 6c4009
  extern void _dl_runtime_profile_avx512 (ElfW(Word)) attribute_hidden;
Packit 6c4009
Packit 6c4009
  if (l->l_info[DT_JMPREL] && lazy)
Packit 6c4009
    {
Packit 6c4009
      /* The GOT entries for functions in the PLT have not yet been filled
Packit 6c4009
	 in.  Their initial contents will arrange when called to push an
Packit 6c4009
	 offset into the .rel.plt section, push _GLOBAL_OFFSET_TABLE_[1],
Packit 6c4009
	 and then jump to _GLOBAL_OFFSET_TABLE_[2].  */
Packit 6c4009
      got = (Elf64_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
Packit 6c4009
      /* If a library is prelinked but we have to relocate anyway,
Packit 6c4009
	 we have to be able to undo the prelinking of .got.plt.
Packit 6c4009
	 The prelinker saved us here address of .plt + 0x16.  */
Packit 6c4009
      if (got[1])
Packit 6c4009
	{
Packit 6c4009
	  l->l_mach.plt = got[1] + l->l_addr;
Packit 6c4009
	  l->l_mach.gotplt = (ElfW(Addr)) &got[3];
Packit 6c4009
	}
Packit 6c4009
      /* Identify this shared object.  */
Packit 6c4009
      *(ElfW(Addr) *) (got + 1) = (ElfW(Addr)) l;
Packit 6c4009
Packit 6c4009
      /* The got[2] entry contains the address of a function which gets
Packit 6c4009
	 called to get the address of a so far unresolved function and
Packit 6c4009
	 jump to it.  The profiling extension of the dynamic linker allows
Packit 6c4009
	 to intercept the calls to collect information.  In this case we
Packit 6c4009
	 don't store the address in the GOT so that all future calls also
Packit 6c4009
	 end in this function.  */
Packit 6c4009
      if (__glibc_unlikely (profile))
Packit 6c4009
	{
Packit Service 3b0880
	  if (HAS_ARCH_FEATURE (AVX512F_Usable))
Packit 6c4009
	    *(ElfW(Addr) *) (got + 2) = (ElfW(Addr)) &_dl_runtime_profile_avx512;
Packit Service 3b0880
	  else if (HAS_ARCH_FEATURE (AVX_Usable))
Packit 6c4009
	    *(ElfW(Addr) *) (got + 2) = (ElfW(Addr)) &_dl_runtime_profile_avx;
Packit 6c4009
	  else
Packit 6c4009
	    *(ElfW(Addr) *) (got + 2) = (ElfW(Addr)) &_dl_runtime_profile_sse;
Packit 6c4009
Packit 6c4009
	  if (GLRO(dl_profile) != NULL
Packit 6c4009
	      && _dl_name_match_p (GLRO(dl_profile), l))
Packit 6c4009
	    /* This is the object we are looking for.  Say that we really
Packit 6c4009
	       want profiling and the timers are started.  */
Packit 6c4009
	    GL(dl_profile_map) = l;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  /* This function will get called to fix up the GOT entry
Packit 6c4009
	     indicated by the offset on the stack, and then jump to
Packit 6c4009
	     the resolved address.  */
Packit 6c4009
	  if (GLRO(dl_x86_cpu_features).xsave_state_size != 0)
Packit 6c4009
	    *(ElfW(Addr) *) (got + 2)
Packit Service 3b0880
	      = (HAS_ARCH_FEATURE (XSAVEC_Usable)
Packit 6c4009
		 ? (ElfW(Addr)) &_dl_runtime_resolve_xsavec
Packit 6c4009
		 : (ElfW(Addr)) &_dl_runtime_resolve_xsave);
Packit 6c4009
	  else
Packit 6c4009
	    *(ElfW(Addr) *) (got + 2)
Packit 6c4009
	      = (ElfW(Addr)) &_dl_runtime_resolve_fxsave;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (l->l_info[ADDRIDX (DT_TLSDESC_GOT)] && lazy)
Packit 6c4009
    *(ElfW(Addr)*)(D_PTR (l, l_info[ADDRIDX (DT_TLSDESC_GOT)]) + l->l_addr)
Packit 6c4009
      = (ElfW(Addr)) &_dl_tlsdesc_resolve_rela;
Packit 6c4009
Packit 6c4009
  return lazy;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Initial entry point code for the dynamic linker.
Packit 6c4009
   The C function `_dl_start' is the real entry point;
Packit 6c4009
   its return value is the user program's entry point.  */
Packit 6c4009
#define RTLD_START asm ("\n\
Packit 6c4009
.text\n\
Packit 6c4009
	.align 16\n\
Packit 6c4009
.globl _start\n\
Packit 6c4009
.globl _dl_start_user\n\
Packit 6c4009
_start:\n\
Packit 6c4009
	movq %rsp, %rdi\n\
Packit 6c4009
	call _dl_start\n\
Packit 6c4009
_dl_start_user:\n\
Packit 6c4009
	# Save the user entry point address in %r12.\n\
Packit 6c4009
	movq %rax, %r12\n\
Packit 6c4009
	# See if we were run as a command with the executable file\n\
Packit 6c4009
	# name as an extra leading argument.\n\
Packit 6c4009
	movl _dl_skip_args(%rip), %eax\n\
Packit 6c4009
	# Pop the original argument count.\n\
Packit 6c4009
	popq %rdx\n\
Packit 6c4009
	# Adjust the stack pointer to skip _dl_skip_args words.\n\
Packit 6c4009
	leaq (%rsp,%rax,8), %rsp\n\
Packit 6c4009
	# Subtract _dl_skip_args from argc.\n\
Packit 6c4009
	subl %eax, %edx\n\
Packit 6c4009
	# Push argc back on the stack.\n\
Packit 6c4009
	pushq %rdx\n\
Packit 6c4009
	# Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env)\n\
Packit 6c4009
	# argc -> rsi\n\
Packit 6c4009
	movq %rdx, %rsi\n\
Packit 6c4009
	# Save %rsp value in %r13.\n\
Packit 6c4009
	movq %rsp, %r13\n\
Packit 6c4009
	# And align stack for the _dl_init call. \n\
Packit 6c4009
	andq $-16, %rsp\n\
Packit 6c4009
	# _dl_loaded -> rdi\n\
Packit 6c4009
	movq _rtld_local(%rip), %rdi\n\
Packit 6c4009
	# env -> rcx\n\
Packit 6c4009
	leaq 16(%r13,%rdx,8), %rcx\n\
Packit 6c4009
	# argv -> rdx\n\
Packit 6c4009
	leaq 8(%r13), %rdx\n\
Packit 6c4009
	# Clear %rbp to mark outermost frame obviously even for constructors.\n\
Packit 6c4009
	xorl %ebp, %ebp\n\
Packit 6c4009
	# Call the function to run the initializers.\n\
Packit 6c4009
	call _dl_init\n\
Packit 6c4009
	# Pass our finalizer function to the user in %rdx, as per ELF ABI.\n\
Packit 6c4009
	leaq _dl_fini(%rip), %rdx\n\
Packit 6c4009
	# And make sure %rsp points to argc stored on the stack.\n\
Packit 6c4009
	movq %r13, %rsp\n\
Packit 6c4009
	# Jump to the user's entry point.\n\
Packit 6c4009
	jmp *%r12\n\
Packit 6c4009
.previous\n\
Packit 6c4009
");
Packit 6c4009
Packit 6c4009
/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
Packit 6c4009
   TLS variable, so undefined references should not be allowed to
Packit 6c4009
   define the value.
Packit 6c4009
   ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve to one
Packit 6c4009
   of the main executable's symbols, as for a COPY reloc.
Packit 6c4009
   ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA iff TYPE describes relocation may
Packit 6c4009
   against protected data whose address be external due to copy relocation.
Packit 6c4009
 */
Packit 6c4009
#define elf_machine_type_class(type)					      \
Packit 6c4009
  ((((type) == R_X86_64_JUMP_SLOT					      \
Packit 6c4009
     || (type) == R_X86_64_DTPMOD64					      \
Packit 6c4009
     || (type) == R_X86_64_DTPOFF64					      \
Packit 6c4009
     || (type) == R_X86_64_TPOFF64					      \
Packit 6c4009
     || (type) == R_X86_64_TLSDESC)					      \
Packit 6c4009
    * ELF_RTYPE_CLASS_PLT)						      \
Packit 6c4009
   | (((type) == R_X86_64_COPY) * ELF_RTYPE_CLASS_COPY)			      \
Packit 6c4009
   | (((type) == R_X86_64_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA))
Packit 6c4009
Packit 6c4009
/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
Packit 6c4009
#define ELF_MACHINE_JMP_SLOT	R_X86_64_JUMP_SLOT
Packit 6c4009
Packit 6c4009
/* The relative ifunc relocation.  */
Packit 6c4009
// XXX This is a work-around for a broken linker.  Remove!
Packit 6c4009
#define ELF_MACHINE_IRELATIVE	R_X86_64_IRELATIVE
Packit 6c4009
Packit 6c4009
/* The x86-64 never uses Elf64_Rel/Elf32_Rel relocations.  */
Packit 6c4009
#define ELF_MACHINE_NO_REL 1
Packit 6c4009
#define ELF_MACHINE_NO_RELA 0
Packit 6c4009
Packit 6c4009
/* We define an initialization function.  This is called very early in
Packit 6c4009
   _dl_sysdep_start.  */
Packit 6c4009
#define DL_PLATFORM_INIT dl_platform_init ()
Packit 6c4009
Packit 6c4009
static inline void __attribute__ ((unused))
Packit 6c4009
dl_platform_init (void)
Packit 6c4009
{
Packit 6c4009
#if IS_IN (rtld)
Packit Service 3b0880
  /* init_cpu_features has been called early from __libc_start_main in
Packit Service 3b0880
     static executable.  */
Packit Service 3b0880
  init_cpu_features (&GLRO(dl_x86_cpu_features));
Packit 6c4009
#else
Packit 6c4009
  if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
Packit 6c4009
    /* Avoid an empty string which would disturb us.  */
Packit 6c4009
    GLRO(dl_platform) = NULL;
Packit 6c4009
#endif
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static inline ElfW(Addr)
Packit 6c4009
elf_machine_fixup_plt (struct link_map *map, lookup_t t,
Packit 6c4009
		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
Packit 6c4009
		       const ElfW(Rela) *reloc,
Packit 6c4009
		       ElfW(Addr) *reloc_addr, ElfW(Addr) value)
Packit 6c4009
{
Packit 6c4009
  return *reloc_addr = value;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Return the final value of a PLT relocation.  On x86-64 the
Packit 6c4009
   JUMP_SLOT relocation ignores the addend.  */
Packit 6c4009
static inline ElfW(Addr)
Packit 6c4009
elf_machine_plt_value (struct link_map *map, const ElfW(Rela) *reloc,
Packit 6c4009
		       ElfW(Addr) value)
Packit 6c4009
{
Packit 6c4009
  return value;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Names of the architecture-specific auditing callback functions.  */
Packit 6c4009
#define ARCH_LA_PLTENTER x86_64_gnu_pltenter
Packit 6c4009
#define ARCH_LA_PLTEXIT x86_64_gnu_pltexit
Packit 6c4009
Packit 6c4009
#endif /* !dl_machine_h */
Packit 6c4009
Packit 6c4009
#ifdef RESOLVE_MAP
Packit 6c4009
Packit 6c4009
/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
Packit 6c4009
   MAP is the object containing the reloc.  */
Packit 6c4009
Packit 6c4009
auto inline void
Packit 6c4009
__attribute__ ((always_inline))
Packit 6c4009
elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
Packit 6c4009
		  const ElfW(Sym) *sym, const struct r_found_version *version,
Packit 6c4009
		  void *const reloc_addr_arg, int skip_ifunc)
Packit 6c4009
{
Packit 6c4009
  ElfW(Addr) *const reloc_addr = reloc_addr_arg;
Packit 6c4009
  const unsigned long int r_type = ELFW(R_TYPE) (reloc->r_info);
Packit 6c4009
Packit 6c4009
# if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
Packit 6c4009
  if (__glibc_unlikely (r_type == R_X86_64_RELATIVE))
Packit 6c4009
    {
Packit 6c4009
#  if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
Packit 6c4009
      /* This is defined in rtld.c, but nowhere in the static libc.a;
Packit 6c4009
	 make the reference weak so static programs can still link.
Packit 6c4009
	 This declaration cannot be done when compiling rtld.c
Packit 6c4009
	 (i.e. #ifdef RTLD_BOOTSTRAP) because rtld.c contains the
Packit 6c4009
	 common defn for _dl_rtld_map, which is incompatible with a
Packit 6c4009
	 weak decl in the same file.  */
Packit 6c4009
#   ifndef SHARED
Packit 6c4009
      weak_extern (GL(dl_rtld_map));
Packit 6c4009
#   endif
Packit 6c4009
      if (map != &GL(dl_rtld_map)) /* Already done in rtld itself.  */
Packit 6c4009
#  endif
Packit 6c4009
	*reloc_addr = map->l_addr + reloc->r_addend;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
# endif
Packit 6c4009
# if !defined RTLD_BOOTSTRAP
Packit 6c4009
  /* l_addr + r_addend may be > 0xffffffff and R_X86_64_RELATIVE64
Packit 6c4009
     relocation updates the whole 64-bit entry.  */
Packit 6c4009
  if (__glibc_unlikely (r_type == R_X86_64_RELATIVE64))
Packit 6c4009
    *(Elf64_Addr *) reloc_addr = (Elf64_Addr) map->l_addr + reloc->r_addend;
Packit 6c4009
  else
Packit 6c4009
# endif
Packit 6c4009
  if (__glibc_unlikely (r_type == R_X86_64_NONE))
Packit 6c4009
    return;
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
# ifndef RTLD_BOOTSTRAP
Packit 6c4009
      const ElfW(Sym) *const refsym = sym;
Packit 6c4009
# endif
Packit 6c4009
      struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
Packit 6c4009
      ElfW(Addr) value = SYMBOL_ADDRESS (sym_map, sym, true);
Packit 6c4009
Packit 6c4009
      if (sym != NULL
Packit 6c4009
	  && __glibc_unlikely (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC)
Packit 6c4009
	  && __glibc_likely (sym->st_shndx != SHN_UNDEF)
Packit 6c4009
	  && __glibc_likely (!skip_ifunc))
Packit 6c4009
	{
Packit 6c4009
# ifndef RTLD_BOOTSTRAP
Packit 6c4009
	  if (sym_map != map
Packit 6c4009
	      && sym_map->l_type != lt_executable
Packit 6c4009
	      && !sym_map->l_relocated)
Packit 6c4009
	    {
Packit 6c4009
	      const char *strtab
Packit 6c4009
		= (const char *) D_PTR (map, l_info[DT_STRTAB]);
Packit 6c4009
	      _dl_error_printf ("\
Packit 6c4009
%s: Relink `%s' with `%s' for IFUNC symbol `%s'\n",
Packit 6c4009
				RTLD_PROGNAME, map->l_name,
Packit 6c4009
				sym_map->l_name,
Packit 6c4009
				strtab + refsym->st_name);
Packit 6c4009
	    }
Packit 6c4009
# endif
Packit 6c4009
	  value = ((ElfW(Addr) (*) (void)) value) ();
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      switch (r_type)
Packit 6c4009
	{
Packit 6c4009
# ifndef RTLD_BOOTSTRAP
Packit 6c4009
#  ifdef __ILP32__
Packit 6c4009
	case R_X86_64_SIZE64:
Packit 6c4009
	  /* Set to symbol size plus addend.  */
Packit 6c4009
	  *(Elf64_Addr *) (uintptr_t) reloc_addr
Packit 6c4009
	    = (Elf64_Addr) sym->st_size + reloc->r_addend;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case R_X86_64_SIZE32:
Packit 6c4009
#  else
Packit 6c4009
	case R_X86_64_SIZE64:
Packit 6c4009
#  endif
Packit 6c4009
	  /* Set to symbol size plus addend.  */
Packit 6c4009
	  value = sym->st_size;
Packit 6c4009
# endif
Packit Service 5667b3
	  /* Fall through.  */
Packit 6c4009
	case R_X86_64_GLOB_DAT:
Packit 6c4009
	case R_X86_64_JUMP_SLOT:
Packit 6c4009
	  *reloc_addr = value + reloc->r_addend;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
# ifndef RESOLVE_CONFLICT_FIND_MAP
Packit 6c4009
	case R_X86_64_DTPMOD64:
Packit 6c4009
#  ifdef RTLD_BOOTSTRAP
Packit 6c4009
	  /* During startup the dynamic linker is always the module
Packit 6c4009
	     with index 1.
Packit 6c4009
	     XXX If this relocation is necessary move before RESOLVE
Packit 6c4009
	     call.  */
Packit 6c4009
	  *reloc_addr = 1;
Packit 6c4009
#  else
Packit 6c4009
	  /* Get the information from the link map returned by the
Packit 6c4009
	     resolve function.  */
Packit 6c4009
	  if (sym_map != NULL)
Packit 6c4009
	    *reloc_addr = sym_map->l_tls_modid;
Packit 6c4009
#  endif
Packit 6c4009
	  break;
Packit 6c4009
	case R_X86_64_DTPOFF64:
Packit 6c4009
#  ifndef RTLD_BOOTSTRAP
Packit 6c4009
	  /* During relocation all TLS symbols are defined and used.
Packit 6c4009
	     Therefore the offset is already correct.  */
Packit 6c4009
	  if (sym != NULL)
Packit 6c4009
	    {
Packit 6c4009
	      value = sym->st_value + reloc->r_addend;
Packit 6c4009
#   ifdef __ILP32__
Packit 6c4009
	      /* This relocation type computes a signed offset that is
Packit 6c4009
		 usually negative.  The symbol and addend values are 32
Packit 6c4009
		 bits but the GOT entry is 64 bits wide and the whole
Packit 6c4009
		 64-bit entry is used as a signed quantity, so we need
Packit 6c4009
		 to sign-extend the computed value to 64 bits.  */
Packit 6c4009
	      *(Elf64_Sxword *) reloc_addr = (Elf64_Sxword) (Elf32_Sword) value;
Packit 6c4009
#   else
Packit 6c4009
	      *reloc_addr = value;
Packit 6c4009
#   endif
Packit 6c4009
	    }
Packit 6c4009
#  endif
Packit 6c4009
	  break;
Packit 6c4009
	case R_X86_64_TLSDESC:
Packit 6c4009
	  {
Packit 6c4009
	    struct tlsdesc volatile *td =
Packit 6c4009
	      (struct tlsdesc volatile *)reloc_addr;
Packit 6c4009
Packit 6c4009
#  ifndef RTLD_BOOTSTRAP
Packit 6c4009
	    if (! sym)
Packit 6c4009
	      {
Packit 6c4009
		td->arg = (void*)reloc->r_addend;
Packit 6c4009
		td->entry = _dl_tlsdesc_undefweak;
Packit 6c4009
	      }
Packit 6c4009
	    else
Packit 6c4009
#  endif
Packit 6c4009
	      {
Packit 6c4009
#  ifndef RTLD_BOOTSTRAP
Packit 6c4009
#   ifndef SHARED
Packit 6c4009
		CHECK_STATIC_TLS (map, sym_map);
Packit 6c4009
#   else
Packit 6c4009
		if (!TRY_STATIC_TLS (map, sym_map))
Packit 6c4009
		  {
Packit 6c4009
		    td->arg = _dl_make_tlsdesc_dynamic
Packit 6c4009
		      (sym_map, sym->st_value + reloc->r_addend);
Packit 6c4009
		    td->entry = _dl_tlsdesc_dynamic;
Packit 6c4009
		  }
Packit 6c4009
		else
Packit 6c4009
#   endif
Packit 6c4009
#  endif
Packit 6c4009
		  {
Packit 6c4009
		    td->arg = (void*)(sym->st_value - sym_map->l_tls_offset
Packit 6c4009
				      + reloc->r_addend);
Packit 6c4009
		    td->entry = _dl_tlsdesc_return;
Packit 6c4009
		  }
Packit 6c4009
	      }
Packit 6c4009
	    break;
Packit 6c4009
	  }
Packit 6c4009
	case R_X86_64_TPOFF64:
Packit 6c4009
	  /* The offset is negative, forward from the thread pointer.  */
Packit 6c4009
#  ifndef RTLD_BOOTSTRAP
Packit 6c4009
	  if (sym != NULL)
Packit 6c4009
#  endif
Packit 6c4009
	    {
Packit 6c4009
#  ifndef RTLD_BOOTSTRAP
Packit 6c4009
	      CHECK_STATIC_TLS (map, sym_map);
Packit 6c4009
#  endif
Packit 6c4009
	      /* We know the offset of the object the symbol is contained in.
Packit 6c4009
		 It is a negative value which will be added to the
Packit 6c4009
		 thread pointer.  */
Packit 6c4009
	      value = (sym->st_value + reloc->r_addend
Packit 6c4009
		       - sym_map->l_tls_offset);
Packit 6c4009
#  ifdef __ILP32__
Packit 6c4009
	      /* The symbol and addend values are 32 bits but the GOT
Packit 6c4009
		 entry is 64 bits wide and the whole 64-bit entry is used
Packit 6c4009
		 as a signed quantity, so we need to sign-extend the
Packit 6c4009
		 computed value to 64 bits.  */
Packit 6c4009
	      *(Elf64_Sxword *) reloc_addr = (Elf64_Sxword) (Elf32_Sword) value;
Packit 6c4009
#  else
Packit 6c4009
	      *reloc_addr = value;
Packit 6c4009
#  endif
Packit 6c4009
	    }
Packit 6c4009
	  break;
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
# ifndef RTLD_BOOTSTRAP
Packit 6c4009
	case R_X86_64_64:
Packit 6c4009
	  /* value + r_addend may be > 0xffffffff and R_X86_64_64
Packit 6c4009
	     relocation updates the whole 64-bit entry.  */
Packit 6c4009
	  *(Elf64_Addr *) reloc_addr = (Elf64_Addr) value + reloc->r_addend;
Packit 6c4009
	  break;
Packit 6c4009
#  ifndef __ILP32__
Packit 6c4009
	case R_X86_64_SIZE32:
Packit 6c4009
	  /* Set to symbol size plus addend.  */
Packit 6c4009
	  value = sym->st_size;
Packit 6c4009
#  endif
Packit Service 5667b3
	  /* Fall through.  */
Packit 6c4009
	case R_X86_64_32:
Packit 6c4009
	  value += reloc->r_addend;
Packit 6c4009
	  *(unsigned int *) reloc_addr = value;
Packit 6c4009
Packit 6c4009
	  const char *fmt;
Packit 6c4009
	  if (__glibc_unlikely (value > UINT_MAX))
Packit 6c4009
	    {
Packit 6c4009
	      const char *strtab;
Packit 6c4009
Packit 6c4009
	      fmt = "\
Packit 6c4009
%s: Symbol `%s' causes overflow in R_X86_64_32 relocation\n";
Packit 6c4009
#  ifndef RESOLVE_CONFLICT_FIND_MAP
Packit 6c4009
	    print_err:
Packit 6c4009
#  endif
Packit 6c4009
	      strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
Packit 6c4009
Packit 6c4009
	      _dl_error_printf (fmt, RTLD_PROGNAME, strtab + refsym->st_name);
Packit 6c4009
	    }
Packit 6c4009
	  break;
Packit 6c4009
#  ifndef RESOLVE_CONFLICT_FIND_MAP
Packit 6c4009
	  /* Not needed for dl-conflict.c.  */
Packit 6c4009
	case R_X86_64_PC32:
Packit 6c4009
	  value += reloc->r_addend - (ElfW(Addr)) reloc_addr;
Packit 6c4009
	  *(unsigned int *) reloc_addr = value;
Packit 6c4009
	  if (__glibc_unlikely (value != (int) value))
Packit 6c4009
	    {
Packit 6c4009
	      fmt = "\
Packit 6c4009
%s: Symbol `%s' causes overflow in R_X86_64_PC32 relocation\n";
Packit 6c4009
	      goto print_err;
Packit 6c4009
	    }
Packit 6c4009
	  break;
Packit 6c4009
	case R_X86_64_COPY:
Packit 6c4009
	  if (sym == NULL)
Packit 6c4009
	    /* This can happen in trace mode if an object could not be
Packit 6c4009
	       found.  */
Packit 6c4009
	    break;
Packit 6c4009
	  memcpy (reloc_addr_arg, (void *) value,
Packit 6c4009
		  MIN (sym->st_size, refsym->st_size));
Packit 6c4009
	  if (__glibc_unlikely (sym->st_size > refsym->st_size)
Packit 6c4009
	      || (__glibc_unlikely (sym->st_size < refsym->st_size)
Packit 6c4009
		  && GLRO(dl_verbose)))
Packit 6c4009
	    {
Packit 6c4009
	      fmt = "\
Packit 6c4009
%s: Symbol `%s' has different size in shared object, consider re-linking\n";
Packit 6c4009
	      goto print_err;
Packit 6c4009
	    }
Packit 6c4009
	  break;
Packit 6c4009
#  endif
Packit 6c4009
	case R_X86_64_IRELATIVE:
Packit 6c4009
	  value = map->l_addr + reloc->r_addend;
Packit 6c4009
	  value = ((ElfW(Addr) (*) (void)) value) ();
Packit 6c4009
	  *reloc_addr = value;
Packit 6c4009
	  break;
Packit 6c4009
	default:
Packit 6c4009
	  _dl_reloc_bad_type (map, r_type, 0);
Packit 6c4009
	  break;
Packit 6c4009
# endif
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
auto inline void
Packit 6c4009
__attribute ((always_inline))
Packit 6c4009
elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
Packit 6c4009
			   void *const reloc_addr_arg)
Packit 6c4009
{
Packit 6c4009
  ElfW(Addr) *const reloc_addr = reloc_addr_arg;
Packit 6c4009
#if !defined RTLD_BOOTSTRAP
Packit 6c4009
  /* l_addr + r_addend may be > 0xffffffff and R_X86_64_RELATIVE64
Packit 6c4009
     relocation updates the whole 64-bit entry.  */
Packit 6c4009
  if (__glibc_unlikely (ELFW(R_TYPE) (reloc->r_info) == R_X86_64_RELATIVE64))
Packit 6c4009
    *(Elf64_Addr *) reloc_addr = (Elf64_Addr) l_addr + reloc->r_addend;
Packit 6c4009
  else
Packit 6c4009
#endif
Packit 6c4009
    {
Packit 6c4009
      assert (ELFW(R_TYPE) (reloc->r_info) == R_X86_64_RELATIVE);
Packit 6c4009
      *reloc_addr = l_addr + reloc->r_addend;
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
auto inline void
Packit 6c4009
__attribute ((always_inline))
Packit 6c4009
elf_machine_lazy_rel (struct link_map *map,
Packit 6c4009
		      ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
Packit 6c4009
		      int skip_ifunc)
Packit 6c4009
{
Packit 6c4009
  ElfW(Addr) *const reloc_addr = (void *) (l_addr + reloc->r_offset);
Packit 6c4009
  const unsigned long int r_type = ELFW(R_TYPE) (reloc->r_info);
Packit 6c4009
Packit 6c4009
  /* Check for unexpected PLT reloc type.  */
Packit 6c4009
  if (__glibc_likely (r_type == R_X86_64_JUMP_SLOT))
Packit 6c4009
    {
Packit 6c4009
      /* Prelink has been deprecated.  */
Packit 6c4009
      if (__glibc_likely (map->l_mach.plt == 0))
Packit 6c4009
	*reloc_addr += l_addr;
Packit 6c4009
      else
Packit 6c4009
	*reloc_addr =
Packit 6c4009
	  map->l_mach.plt
Packit 6c4009
	  + (((ElfW(Addr)) reloc_addr) - map->l_mach.gotplt) * 2;
Packit 6c4009
    }
Packit 6c4009
  else if (__glibc_likely (r_type == R_X86_64_TLSDESC))
Packit 6c4009
    {
Packit 6c4009
      struct tlsdesc volatile * __attribute__((__unused__)) td =
Packit 6c4009
	(struct tlsdesc volatile *)reloc_addr;
Packit 6c4009
Packit 6c4009
      td->arg = (void*)reloc;
Packit 6c4009
      td->entry = (void*)(D_PTR (map, l_info[ADDRIDX (DT_TLSDESC_PLT)])
Packit 6c4009
			  + map->l_addr);
Packit 6c4009
    }
Packit 6c4009
  else if (__glibc_unlikely (r_type == R_X86_64_IRELATIVE))
Packit 6c4009
    {
Packit 6c4009
      ElfW(Addr) value = map->l_addr + reloc->r_addend;
Packit 6c4009
      if (__glibc_likely (!skip_ifunc))
Packit 6c4009
	value = ((ElfW(Addr) (*) (void)) value) ();
Packit 6c4009
      *reloc_addr = value;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    _dl_reloc_bad_type (map, r_type, 1);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#endif /* RESOLVE_MAP */