Blame sysdeps/alpha/dl-machine.h

Packit 6c4009
/* Machine-dependent ELF dynamic relocation inline functions.  Alpha version.
Packit 6c4009
   Copyright (C) 1996-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Richard Henderson <rth@tamu.edu>.
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
/* This was written in the absence of an ABI -- don't expect
Packit 6c4009
   it to remain unchanged.  */
Packit 6c4009
Packit 6c4009
#ifndef dl_machine_h
Packit 6c4009
#define dl_machine_h 1
Packit 6c4009
Packit 6c4009
#define ELF_MACHINE_NAME "alpha"
Packit 6c4009
Packit 6c4009
#include <string.h>
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Mask identifying addresses reserved for the user program,
Packit 6c4009
   where the dynamic linker should not map anything.  */
Packit 6c4009
#define ELF_MACHINE_USER_ADDRESS_MASK	0x120000000UL
Packit 6c4009
Packit 6c4009
/* Translate a processor specific dynamic tag to the index in l_info array.  */
Packit 6c4009
#define DT_ALPHA(x) (DT_ALPHA_##x - DT_LOPROC + DT_NUM)
Packit 6c4009
Packit 6c4009
/* Return nonzero iff ELF header is compatible with the running host.  */
Packit 6c4009
static inline int
Packit 6c4009
elf_machine_matches_host (const Elf64_Ehdr *ehdr)
Packit 6c4009
{
Packit 6c4009
  return ehdr->e_machine == EM_ALPHA;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Return the link-time address of _DYNAMIC.  The multiple-got-capable
Packit 6c4009
   linker no longer allocates the first .got entry for this.  But not to
Packit 6c4009
   worry, no special tricks are needed.  */
Packit 6c4009
static inline Elf64_Addr
Packit 6c4009
elf_machine_dynamic (void)
Packit 6c4009
{
Packit 6c4009
#ifndef NO_AXP_MULTI_GOT_LD
Packit 6c4009
  return (Elf64_Addr) &_DYNAMIC;
Packit 6c4009
#else
Packit 6c4009
  register Elf64_Addr *gp __asm__ ("$29");
Packit 6c4009
  return gp[-4096];
Packit 6c4009
#endif
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Return the run-time load address of the shared object.  */
Packit 6c4009
Packit 6c4009
static inline Elf64_Addr
Packit 6c4009
elf_machine_load_address (void)
Packit 6c4009
{
Packit 6c4009
  /* This relies on the compiler using gp-relative addresses for static symbols.  */
Packit 6c4009
  static void *dot = ˙
Packit 6c4009
  return (void *)&dot - dot;
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
Packit 6c4009
elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
Packit 6c4009
{
Packit 6c4009
  extern char _dl_runtime_resolve_new[] attribute_hidden;
Packit 6c4009
  extern char _dl_runtime_profile_new[] attribute_hidden;
Packit 6c4009
  extern char _dl_runtime_resolve_old[] attribute_hidden;
Packit 6c4009
  extern char _dl_runtime_profile_old[] attribute_hidden;
Packit 6c4009
Packit 6c4009
  struct pltgot {
Packit 6c4009
    char *resolve;
Packit 6c4009
    struct link_map *link;
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
  struct pltgot *pg;
Packit 6c4009
  long secureplt;
Packit 6c4009
  char *resolve;
Packit 6c4009
Packit 6c4009
  if (map->l_info[DT_JMPREL] == 0 || !lazy)
Packit 6c4009
    return lazy;
Packit 6c4009
Packit 6c4009
  /* Check to see if we're using the read-only plt form.  */
Packit 6c4009
  secureplt = map->l_info[DT_ALPHA(PLTRO)] != 0;
Packit 6c4009
Packit 6c4009
  /* If the binary uses the read-only secure plt format, PG points to
Packit 6c4009
     the .got.plt section, which is the right place for ld.so to place
Packit 6c4009
     its hooks.  Otherwise, PG is currently pointing at the start of
Packit 6c4009
     the plt; the hooks go at offset 16.  */
Packit 6c4009
  pg = (struct pltgot *) D_PTR (map, l_info[DT_PLTGOT]);
Packit 6c4009
  pg += !secureplt;
Packit 6c4009
Packit 6c4009
  /* This function will be called to perform the relocation.  They're
Packit 6c4009
     not declared as functions to convince the compiler to use gp
Packit 6c4009
     relative relocations for them.  */
Packit 6c4009
  if (secureplt)
Packit 6c4009
    resolve = _dl_runtime_resolve_new;
Packit 6c4009
  else
Packit 6c4009
    resolve = _dl_runtime_resolve_old;
Packit 6c4009
Packit 6c4009
  if (__builtin_expect (profile, 0))
Packit 6c4009
    {
Packit 6c4009
      if (secureplt)
Packit 6c4009
	resolve = _dl_runtime_profile_new;
Packit 6c4009
      else
Packit 6c4009
	resolve = _dl_runtime_profile_old;
Packit 6c4009
Packit 6c4009
      if (GLRO(dl_profile) && _dl_name_match_p (GLRO(dl_profile), map))
Packit 6c4009
	{
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) = map;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  pg->resolve = resolve;
Packit 6c4009
  pg->link = map;
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
Packit 6c4009
#define RTLD_START asm ("\
Packit 6c4009
	.section .text						\n\
Packit 6c4009
	.set at							\n\
Packit 6c4009
	.globl _start						\n\
Packit 6c4009
	.ent _start						\n\
Packit 6c4009
_start:								\n\
Packit 6c4009
	.frame $31,0,$31,0					\n\
Packit 6c4009
	br	$gp, 0f						\n\
Packit 6c4009
0:	ldgp	$gp, 0($gp)					\n\
Packit 6c4009
	.prologue 0						\n\
Packit 6c4009
	/* Pass pointer to argument block to _dl_start.  */	\n\
Packit 6c4009
	mov	$sp, $16					\n\
Packit 6c4009
	bsr	$26, _dl_start		!samegp			\n\
Packit 6c4009
	.end _start						\n\
Packit 6c4009
	/* FALLTHRU */						\n\
Packit 6c4009
	.globl _dl_start_user					\n\
Packit 6c4009
	.ent _dl_start_user					\n\
Packit 6c4009
_dl_start_user:							\n\
Packit 6c4009
	.frame $31,0,$31,0					\n\
Packit 6c4009
	.prologue 0						\n\
Packit 6c4009
	/* Save the user entry point address in s0.  */		\n\
Packit 6c4009
	mov	$0, $9						\n\
Packit 6c4009
	/* See if we were run as a command with the executable	\n\
Packit 6c4009
	   file name as an extra leading argument.  */		\n\
Packit 6c4009
	ldah	$1, _dl_skip_args($gp)	!gprelhigh		\n\
Packit 6c4009
	ldl	$1, _dl_skip_args($1)	!gprellow		\n\
Packit 6c4009
	bne	$1, $fixup_stack				\n\
Packit 6c4009
$fixup_stack_ret:						\n\
Packit 6c4009
	/* The special initializer gets called with the stack	\n\
Packit 6c4009
	   just as the application's entry point will see it;	\n\
Packit 6c4009
	   it can switch stacks if it moves these contents	\n\
Packit 6c4009
	   over.  */						\n\
Packit 6c4009
" RTLD_START_SPECIAL_INIT "					\n\
Packit 6c4009
	/* Call _dl_init(_dl_loaded, argc, argv, envp) to run	\n\
Packit 6c4009
	   initializers.  */					\n\
Packit 6c4009
	ldah	$16, _rtld_local($gp)	!gprelhigh		\n\
Packit 6c4009
	ldq	$16, _rtld_local($16)	!gprellow		\n\
Packit 6c4009
	ldq	$17, 0($sp)					\n\
Packit 6c4009
	lda	$18, 8($sp)					\n\
Packit 6c4009
	s8addq	$17, 8, $19					\n\
Packit 6c4009
	addq	$19, $18, $19					\n\
Packit 6c4009
	bsr	$26, _dl_init		!samegp			\n\
Packit 6c4009
	/* Pass our finalizer function to the user in $0. */	\n\
Packit 6c4009
	ldah	$0, _dl_fini($gp)	!gprelhigh		\n\
Packit 6c4009
	lda	$0, _dl_fini($0)	!gprellow		\n\
Packit 6c4009
	/* Jump to the user's entry point.  */			\n\
Packit 6c4009
	mov	$9, $27						\n\
Packit 6c4009
	jmp	($9)						\n\
Packit 6c4009
$fixup_stack:							\n\
Packit 6c4009
	/* Adjust the stack pointer to skip _dl_skip_args words.\n\
Packit 6c4009
	   This involves copying everything down, since the	\n\
Packit 6c4009
	   stack pointer must always be 16-byte aligned.  */	\n\
Packit 6c4009
	ldah	$7, __GI__dl_argv($gp) !gprelhigh		\n\
Packit 6c4009
	ldq	$2, 0($sp)					\n\
Packit 6c4009
	ldq	$5, __GI__dl_argv($7) !gprellow			\n\
Packit 6c4009
	subq	$31, $1, $6					\n\
Packit 6c4009
	subq	$2, $1, $2					\n\
Packit 6c4009
	s8addq	$6, $5, $5					\n\
Packit 6c4009
	mov	$sp, $4						\n\
Packit 6c4009
	s8addq	$1, $sp, $3					\n\
Packit 6c4009
	stq	$2, 0($sp)					\n\
Packit 6c4009
	stq	$5, __GI__dl_argv($7) !gprellow			\n\
Packit 6c4009
	/* Copy down argv.  */					\n\
Packit 6c4009
0:	ldq	$5, 8($3)					\n\
Packit 6c4009
	addq	$4, 8, $4					\n\
Packit 6c4009
	addq	$3, 8, $3					\n\
Packit 6c4009
	stq	$5, 0($4)					\n\
Packit 6c4009
	bne	$5, 0b						\n\
Packit 6c4009
	/* Copy down envp.  */					\n\
Packit 6c4009
1:	ldq	$5, 8($3)					\n\
Packit 6c4009
	addq	$4, 8, $4					\n\
Packit 6c4009
	addq	$3, 8, $3					\n\
Packit 6c4009
	stq	$5, 0($4)					\n\
Packit 6c4009
	bne	$5, 1b						\n\
Packit 6c4009
	/* Copy down auxiliary table.  */			\n\
Packit 6c4009
2:	ldq	$5, 8($3)					\n\
Packit 6c4009
	ldq	$6, 16($3)					\n\
Packit 6c4009
	addq	$4, 16, $4					\n\
Packit 6c4009
	addq	$3, 16, $3					\n\
Packit 6c4009
	stq	$5, -8($4)					\n\
Packit 6c4009
	stq	$6, 0($4)					\n\
Packit 6c4009
	bne	$5, 2b						\n\
Packit 6c4009
	br	$fixup_stack_ret				\n\
Packit 6c4009
	.end _dl_start_user					\n\
Packit 6c4009
	.set noat						\n\
Packit 6c4009
.previous");
Packit 6c4009
Packit 6c4009
#ifndef RTLD_START_SPECIAL_INIT
Packit 6c4009
#define RTLD_START_SPECIAL_INIT /* nothing */
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry
Packit 6c4009
   or TLS variables, so undefined references should not be allowed
Packit 6c4009
   to define the value.
Packit 6c4009
Packit 6c4009
   ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve
Packit 6c4009
   to one of the main executable's symbols, as for a COPY reloc.
Packit 6c4009
   This is unused on Alpha.  */
Packit 6c4009
Packit 6c4009
# define elf_machine_type_class(type)	\
Packit 6c4009
  (((type) == R_ALPHA_JMP_SLOT		\
Packit 6c4009
    || (type) == R_ALPHA_DTPMOD64	\
Packit 6c4009
    || (type) == R_ALPHA_DTPREL64	\
Packit 6c4009
    || (type) == R_ALPHA_TPREL64) * ELF_RTYPE_CLASS_PLT)
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_ALPHA_JMP_SLOT
Packit 6c4009
Packit 6c4009
/* The alpha never uses Elf64_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 functions.  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 (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
}
Packit 6c4009
Packit 6c4009
/* Fix up the instructions of a PLT entry to invoke the function
Packit 6c4009
   rather than the dynamic linker.  */
Packit 6c4009
static inline Elf64_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 Elf64_Rela *reloc,
Packit 6c4009
		       Elf64_Addr *got_addr, Elf64_Addr value)
Packit 6c4009
{
Packit 6c4009
  const Elf64_Rela *rela_plt;
Packit 6c4009
  Elf64_Word *plte;
Packit 6c4009
  long int edisp;
Packit 6c4009
Packit 6c4009
  /* Store the value we are going to load.  */
Packit 6c4009
  *got_addr = value;
Packit 6c4009
Packit 6c4009
  /* If this binary uses the read-only secure plt format, we're done.  */
Packit 6c4009
  if (map->l_info[DT_ALPHA(PLTRO)])
Packit 6c4009
    return value;
Packit 6c4009
Packit 6c4009
  /* Otherwise we have to modify the plt entry in place to do the branch.  */
Packit 6c4009
Packit 6c4009
  /* Recover the PLT entry address by calculating reloc's index into the
Packit 6c4009
     .rela.plt, and finding that entry in the .plt.  */
Packit 6c4009
  rela_plt = (const Elf64_Rela *) D_PTR (map, l_info[DT_JMPREL]);
Packit 6c4009
  plte = (Elf64_Word *) (D_PTR (map, l_info[DT_PLTGOT]) + 32);
Packit 6c4009
  plte += 3 * (reloc - rela_plt);
Packit 6c4009
Packit 6c4009
  /* Find the displacement from the plt entry to the function.  */
Packit 6c4009
  edisp = (long int) (value - (Elf64_Addr)&plte[3]) / 4;
Packit 6c4009
Packit 6c4009
  if (edisp >= -0x100000 && edisp < 0x100000)
Packit 6c4009
    {
Packit 6c4009
      /* If we are in range, use br to perfect branch prediction and
Packit 6c4009
	 elide the dependency on the address load.  This case happens,
Packit 6c4009
	 e.g., when a shared library call is resolved to the same library.  */
Packit 6c4009
Packit 6c4009
      int hi, lo;
Packit 6c4009
      hi = value - (Elf64_Addr)&plte[0];
Packit 6c4009
      lo = (short int) hi;
Packit 6c4009
      hi = (hi - lo) >> 16;
Packit 6c4009
Packit 6c4009
      /* Emit "lda $27,lo($27)" */
Packit 6c4009
      plte[1] = 0x237b0000 | (lo & 0xffff);
Packit 6c4009
Packit 6c4009
      /* Emit "br $31,function" */
Packit 6c4009
      plte[2] = 0xc3e00000 | (edisp & 0x1fffff);
Packit 6c4009
Packit 6c4009
      /* Think about thread-safety -- the previous instructions must be
Packit 6c4009
	 committed to memory before the first is overwritten.  */
Packit 6c4009
      __asm__ __volatile__("wmb" : : : "memory");
Packit 6c4009
Packit 6c4009
      /* Emit "ldah $27,hi($27)" */
Packit 6c4009
      plte[0] = 0x277b0000 | (hi & 0xffff);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      /* Don't bother with the hint since we already know the hint is
Packit 6c4009
	 wrong.  Eliding it prevents the wrong page from getting pulled
Packit 6c4009
	 into the cache.  */
Packit 6c4009
Packit 6c4009
      int hi, lo;
Packit 6c4009
      hi = (Elf64_Addr)got_addr - (Elf64_Addr)&plte[0];
Packit 6c4009
      lo = (short)hi;
Packit 6c4009
      hi = (hi - lo) >> 16;
Packit 6c4009
Packit 6c4009
      /* Emit "ldq $27,lo($27)" */
Packit 6c4009
      plte[1] = 0xa77b0000 | (lo & 0xffff);
Packit 6c4009
Packit 6c4009
      /* Emit "jmp $31,($27)" */
Packit 6c4009
      plte[2] = 0x6bfb0000;
Packit 6c4009
Packit 6c4009
      /* Think about thread-safety -- the previous instructions must be
Packit 6c4009
	 committed to memory before the first is overwritten.  */
Packit 6c4009
      __asm__ __volatile__("wmb" : : : "memory");
Packit 6c4009
Packit 6c4009
      /* Emit "ldah $27,hi($27)" */
Packit 6c4009
      plte[0] = 0x277b0000 | (hi & 0xffff);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* At this point, if we've been doing runtime resolution, Icache is dirty.
Packit 6c4009
     This will be taken care of in _dl_runtime_resolve.  If instead we are
Packit 6c4009
     doing this as part of non-lazy startup relocation, that bit of code
Packit 6c4009
     hasn't made it into Icache yet, so there's nothing to clean up.  */
Packit 6c4009
Packit 6c4009
  return value;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Return the final value of a plt relocation.  */
Packit 6c4009
static inline Elf64_Addr
Packit 6c4009
elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
Packit 6c4009
		       Elf64_Addr value)
Packit 6c4009
{
Packit 6c4009
  return value + reloc->r_addend;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Names of the architecture-specific auditing callback functions.  */
Packit 6c4009
#define ARCH_LA_PLTENTER	alpha_gnu_pltenter
Packit 6c4009
#define ARCH_LA_PLTEXIT		alpha_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
auto inline void
Packit 6c4009
__attribute__ ((always_inline))
Packit 6c4009
elf_machine_rela (struct link_map *map,
Packit 6c4009
		  const Elf64_Rela *reloc,
Packit 6c4009
		  const Elf64_Sym *sym,
Packit 6c4009
		  const struct r_found_version *version,
Packit 6c4009
		  void *const reloc_addr_arg,
Packit 6c4009
		  int skip_ifunc)
Packit 6c4009
{
Packit 6c4009
  Elf64_Addr *const reloc_addr = reloc_addr_arg;
Packit 6c4009
  unsigned long int const r_type = ELF64_R_TYPE (reloc->r_info);
Packit 6c4009
Packit 6c4009
#if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC && !defined SHARED
Packit 6c4009
  /* This is defined in rtld.c, but nowhere in the static libc.a; make the
Packit 6c4009
     reference weak so static programs can still link.  This declaration
Packit 6c4009
     cannot be done when compiling rtld.c (i.e.  #ifdef RTLD_BOOTSTRAP)
Packit 6c4009
     because rtld.c contains the common defn for _dl_rtld_map, which is
Packit 6c4009
     incompatible with a weak decl in the same file.  */
Packit 6c4009
  weak_extern (_dl_rtld_map);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  /* We cannot use a switch here because we cannot locate the switch
Packit 6c4009
     jump table until we've self-relocated.  */
Packit 6c4009
Packit 6c4009
#if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
Packit 6c4009
  if (__builtin_expect (r_type == R_ALPHA_RELATIVE, 0))
Packit 6c4009
    {
Packit 6c4009
# if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
Packit 6c4009
      /* Already done in dynamic linker.  */
Packit 6c4009
      if (map != &GL(dl_rtld_map))
Packit 6c4009
# endif
Packit 6c4009
	{
Packit 6c4009
	  /* XXX Make some timings.  Maybe it's preferable to test for
Packit 6c4009
	     unaligned access and only do it the complex way if necessary.  */
Packit 6c4009
	  Elf64_Addr reloc_addr_val;
Packit 6c4009
Packit 6c4009
	  /* Load value without causing unaligned trap. */
Packit 6c4009
	  memcpy (&reloc_addr_val, reloc_addr_arg, 8);
Packit 6c4009
	  reloc_addr_val += map->l_addr;
Packit 6c4009
Packit 6c4009
	  /* Store value without causing unaligned trap. */
Packit 6c4009
	  memcpy (reloc_addr_arg, &reloc_addr_val, 8);
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
#endif
Packit 6c4009
    if (__builtin_expect (r_type == R_ALPHA_NONE, 0))
Packit 6c4009
      return;
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
Packit 6c4009
      Elf64_Addr sym_value;
Packit 6c4009
      Elf64_Addr sym_raw_value;
Packit 6c4009
Packit 6c4009
      sym_raw_value = sym_value = reloc->r_addend;
Packit 6c4009
      if (sym_map)
Packit 6c4009
	{
Packit 6c4009
	  sym_raw_value += sym->st_value;
Packit 6c4009
	  sym_value += SYMBOL_ADDRESS (sym_map, sym, true);
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (r_type == R_ALPHA_GLOB_DAT)
Packit 6c4009
	*reloc_addr = sym_value;
Packit 6c4009
#ifdef RESOLVE_CONFLICT_FIND_MAP
Packit 6c4009
      /* In .gnu.conflict section, R_ALPHA_JMP_SLOT relocations have
Packit 6c4009
	 R_ALPHA_JMP_SLOT in lower 8 bits and the remaining 24 bits
Packit 6c4009
	 are .rela.plt index.  */
Packit 6c4009
      else if ((r_type & 0xff) == R_ALPHA_JMP_SLOT)
Packit 6c4009
	{
Packit 6c4009
	  /* elf_machine_fixup_plt needs the map reloc_addr points into,
Packit 6c4009
	     while in _dl_resolve_conflicts map is _dl_loaded.  */
Packit 6c4009
	  RESOLVE_CONFLICT_FIND_MAP (map, reloc_addr);
Packit 6c4009
	  reloc = ((const Elf64_Rela *) D_PTR (map, l_info[DT_JMPREL]))
Packit 6c4009
		  + (r_type >> 8);
Packit 6c4009
	  elf_machine_fixup_plt (map, 0, 0, 0, reloc, reloc_addr, sym_value);
Packit 6c4009
	}
Packit 6c4009
#else
Packit 6c4009
      else if (r_type == R_ALPHA_JMP_SLOT)
Packit 6c4009
	elf_machine_fixup_plt (map, 0, 0, 0, reloc, reloc_addr, sym_value);
Packit 6c4009
#endif
Packit 6c4009
#ifndef RTLD_BOOTSTRAP
Packit 6c4009
      else if (r_type == R_ALPHA_REFQUAD)
Packit 6c4009
	{
Packit 6c4009
	  /* Store value without causing unaligned trap.  */
Packit 6c4009
	  memcpy (reloc_addr_arg, &sym_value, 8);
Packit 6c4009
	}
Packit 6c4009
#endif
Packit 6c4009
      else if (r_type == R_ALPHA_DTPMOD64)
Packit 6c4009
	{
Packit 6c4009
# ifdef RTLD_BOOTSTRAP
Packit 6c4009
	  /* During startup the dynamic linker is always index 1.  */
Packit 6c4009
	  *reloc_addr = 1;
Packit 6c4009
# else
Packit 6c4009
	  /* Get the information from the link map returned by the
Packit 6c4009
	     resolv function.  */
Packit 6c4009
	  if (sym_map != NULL)
Packit 6c4009
	    *reloc_addr = sym_map->l_tls_modid;
Packit 6c4009
# endif
Packit 6c4009
	}
Packit 6c4009
      else if (r_type == R_ALPHA_DTPREL64)
Packit 6c4009
	{
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
	  *reloc_addr = sym_raw_value;
Packit 6c4009
# endif
Packit 6c4009
	}
Packit 6c4009
      else if (r_type == R_ALPHA_TPREL64)
Packit 6c4009
	{
Packit 6c4009
# ifdef RTLD_BOOTSTRAP
Packit 6c4009
	  *reloc_addr = sym_raw_value + map->l_tls_offset;
Packit 6c4009
# else
Packit 6c4009
	  if (sym_map)
Packit 6c4009
	    {
Packit 6c4009
	      CHECK_STATIC_TLS (map, sym_map);
Packit 6c4009
	      *reloc_addr = sym_raw_value + sym_map->l_tls_offset;
Packit 6c4009
	    }
Packit 6c4009
# endif
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	_dl_reloc_bad_type (map, r_type, 0);
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Let do-rel.h know that on Alpha if l_addr is 0, all RELATIVE relocs
Packit 6c4009
   can be skipped.  */
Packit 6c4009
#define ELF_MACHINE_REL_RELATIVE 1
Packit 6c4009
Packit 6c4009
auto inline void
Packit 6c4009
__attribute__ ((always_inline))
Packit 6c4009
elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
Packit 6c4009
			   void *const reloc_addr_arg)
Packit 6c4009
{
Packit 6c4009
  /* XXX Make some timings.  Maybe it's preferable to test for
Packit 6c4009
     unaligned access and only do it the complex way if necessary.  */
Packit 6c4009
  Elf64_Addr reloc_addr_val;
Packit 6c4009
Packit 6c4009
  /* Load value without causing unaligned trap. */
Packit 6c4009
  memcpy (&reloc_addr_val, reloc_addr_arg, 8);
Packit 6c4009
  reloc_addr_val += l_addr;
Packit 6c4009
Packit 6c4009
  /* Store value without causing unaligned trap. */
Packit 6c4009
  memcpy (reloc_addr_arg, &reloc_addr_val, 8);
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
		      Elf64_Addr l_addr, const Elf64_Rela *reloc,
Packit 6c4009
		      int skip_ifunc)
Packit 6c4009
{
Packit 6c4009
  Elf64_Addr * const reloc_addr = (void *)(l_addr + reloc->r_offset);
Packit 6c4009
  unsigned long int const r_type = ELF64_R_TYPE (reloc->r_info);
Packit 6c4009
Packit 6c4009
  if (r_type == R_ALPHA_JMP_SLOT)
Packit 6c4009
    {
Packit 6c4009
      /* Perform a RELATIVE reloc on the .got entry that transfers
Packit 6c4009
	 to the .plt.  */
Packit 6c4009
      *reloc_addr += l_addr;
Packit 6c4009
    }
Packit 6c4009
  else if (r_type == R_ALPHA_NONE)
Packit 6c4009
    return;
Packit 6c4009
  else
Packit 6c4009
    _dl_reloc_bad_type (map, r_type, 1);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#endif /* RESOLVE_MAP */