Blame sysdeps/sparc/sparc32/dl-machine.h

Packit 6c4009
/* Machine-dependent ELF dynamic relocation inline functions.  SPARC version.
Packit 6c4009
   Copyright (C) 1996-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
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 "sparc"
Packit 6c4009
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <sys/param.h>
Packit 6c4009
#include <ldsodefs.h>
Packit 6c4009
#include <sysdep.h>
Packit 6c4009
#include <tls.h>
Packit 6c4009
#include <dl-plt.h>
Packit 6c4009
#include <elf/dl-hwcaps.h>
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 Elf32_Ehdr *ehdr)
Packit 6c4009
{
Packit 6c4009
  if (ehdr->e_machine == EM_SPARC)
Packit 6c4009
    return 1;
Packit 6c4009
  else if (ehdr->e_machine == EM_SPARC32PLUS)
Packit 6c4009
    {
Packit 6c4009
#if HAVE_TUNABLES || defined SHARED
Packit 6c4009
      uint64_t hwcap_mask = GET_HWCAP_MASK();
Packit 6c4009
      return GLRO(dl_hwcap) & hwcap_mask & HWCAP_SPARC_V9;
Packit 6c4009
#else
Packit 6c4009
      return GLRO(dl_hwcap) & HWCAP_SPARC_V9;
Packit 6c4009
#endif
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* We have to do this because elf_machine_{dynamic,load_address} can be
Packit 6c4009
   invoked from functions that have no GOT references, and thus the compiler
Packit 6c4009
   has no obligation to load the PIC register.  */
Packit 6c4009
#define LOAD_PIC_REG(PIC_REG)	\
Packit 6c4009
do {	register Elf32_Addr pc __asm("o7"); \
Packit 6c4009
	__asm("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t" \
Packit 6c4009
	      "call 1f\n\t" \
Packit 6c4009
	      "add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n" \
Packit 6c4009
	      "1:\tadd %1, %0, %1" \
Packit 6c4009
	      : "=r" (pc), "=r" (PIC_REG)); \
Packit 6c4009
} while (0)
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 Elf32_Addr
Packit 6c4009
elf_machine_dynamic (void)
Packit 6c4009
{
Packit 6c4009
  register Elf32_Addr *got asm ("%l7");
Packit 6c4009
Packit 6c4009
  LOAD_PIC_REG (got);
Packit 6c4009
Packit 6c4009
  return *got;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Return the run-time load address of the shared object.  */
Packit 6c4009
static inline Elf32_Addr
Packit 6c4009
elf_machine_load_address (void)
Packit 6c4009
{
Packit 6c4009
  register Elf32_Addr *pc __asm ("%o7"), *got __asm ("%l7");
Packit 6c4009
Packit 6c4009
  __asm ("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t"
Packit 6c4009
	 "call 1f\n\t"
Packit 6c4009
	 " add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n\t"
Packit 6c4009
	 "call _DYNAMIC\n\t"
Packit 6c4009
	 "call _GLOBAL_OFFSET_TABLE_\n"
Packit 6c4009
	 "1:\tadd %1, %0, %1\n\t" : "=r" (pc), "=r" (got));
Packit 6c4009
Packit 6c4009
  /* got is now l_addr + _GLOBAL_OFFSET_TABLE_
Packit 6c4009
     *got is _DYNAMIC
Packit 6c4009
     pc[2]*4 is l_addr + _DYNAMIC - (long)pc - 8
Packit 6c4009
     pc[3]*4 is l_addr + _GLOBAL_OFFSET_TABLE_ - (long)pc - 12  */
Packit 6c4009
  return (Elf32_Addr) got - *got + (pc[2] - pc[3]) * 4 - 4;
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 *l, int lazy, int profile)
Packit 6c4009
{
Packit 6c4009
  Elf32_Addr *plt;
Packit 6c4009
  extern void _dl_runtime_resolve (Elf32_Word);
Packit 6c4009
  extern void _dl_runtime_profile (Elf32_Word);
Packit 6c4009
Packit 6c4009
  if (l->l_info[DT_JMPREL] && lazy)
Packit 6c4009
    {
Packit 6c4009
      Elf32_Addr rfunc;
Packit 6c4009
Packit 6c4009
      /* The entries for functions in the PLT have not yet been filled in.
Packit 6c4009
	 Their initial contents will arrange when called to set the high 22
Packit 6c4009
	 bits of %g1 with an offset into the .rela.plt section and jump to
Packit 6c4009
	 the beginning of the PLT.  */
Packit 6c4009
      plt = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
Packit 6c4009
      if (__builtin_expect(profile, 0))
Packit 6c4009
	{
Packit 6c4009
	  rfunc = (Elf32_Addr) &_dl_runtime_profile;
Packit 6c4009
Packit 6c4009
	  if (GLRO(dl_profile) != NULL
Packit 6c4009
	      && _dl_name_match_p (GLRO(dl_profile), l))
Packit 6c4009
	    GL(dl_profile_map) = l;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  rfunc = (Elf32_Addr) &_dl_runtime_resolve;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* The beginning of the PLT does:
Packit 6c4009
Packit 6c4009
		sethi %hi(_dl_runtime_{resolve,profile}), %g2
Packit 6c4009
	 pltpc:	jmpl %g2 + %lo(_dl_runtime_{resolve,profile}), %g2
Packit 6c4009
		 nop
Packit 6c4009
		.word MAP
Packit 6c4009
Packit 6c4009
	 The PC value (pltpc) saved in %g2 by the jmpl points near the
Packit 6c4009
	 location where we store the link_map pointer for this object.  */
Packit 6c4009
Packit 6c4009
      plt[0] = 0x05000000 | ((rfunc >> 10) & 0x003fffff);
Packit 6c4009
      plt[1] = 0x85c0a000 | (rfunc & 0x3ff);
Packit 6c4009
      plt[2] = OPCODE_NOP;	/* Fill call delay slot.  */
Packit 6c4009
      plt[3] = (Elf32_Addr) l;
Packit 6c4009
      if (__builtin_expect (l->l_info[VALIDX(DT_GNU_PRELINKED)] != NULL, 0)
Packit 6c4009
	  || __builtin_expect (l->l_info [VALIDX (DT_GNU_LIBLISTSZ)] != NULL, 0))
Packit 6c4009
	{
Packit 6c4009
	  /* Need to reinitialize .plt to undo prelinking.  */
Packit 6c4009
	  Elf32_Rela *rela = (Elf32_Rela *) D_PTR (l, l_info[DT_JMPREL]);
Packit 6c4009
	  Elf32_Rela *relaend
Packit 6c4009
	    = (Elf32_Rela *) ((char *) rela
Packit 6c4009
			      + l->l_info[DT_PLTRELSZ]->d_un.d_val);
Packit 6c4009
#if !defined RTLD_BOOTSTRAP && !defined __sparc_v9__
Packit 6c4009
	  /* Note that we don't mask the hwcap here, as the flush is
Packit 6c4009
	     essential to functionality on those cpu's that implement it.
Packit 6c4009
	     For sparcv9 we can assume flush is present.  */
Packit 6c4009
	  const int do_flush = GLRO(dl_hwcap) & HWCAP_SPARC_FLUSH;
Packit 6c4009
#else
Packit 6c4009
	  const int do_flush = 1;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	  /* prelink must ensure there are no R_SPARC_NONE relocs left
Packit 6c4009
	     in .rela.plt.  */
Packit 6c4009
	  while (rela < relaend)
Packit 6c4009
	    {
Packit 6c4009
	      *(unsigned int *) (rela->r_offset + l->l_addr)
Packit 6c4009
		= OPCODE_SETHI_G1 | (rela->r_offset + l->l_addr
Packit 6c4009
				     - (Elf32_Addr) plt);
Packit 6c4009
	      *(unsigned int *) (rela->r_offset + l->l_addr + 4)
Packit 6c4009
		= OPCODE_BA | ((((Elf32_Addr) plt
Packit 6c4009
				 - rela->r_offset - l->l_addr - 4) >> 2)
Packit 6c4009
			       & 0x3fffff);
Packit 6c4009
	      if (do_flush)
Packit 6c4009
		{
Packit 6c4009
		  __asm __volatile ("flush %0" : : "r" (rela->r_offset
Packit 6c4009
							+ l->l_addr));
Packit 6c4009
		  __asm __volatile ("flush %0+4" : : "r" (rela->r_offset
Packit 6c4009
							  + l->l_addr));
Packit 6c4009
		}
Packit 6c4009
	      ++rela;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return lazy;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
Packit 6c4009
   PLT entries should not be allowed to 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
#define elf_machine_type_class(type) \
Packit 6c4009
  ((((type) == R_SPARC_JMP_SLOT						      \
Packit 6c4009
     || ((type) >= R_SPARC_TLS_GD_HI22 && (type) <= R_SPARC_TLS_TPOFF64))     \
Packit 6c4009
    * ELF_RTYPE_CLASS_PLT)						      \
Packit 6c4009
   | (((type) == R_SPARC_COPY) * ELF_RTYPE_CLASS_COPY))
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_SPARC_JMP_SLOT
Packit 6c4009
Packit 6c4009
/* The SPARC never uses Elf32_Rel relocations.  */
Packit 6c4009
#define ELF_MACHINE_NO_REL 1
Packit 6c4009
#define ELF_MACHINE_NO_RELA 0
Packit 6c4009
Packit 6c4009
/* Undo the sub %sp, 6*4, %sp; add %sp, 22*4, %o0 below to get at the
Packit 6c4009
   value we want in __libc_stack_end.  */
Packit 6c4009
#define DL_STACK_END(cookie) \
Packit 6c4009
  ((void *) (((long) (cookie)) - (22 - 6) * 4))
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_GOT_ADDRESS(pic_reg, reg, symbol)	\
Packit 6c4009
	"sethi	%gdop_hix22(" #symbol "), " #reg "\n\t" \
Packit 6c4009
	"xor	" #reg ", %gdop_lox10(" #symbol "), " #reg "\n\t" \
Packit 6c4009
	"ld	[" #pic_reg " + " #reg "], " #reg ", %gdop(" #symbol ")"
Packit 6c4009
Packit 6c4009
#define RTLD_START __asm__ ("\
Packit 6c4009
	.text\n\
Packit 6c4009
	.globl	_start\n\
Packit 6c4009
	.type	_start, @function\n\
Packit 6c4009
	.align	32\n\
Packit 6c4009
_start:\n\
Packit 6c4009
  /* Allocate space for functions to drop their arguments.  */\n\
Packit 6c4009
	sub	%sp, 6*4, %sp\n\
Packit 6c4009
  /* Pass pointer to argument block to _dl_start.  */\n\
Packit 6c4009
	call	_dl_start\n\
Packit 6c4009
	 add	%sp, 22*4, %o0\n\
Packit 6c4009
	/* FALTHRU */\n\
Packit 6c4009
	.globl	_dl_start_user\n\
Packit 6c4009
	.type	_dl_start_user, @function\n\
Packit 6c4009
_dl_start_user:\n\
Packit 6c4009
  /* Load the PIC register.  */\n\
Packit 6c4009
1:	call	2f\n\
Packit 6c4009
	 sethi	%hi(_GLOBAL_OFFSET_TABLE_-(1b-.)), %l7\n\
Packit 6c4009
2:	or	%l7, %lo(_GLOBAL_OFFSET_TABLE_-(1b-.)), %l7\n\
Packit 6c4009
	add	%l7, %o7, %l7\n\
Packit 6c4009
  /* Save the user entry point address in %l0 */\n\
Packit 6c4009
	mov	%o0, %l0\n\
Packit 6c4009
  /* See if we were run as a command with the executable file name as an\n\
Packit 6c4009
     extra leading argument.  If so, adjust the contents of the stack.  */\n\
Packit 6c4009
	" RTLD_GOT_ADDRESS(%l7, %g2, _dl_skip_args) "\n\
Packit 6c4009
	ld	[%g2], %i0\n\
Packit 6c4009
	tst	%i0\n\
Packit 6c4009
	beq	3f\n\
Packit 6c4009
	 ld	[%sp+22*4], %i5		/* load argc */\n\
Packit 6c4009
	/* Find out how far to shift.  */\n\
Packit 6c4009
	" RTLD_GOT_ADDRESS(%l7, %l3, _dl_argv) "\n\
Packit 6c4009
	sub	%i5, %i0, %i5\n\
Packit 6c4009
	ld	[%l3], %l4\n\
Packit 6c4009
	sll	%i0, 2, %i2\n\
Packit 6c4009
	st	%i5, [%sp+22*4]\n\
Packit 6c4009
	sub	%l4, %i2, %l4\n\
Packit 6c4009
	add	%sp, 23*4, %i1\n\
Packit 6c4009
	add	%i1, %i2, %i2\n\
Packit 6c4009
	st	%l4, [%l3]\n\
Packit 6c4009
	/* Copy down argv */\n\
Packit 6c4009
21:	ld	[%i2], %i3\n\
Packit 6c4009
	add	%i2, 4, %i2\n\
Packit 6c4009
	tst	%i3\n\
Packit 6c4009
	st	%i3, [%i1]\n\
Packit 6c4009
	bne	21b\n\
Packit 6c4009
	 add	%i1, 4, %i1\n\
Packit 6c4009
	/* Copy down env */\n\
Packit 6c4009
22:	ld	[%i2], %i3\n\
Packit 6c4009
	add	%i2, 4, %i2\n\
Packit 6c4009
	tst	%i3\n\
Packit 6c4009
	st	%i3, [%i1]\n\
Packit 6c4009
	bne	22b\n\
Packit 6c4009
	 add	%i1, 4, %i1\n\
Packit 6c4009
	/* Copy down auxiliary table.  */\n\
Packit 6c4009
23:	ld	[%i2], %i3\n\
Packit 6c4009
	ld	[%i2+4], %i4\n\
Packit 6c4009
	add	%i2, 8, %i2\n\
Packit 6c4009
	tst	%i3\n\
Packit 6c4009
	st	%i3, [%i1]\n\
Packit 6c4009
	st	%i4, [%i1+4]\n\
Packit 6c4009
	bne	23b\n\
Packit 6c4009
	 add	%i1, 8, %i1\n\
Packit 6c4009
  /* %o0 = _dl_loaded, %o1 = argc, %o2 = argv, %o3 = envp.  */\n\
Packit 6c4009
3:	" RTLD_GOT_ADDRESS(%l7, %o0, _rtld_local) "\n\
Packit 6c4009
	add	%sp, 23*4, %o2\n\
Packit 6c4009
	sll	%i5, 2, %o3\n\
Packit 6c4009
	add	%o3, 4, %o3\n\
Packit 6c4009
	mov	%i5, %o1\n\
Packit 6c4009
	add	%o2, %o3, %o3\n\
Packit 6c4009
	call	_dl_init\n\
Packit 6c4009
	 ld	[%o0], %o0\n\
Packit 6c4009
  /* Pass our finalizer function to the user in %g1.  */\n\
Packit 6c4009
	" RTLD_GOT_ADDRESS(%l7, %g1, _dl_fini) "\n\
Packit 6c4009
  /* Jump to the user's entry point and deallocate the extra stack we got.  */\n\
Packit 6c4009
	jmp	%l0\n\
Packit 6c4009
	 add	%sp, 6*4, %sp\n\
Packit 6c4009
	.size   _dl_start_user, . - _dl_start_user\n\
Packit 6c4009
	.previous");
Packit 6c4009
Packit 6c4009
static inline Elf32_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 Elf32_Rela *reloc,
Packit 6c4009
		       Elf32_Addr *reloc_addr, Elf32_Addr value)
Packit 6c4009
{
Packit 6c4009
#ifdef __sparc_v9__
Packit 6c4009
  /* Sparc v9 can assume flush is always present.  */
Packit 6c4009
  const int do_flush = 1;
Packit 6c4009
#else
Packit 6c4009
  /* Note that we don't mask the hwcap here, as the flush is essential to
Packit 6c4009
     functionality on those cpu's that implement it.  */
Packit 6c4009
  const int do_flush = GLRO(dl_hwcap) & HWCAP_SPARC_FLUSH;
Packit 6c4009
#endif
Packit 6c4009
  return sparc_fixup_plt (reloc, reloc_addr, value, 1, do_flush);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Return the final value of a plt relocation.  */
Packit 6c4009
static inline Elf32_Addr
Packit 6c4009
elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
Packit 6c4009
		       Elf32_Addr value)
Packit 6c4009
{
Packit 6c4009
  return value + reloc->r_addend;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#endif /* dl_machine_h */
Packit 6c4009
Packit 6c4009
#define ARCH_LA_PLTENTER	sparc32_gnu_pltenter
Packit 6c4009
#define ARCH_LA_PLTEXIT		sparc32_gnu_pltexit
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 Elf32_Rela *reloc,
Packit 6c4009
		  const Elf32_Sym *sym, const struct r_found_version *version,
Packit 6c4009
		  void *const reloc_addr_arg, int skip_ifunc)
Packit 6c4009
{
Packit 6c4009
  Elf32_Addr *const reloc_addr = reloc_addr_arg;
Packit 6c4009
#if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
Packit 6c4009
  const Elf32_Sym *const refsym = sym;
Packit 6c4009
#endif
Packit 6c4009
  Elf32_Addr value;
Packit 6c4009
  const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
Packit 6c4009
#if !defined RESOLVE_CONFLICT_FIND_MAP
Packit 6c4009
  struct link_map *sym_map = NULL;
Packit 6c4009
#endif
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; 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
  if (__glibc_unlikely (r_type == R_SPARC_NONE))
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  if (__glibc_unlikely (r_type == R_SPARC_SIZE32))
Packit 6c4009
    {
Packit 6c4009
      *reloc_addr = sym->st_size + reloc->r_addend;
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
#if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
Packit 6c4009
  if (__glibc_unlikely (r_type == R_SPARC_RELATIVE))
Packit 6c4009
    {
Packit 6c4009
# if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
Packit 6c4009
      if (map != &_dl_rtld_map) /* Already done in rtld itself. */
Packit 6c4009
# endif
Packit 6c4009
	*reloc_addr += map->l_addr + reloc->r_addend;
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef RESOLVE_CONFLICT_FIND_MAP
Packit 6c4009
  if (__builtin_expect (ELF32_ST_BIND (sym->st_info) == STB_LOCAL, 0)
Packit 6c4009
      && sym->st_shndx != SHN_UNDEF)
Packit 6c4009
    {
Packit 6c4009
      sym_map = map;
Packit 6c4009
      value = map->l_addr;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      sym_map = RESOLVE_MAP (&sym, version, r_type);
Packit 6c4009
      value = SYMBOL_ADDRESS (sym_map, sym, true);
Packit 6c4009
    }
Packit 6c4009
#else
Packit 6c4009
  value = 0;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  value += reloc->r_addend;	/* Assume copy relocs have zero addend.  */
Packit 6c4009
Packit 6c4009
  if (sym != NULL
Packit 6c4009
      && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)
Packit 6c4009
      && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1)
Packit 6c4009
      && __builtin_expect (!skip_ifunc, 1))
Packit 6c4009
    {
Packit 6c4009
      value = ((Elf32_Addr (*) (int)) value) (GLRO(dl_hwcap));
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  switch (r_type)
Packit 6c4009
    {
Packit 6c4009
#if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
Packit 6c4009
    case R_SPARC_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
      if (sym->st_size > refsym->st_size
Packit 6c4009
	  || (GLRO(dl_verbose) && sym->st_size < refsym->st_size))
Packit 6c4009
	{
Packit 6c4009
	  const char *strtab;
Packit 6c4009
Packit 6c4009
	  strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
Packit 6c4009
	  _dl_error_printf ("\
Packit 6c4009
%s: Symbol `%s' has different size in shared object, consider re-linking\n",
Packit 6c4009
			    RTLD_PROGNAME, strtab + refsym->st_name);
Packit 6c4009
	}
Packit 6c4009
      memcpy (reloc_addr_arg, (void *) value,
Packit 6c4009
	      MIN (sym->st_size, refsym->st_size));
Packit 6c4009
      break;
Packit 6c4009
#endif
Packit 6c4009
    case R_SPARC_GLOB_DAT:
Packit 6c4009
    case R_SPARC_32:
Packit 6c4009
      *reloc_addr = value;
Packit 6c4009
      break;
Packit 6c4009
    case R_SPARC_IRELATIVE:
Packit 6c4009
      value = ((Elf32_Addr (*) (int)) value) (GLRO(dl_hwcap));
Packit 6c4009
      *reloc_addr = value;
Packit 6c4009
      break;
Packit 6c4009
    case R_SPARC_JMP_IREL:
Packit 6c4009
      value = ((Elf32_Addr (*) (int)) value) (GLRO(dl_hwcap));
Packit 6c4009
      /* Fall thru */
Packit 6c4009
    case R_SPARC_JMP_SLOT:
Packit 6c4009
      {
Packit 6c4009
#if !defined RTLD_BOOTSTRAP && !defined __sparc_v9__
Packit 6c4009
	/* Note that we don't mask the hwcap here, as the flush is
Packit 6c4009
	   essential to functionality on those cpu's that implement
Packit 6c4009
	   it.  For sparcv9 we can assume flush is present.  */
Packit 6c4009
	const int do_flush = GLRO(dl_hwcap) & HWCAP_SPARC_FLUSH;
Packit 6c4009
#else
Packit 6c4009
	/* Unfortunately, this is necessary, so that we can ensure
Packit 6c4009
	   ld.so will not execute corrupt PLT entry instructions. */
Packit 6c4009
	const int do_flush = 1;
Packit 6c4009
#endif
Packit 6c4009
	/* At this point we don't need to bother with thread safety,
Packit 6c4009
	   so we can optimize the first instruction of .plt out.  */
Packit 6c4009
	sparc_fixup_plt (reloc, reloc_addr, value, 0, do_flush);
Packit 6c4009
      }
Packit 6c4009
      break;
Packit 6c4009
#ifndef RESOLVE_CONFLICT_FIND_MAP
Packit 6c4009
    case R_SPARC_TLS_DTPMOD32:
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
      break;
Packit 6c4009
    case R_SPARC_TLS_DTPOFF32:
Packit 6c4009
      /* During relocation all TLS symbols are defined and used.
Packit 6c4009
	 Therefore the offset is already correct.  */
Packit 6c4009
      *reloc_addr = (sym == NULL ? 0 : sym->st_value) + reloc->r_addend;
Packit 6c4009
      break;
Packit 6c4009
    case R_SPARC_TLS_TPOFF32:
Packit 6c4009
      /* The offset is negative, forward from the thread pointer.  */
Packit 6c4009
      /* We know the offset of 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
      if (sym != NULL)
Packit 6c4009
	{
Packit 6c4009
	  CHECK_STATIC_TLS (map, sym_map);
Packit 6c4009
	  *reloc_addr = sym->st_value - sym_map->l_tls_offset
Packit 6c4009
	    + reloc->r_addend;
Packit 6c4009
	}
Packit 6c4009
      break;
Packit 6c4009
# ifndef RTLD_BOOTSTRAP
Packit 6c4009
    case R_SPARC_TLS_LE_HIX22:
Packit 6c4009
    case R_SPARC_TLS_LE_LOX10:
Packit 6c4009
      if (sym != NULL)
Packit 6c4009
	{
Packit 6c4009
	  CHECK_STATIC_TLS (map, sym_map);
Packit 6c4009
	  value = sym->st_value - sym_map->l_tls_offset
Packit 6c4009
	    + reloc->r_addend;
Packit 6c4009
	  if (r_type == R_SPARC_TLS_LE_HIX22)
Packit 6c4009
	    *reloc_addr = (*reloc_addr & 0xffc00000) | ((~value) >> 10);
Packit 6c4009
	  else
Packit 6c4009
	    *reloc_addr = (*reloc_addr & 0xffffe000) | (value & 0x3ff)
Packit 6c4009
	      | 0x1c00;
Packit 6c4009
	}
Packit 6c4009
      break;
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
#ifndef RTLD_BOOTSTRAP
Packit 6c4009
    case R_SPARC_8:
Packit 6c4009
      *(char *) reloc_addr = value;
Packit 6c4009
      break;
Packit 6c4009
    case R_SPARC_16:
Packit 6c4009
      *(short *) reloc_addr = value;
Packit 6c4009
      break;
Packit 6c4009
    case R_SPARC_DISP8:
Packit 6c4009
      *(char *) reloc_addr = (value - (Elf32_Addr) reloc_addr);
Packit 6c4009
      break;
Packit 6c4009
    case R_SPARC_DISP16:
Packit 6c4009
      *(short *) reloc_addr = (value - (Elf32_Addr) reloc_addr);
Packit 6c4009
      break;
Packit 6c4009
    case R_SPARC_DISP32:
Packit 6c4009
      *reloc_addr = (value - (Elf32_Addr) reloc_addr);
Packit 6c4009
      break;
Packit 6c4009
    case R_SPARC_LO10:
Packit 6c4009
      *reloc_addr = (*reloc_addr & ~0x3ff) | (value & 0x3ff);
Packit 6c4009
      break;
Packit 6c4009
    case R_SPARC_WDISP30:
Packit 6c4009
      *reloc_addr = ((*reloc_addr & 0xc0000000)
Packit 6c4009
		     | ((value - (unsigned int) reloc_addr) >> 2));
Packit 6c4009
      break;
Packit 6c4009
    case R_SPARC_HI22:
Packit 6c4009
      *reloc_addr = (*reloc_addr & 0xffc00000) | (value >> 10);
Packit 6c4009
      break;
Packit 6c4009
    case R_SPARC_UA16:
Packit 6c4009
      ((unsigned char *) reloc_addr_arg) [0] = value >> 8;
Packit 6c4009
      ((unsigned char *) reloc_addr_arg) [1] = value;
Packit 6c4009
      break;
Packit 6c4009
    case R_SPARC_UA32:
Packit 6c4009
      ((unsigned char *) reloc_addr_arg) [0] = value >> 24;
Packit 6c4009
      ((unsigned char *) reloc_addr_arg) [1] = value >> 16;
Packit 6c4009
      ((unsigned char *) reloc_addr_arg) [2] = value >> 8;
Packit 6c4009
      ((unsigned char *) reloc_addr_arg) [3] = value;
Packit 6c4009
      break;
Packit 6c4009
#endif
Packit 6c4009
#if !defined RTLD_BOOTSTRAP || defined _NDEBUG
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
auto inline void
Packit 6c4009
__attribute__ ((always_inline))
Packit 6c4009
elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
Packit 6c4009
			   void *const reloc_addr_arg)
Packit 6c4009
{
Packit 6c4009
  Elf32_Addr *const reloc_addr = reloc_addr_arg;
Packit 6c4009
  *reloc_addr += l_addr + reloc->r_addend;
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
		      Elf32_Addr l_addr, const Elf32_Rela *reloc,
Packit 6c4009
		      int skip_ifunc)
Packit 6c4009
{
Packit 6c4009
  Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
Packit 6c4009
  const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
Packit 6c4009
Packit 6c4009
  if (__glibc_likely (r_type == R_SPARC_JMP_SLOT))
Packit 6c4009
    ;
Packit 6c4009
  else if (r_type == R_SPARC_JMP_IREL)
Packit 6c4009
    {
Packit 6c4009
      Elf32_Addr value = map->l_addr + reloc->r_addend;
Packit 6c4009
      if (__glibc_likely (!skip_ifunc))
Packit 6c4009
	value = ((Elf32_Addr (*) (int)) value) (GLRO(dl_hwcap));
Packit 6c4009
      sparc_fixup_plt (reloc, reloc_addr, value, 1, 1);
Packit 6c4009
    }
Packit 6c4009
  else if (r_type == R_SPARC_NONE)
Packit 6c4009
    ;
Packit 6c4009
  else
Packit 6c4009
    _dl_reloc_bad_type (map, r_type, 1);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#endif	/* RESOLVE_MAP */