Blame sysdeps/arm/dl-machine.h

Packit 6c4009
/* Machine-dependent ELF dynamic relocation inline functions.  ARM version.
Packit 6c4009
   Copyright (C) 1995-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 "ARM"
Packit 6c4009
Packit 6c4009
#include <sys/param.h>
Packit 6c4009
#include <tls.h>
Packit 6c4009
#include <dl-tlsdesc.h>
Packit 6c4009
#include <dl-irel.h>
Packit 6c4009
Packit 6c4009
#ifndef CLEAR_CACHE
Packit 6c4009
# error CLEAR_CACHE definition required to handle TEXTREL
Packit 6c4009
#endif
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 Elf32_Ehdr *ehdr)
Packit 6c4009
{
Packit 6c4009
  return ehdr->e_machine == EM_ARM;
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.  */
Packit 6c4009
static inline Elf32_Addr __attribute__ ((unused))
Packit 6c4009
elf_machine_dynamic (void)
Packit 6c4009
{
Packit 6c4009
  /* Declaring this hidden ensures that a PC-relative reference is used.  */
Packit 6c4009
  extern const Elf32_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 Elf32_Addr __attribute__ ((unused))
Packit 6c4009
elf_machine_load_address (void)
Packit 6c4009
{
Packit 6c4009
  Elf32_Addr pcrel_addr;
Packit 6c4009
#ifdef SHARED
Packit 6c4009
  extern Elf32_Addr __dl_start (void *) asm ("_dl_start");
Packit 6c4009
  Elf32_Addr got_addr = (Elf32_Addr) &__dl_start;
Packit 6c4009
  asm ("adr %0, _dl_start" : "=r" (pcrel_addr));
Packit 6c4009
#else
Packit 6c4009
  extern Elf32_Addr __dl_relocate_static_pie (void *)
Packit 6c4009
    asm ("_dl_relocate_static_pie") attribute_hidden;
Packit 6c4009
  Elf32_Addr got_addr = (Elf32_Addr) &__dl_relocate_static_pie;
Packit 6c4009
  asm ("adr %0, _dl_relocate_static_pie" : "=r" (pcrel_addr));
Packit 6c4009
#endif
Packit 6c4009
#ifdef __thumb__
Packit 6c4009
  /* Clear the low bit of the function address.
Packit 6c4009
Packit 6c4009
     NOTE: got_addr is from GOT table whose lsb is always set by linker if it's
Packit 6c4009
     Thumb function address.  PCREL_ADDR comes from PC-relative calculation
Packit 6c4009
     which will finish during assembling.  GAS assembler before the fix for
Packit 6c4009
     PR gas/21458 was not setting the lsb but does after that.  Always do the
Packit 6c4009
     strip for both, so the code works with various combinations of glibc and
Packit 6c4009
     Binutils.  */
Packit 6c4009
  got_addr &= ~(Elf32_Addr) 1;
Packit 6c4009
  pcrel_addr &= ~(Elf32_Addr) 1;
Packit 6c4009
#endif
Packit 6c4009
  return pcrel_addr - got_addr;
Packit 6c4009
}
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))
Packit 6c4009
elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
Packit 6c4009
{
Packit 6c4009
  Elf32_Addr *got;
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
      /* patb: this is different than i386 */
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
	 index into the .got section, load ip with &_GLOBAL_OFFSET_TABLE_[3],
Packit 6c4009
	 and then jump to _GLOBAL_OFFSET_TABLE[2].  */
Packit 6c4009
      got = (Elf32_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.  */
Packit 6c4009
      if (got[1])
Packit 6c4009
	l->l_mach.plt = got[1] + l->l_addr;
Packit 6c4009
      got[1] = (Elf32_Addr) l;	/* Identify this shared object.  */
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 (profile)
Packit 6c4009
	{
Packit 6c4009
	  got[2] = (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
	    /* Say that we really want profiling and the timers are
Packit 6c4009
	       started.  */
Packit 6c4009
	    GL(dl_profile_map) = l;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	/* This function will get called to fix up the GOT entry indicated by
Packit 6c4009
	   the offset on the stack, and then jump to the resolved address.  */
Packit 6c4009
	got[2] = (Elf32_Addr) &_dl_runtime_resolve;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return lazy;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#if defined(ARCH_HAS_BX)
Packit 6c4009
#define BX(x) "bx\t" #x
Packit 6c4009
#else
Packit 6c4009
#define BX(x) "mov\tpc, " #x
Packit 6c4009
#endif
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	0xf8000000UL
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
.text\n\
Packit 6c4009
.globl _start\n\
Packit 6c4009
.type _start, %function\n\
Packit 6c4009
.globl _dl_start_user\n\
Packit 6c4009
.type _dl_start_user, %function\n\
Packit 6c4009
_start:\n\
Packit 6c4009
	@ we are PIC code, so get global offset table\n\
Packit 6c4009
	ldr	sl, .L_GET_GOT\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
	ldr	r4, .L_SKIP_ARGS\n\
Packit 6c4009
	@ at start time, all the args are on the stack\n\
Packit 6c4009
	mov	r0, sp\n\
Packit 6c4009
	bl	_dl_start\n\
Packit 6c4009
	@ returns user entry point in r0\n\
Packit 6c4009
_dl_start_user:\n\
Packit 6c4009
	adr	r6, .L_GET_GOT\n\
Packit 6c4009
	add	sl, sl, r6\n\
Packit 6c4009
	ldr	r4, [sl, r4]\n\
Packit 6c4009
	@ save the entry point in another register\n\
Packit 6c4009
	mov	r6, r0\n\
Packit 6c4009
	@ get the original arg count\n\
Packit 6c4009
	ldr	r1, [sp]\n\
Packit 6c4009
	@ get the argv address\n\
Packit 6c4009
	add	r2, sp, #4\n\
Packit 6c4009
	@ Fix up the stack if necessary.\n\
Packit 6c4009
	cmp	r4, #0\n\
Packit 6c4009
	bne	.L_fixup_stack\n\
Packit 6c4009
.L_done_fixup:\n\
Packit 6c4009
	@ compute envp\n\
Packit 6c4009
	add	r3, r2, r1, lsl #2\n\
Packit 6c4009
	add	r3, r3, #4\n\
Packit 6c4009
	@ now we call _dl_init\n\
Packit 6c4009
	ldr	r0, .L_LOADED\n\
Packit 6c4009
	ldr	r0, [sl, r0]\n\
Packit 6c4009
	@ call _dl_init\n\
Packit 6c4009
	bl	_dl_init(PLT)\n\
Packit 6c4009
	@ load the finalizer function\n\
Packit 6c4009
	ldr	r0, .L_FINI_PROC\n\
Packit 6c4009
	add	r0, sl, r0\n\
Packit 6c4009
	@ jump to the user_s entry point\n\
Packit 6c4009
	" BX(r6) "\n\
Packit 6c4009
\n\
Packit 6c4009
	@ iWMMXt and EABI targets require the stack to be eight byte\n\
Packit 6c4009
	@ aligned - shuffle arguments etc.\n\
Packit 6c4009
.L_fixup_stack:\n\
Packit 6c4009
	@ subtract _dl_skip_args from original arg count\n\
Packit 6c4009
	sub	r1, r1, r4\n\
Packit 6c4009
	@ store the new argc in the new stack location\n\
Packit 6c4009
	str	r1, [sp]\n\
Packit 6c4009
	@ find the first unskipped argument\n\
Packit 6c4009
	mov	r3, r2\n\
Packit 6c4009
	add	r4, r2, r4, lsl #2\n\
Packit 6c4009
	@ shuffle argv down\n\
Packit 6c4009
1:	ldr	r5, [r4], #4\n\
Packit 6c4009
	str	r5, [r3], #4\n\
Packit 6c4009
	cmp	r5, #0\n\
Packit 6c4009
	bne	1b\n\
Packit 6c4009
	@ shuffle envp down\n\
Packit 6c4009
1:	ldr	r5, [r4], #4\n\
Packit 6c4009
	str	r5, [r3], #4\n\
Packit 6c4009
	cmp	r5, #0\n\
Packit 6c4009
	bne	1b\n\
Packit 6c4009
	@ shuffle auxv down\n\
Packit 6c4009
1:	ldmia	r4!, {r0, r5}\n\
Packit 6c4009
	stmia	r3!, {r0, r5}\n\
Packit 6c4009
	cmp	r0, #0\n\
Packit 6c4009
	bne	1b\n\
Packit 6c4009
	@ Update _dl_argv\n\
Packit 6c4009
	ldr	r3, .L_ARGV\n\
Packit 6c4009
	str	r2, [sl, r3]\n\
Packit 6c4009
	b	.L_done_fixup\n\
Packit 6c4009
\n\
Packit 6c4009
.L_GET_GOT:\n\
Packit 6c4009
	.word	_GLOBAL_OFFSET_TABLE_ - .L_GET_GOT\n\
Packit 6c4009
.L_SKIP_ARGS:\n\
Packit 6c4009
	.word	_dl_skip_args(GOTOFF)\n\
Packit 6c4009
.L_FINI_PROC:\n\
Packit 6c4009
	.word	_dl_fini(GOTOFF)\n\
Packit 6c4009
.L_ARGV:\n\
Packit 6c4009
	.word	_dl_argv(GOTOFF)\n\
Packit 6c4009
.L_LOADED:\n\
Packit 6c4009
	.word	_rtld_local(GOTOFF)\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 against
Packit 6c4009
   protected data whose address may be external due to copy relocation.  */
Packit 6c4009
#ifndef RTLD_BOOTSTRAP
Packit 6c4009
# define elf_machine_type_class(type) \
Packit 6c4009
  ((((type) == R_ARM_JUMP_SLOT || (type) == R_ARM_TLS_DTPMOD32		\
Packit 6c4009
     || (type) == R_ARM_TLS_DTPOFF32 || (type) == R_ARM_TLS_TPOFF32	\
Packit 6c4009
     || (type) == R_ARM_TLS_DESC)					\
Packit 6c4009
    * ELF_RTYPE_CLASS_PLT)						\
Packit 6c4009
   | (((type) == R_ARM_COPY) * ELF_RTYPE_CLASS_COPY)			\
Packit 6c4009
   | (((type) == R_ARM_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA))
Packit 6c4009
#else
Packit 6c4009
#define elf_machine_type_class(type) \
Packit 6c4009
  ((((type) == R_ARM_JUMP_SLOT) * ELF_RTYPE_CLASS_PLT)	\
Packit 6c4009
   | (((type) == R_ARM_COPY) * ELF_RTYPE_CLASS_COPY)	\
Packit 6c4009
   | (((type) == R_ARM_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA))
Packit 6c4009
#endif
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_ARM_JUMP_SLOT
Packit 6c4009
Packit 6c4009
/* ARM never uses Elf32_Rela relocations for the dynamic linker.
Packit 6c4009
   Prelinked libraries may use Elf32_Rela though.  */
Packit 6c4009
#define ELF_MACHINE_PLT_REL 1
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
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_Rel *reloc,
Packit 6c4009
		       Elf32_Addr *reloc_addr, Elf32_Addr value)
Packit 6c4009
{
Packit 6c4009
  return *reloc_addr = value;
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_Rel *reloc,
Packit 6c4009
		       Elf32_Addr value)
Packit 6c4009
{
Packit 6c4009
  return value;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#endif /* !dl_machine_h */
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* ARM never uses Elf32_Rela relocations for the dynamic linker.
Packit 6c4009
   Prelinked libraries may use Elf32_Rela though.  */
Packit 6c4009
#define ELF_MACHINE_NO_RELA defined RTLD_BOOTSTRAP
Packit 6c4009
#define ELF_MACHINE_NO_REL 0
Packit 6c4009
Packit 6c4009
/* Names of the architecture-specific auditing callback functions.  */
Packit 6c4009
#define ARCH_LA_PLTENTER arm_gnu_pltenter
Packit 6c4009
#define ARCH_LA_PLTEXIT arm_gnu_pltexit
Packit 6c4009
Packit 6c4009
#ifdef RESOLVE_MAP
Packit 6c4009
/* Handle a PC24 reloc, including the out-of-range case.  */
Packit 6c4009
auto void
Packit 6c4009
relocate_pc24 (struct link_map *map, Elf32_Addr value,
Packit 6c4009
               Elf32_Addr *const reloc_addr, Elf32_Sword addend)
Packit 6c4009
{
Packit 6c4009
  Elf32_Addr new_value;
Packit 6c4009
Packit 6c4009
  /* Set NEW_VALUE based on V, and return true iff it overflows 24 bits.  */
Packit 6c4009
  inline bool set_new_value (Elf32_Addr v)
Packit 6c4009
  {
Packit 6c4009
    new_value = v + addend - (Elf32_Addr) reloc_addr;
Packit 6c4009
    Elf32_Addr topbits = new_value & 0xfe000000;
Packit 6c4009
    return topbits != 0xfe000000 && topbits != 0x00000000;
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
  if (set_new_value (value))
Packit 6c4009
    {
Packit 6c4009
      /* The PC-relative address doesn't fit in 24 bits!  */
Packit 6c4009
Packit 6c4009
      static void *fix_page;
Packit 6c4009
      static size_t fix_offset;
Packit 6c4009
      if (fix_page == NULL)
Packit 6c4009
        {
Packit 6c4009
          void *new_page = __mmap (NULL, GLRO(dl_pagesize),
Packit 6c4009
                                   PROT_READ | PROT_WRITE | PROT_EXEC,
Packit 6c4009
                                   MAP_PRIVATE | MAP_ANON, -1, 0);
Packit 6c4009
          if (new_page == MAP_FAILED)
Packit 6c4009
            _dl_signal_error (0, map->l_name, NULL,
Packit 6c4009
                              "could not map page for fixup");
Packit 6c4009
          fix_page = new_page;
Packit 6c4009
          assert (fix_offset == 0);
Packit 6c4009
        }
Packit 6c4009
Packit 6c4009
      Elf32_Word *fix_address = fix_page + fix_offset;
Packit 6c4009
      fix_address[0] = 0xe51ff004;	/* ldr pc, [pc, #-4] */
Packit 6c4009
      fix_address[1] = value;
Packit 6c4009
Packit 6c4009
      fix_offset += sizeof fix_address[0] * 2;
Packit 6c4009
      if (fix_offset >= GLRO(dl_pagesize))
Packit 6c4009
        {
Packit 6c4009
          fix_page = NULL;
Packit 6c4009
          fix_offset = 0;
Packit 6c4009
        }
Packit 6c4009
Packit 6c4009
      if (set_new_value ((Elf32_Addr) fix_address))
Packit 6c4009
        _dl_signal_error (0, map->l_name, NULL,
Packit 6c4009
                          "R_ARM_PC24 relocation out of range");
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  *reloc_addr = (*reloc_addr & 0xff000000) | ((new_value >> 2) & 0x00ffffff);
Packit 6c4009
}
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_rel (struct link_map *map, const Elf32_Rel *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
  const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
Packit 6c4009
Packit 6c4009
#if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
Packit 6c4009
  if (__builtin_expect (r_type == R_ARM_RELATIVE, 0))
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 (_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;
Packit 6c4009
    }
Packit 6c4009
# ifndef RTLD_BOOTSTRAP
Packit 6c4009
  else if (__builtin_expect (r_type == R_ARM_NONE, 0))
Packit 6c4009
    return;
Packit 6c4009
# endif
Packit 6c4009
  else
Packit 6c4009
#endif
Packit 6c4009
    {
Packit 6c4009
      const Elf32_Sym *const refsym = sym;
Packit 6c4009
      struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
Packit 6c4009
      Elf32_Addr value = SYMBOL_ADDRESS (sym_map, sym, true);
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
	value = elf_ifunc_invoke (value);
Packit 6c4009
Packit 6c4009
      switch (r_type)
Packit 6c4009
	{
Packit 6c4009
	case R_ARM_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
	case R_ARM_GLOB_DAT:
Packit 6c4009
	case R_ARM_JUMP_SLOT:
Packit 6c4009
# ifdef RTLD_BOOTSTRAP
Packit 6c4009
	  /* Fix weak undefined references.  */
Packit 6c4009
	  if (sym != NULL && sym->st_value == 0)
Packit 6c4009
	    *reloc_addr = 0;
Packit 6c4009
	  else
Packit 6c4009
# endif
Packit 6c4009
	    *reloc_addr = value;
Packit 6c4009
	  break;
Packit 6c4009
	case R_ARM_ABS32:
Packit 6c4009
	  {
Packit 6c4009
	    struct unaligned
Packit 6c4009
	      {
Packit 6c4009
		Elf32_Addr x;
Packit 6c4009
	      } __attribute__ ((packed, may_alias));
Packit 6c4009
# ifndef RTLD_BOOTSTRAP
Packit 6c4009
	   /* This is defined in rtld.c, but nowhere in the static
Packit 6c4009
	      libc.a; make the reference weak so static programs can
Packit 6c4009
	      still link.  This declaration cannot be done when
Packit 6c4009
	      compiling rtld.c (i.e.  #ifdef RTLD_BOOTSTRAP) because
Packit 6c4009
	      rtld.c contains the common defn for _dl_rtld_map, which
Packit 6c4009
	      is incompatible with a weak decl in the same file.  */
Packit 6c4009
#  ifndef SHARED
Packit 6c4009
	    weak_extern (_dl_rtld_map);
Packit 6c4009
#  endif
Packit 6c4009
	    if (map == &GL(dl_rtld_map))
Packit 6c4009
	      /* Undo the relocation done here during bootstrapping.
Packit 6c4009
		 Now we will relocate it anew, possibly using a
Packit 6c4009
		 binding found in the user program or a loaded library
Packit 6c4009
		 rather than the dynamic linker's built-in definitions
Packit 6c4009
		 used while loading those libraries.  */
Packit 6c4009
	      value -= SYMBOL_ADDRESS (map, refsym, true);
Packit 6c4009
# endif
Packit 6c4009
	    /* Support relocations on mis-aligned offsets.  */
Packit 6c4009
	    ((struct unaligned *) reloc_addr)->x += value;
Packit 6c4009
	    break;
Packit 6c4009
	  }
Packit 6c4009
	case R_ARM_TLS_DESC:
Packit 6c4009
	  {
Packit 6c4009
	    struct tlsdesc *td = (struct tlsdesc *)reloc_addr;
Packit 6c4009
Packit 6c4009
# ifndef RTLD_BOOTSTRAP
Packit 6c4009
	    if (! sym)
Packit 6c4009
	      td->entry = _dl_tlsdesc_undefweak;
Packit 6c4009
	    else
Packit 6c4009
# endif
Packit 6c4009
	      {
Packit 6c4009
		if (ELF32_R_SYM (reloc->r_info) == STN_UNDEF)
Packit 6c4009
		  value = td->argument.value;
Packit 6c4009
		else
Packit 6c4009
		  value = sym->st_value;
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->argument.pointer
Packit 6c4009
		      = _dl_make_tlsdesc_dynamic (sym_map, value);
Packit 6c4009
		    td->entry = _dl_tlsdesc_dynamic;
Packit 6c4009
		  }
Packit 6c4009
		else
Packit 6c4009
#  endif
Packit 6c4009
# endif
Packit 6c4009
		{
Packit 6c4009
		  td->argument.value = value + sym_map->l_tls_offset;
Packit 6c4009
		  td->entry = _dl_tlsdesc_return;
Packit 6c4009
		}
Packit 6c4009
	      }
Packit 6c4009
	    }
Packit 6c4009
	    break;
Packit 6c4009
	case R_ARM_PC24:
Packit 6c4009
          relocate_pc24 (map, value, reloc_addr,
Packit 6c4009
                         /* Sign-extend the 24-bit addend in the
Packit 6c4009
                            instruction (which counts instructions), and
Packit 6c4009
                            then shift it up two so as to count bytes.  */
Packit 6c4009
                         (((Elf32_Sword) *reloc_addr << 8) >> 8) << 2);
Packit 6c4009
	  break;
Packit 6c4009
#if !defined RTLD_BOOTSTRAP
Packit 6c4009
	case R_ARM_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
Packit 6c4009
	case R_ARM_TLS_DTPOFF32:
Packit 6c4009
	  if (sym != NULL)
Packit 6c4009
	    *reloc_addr += sym->st_value;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case R_ARM_TLS_TPOFF32:
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
	    }
Packit 6c4009
	  break;
Packit 6c4009
	case R_ARM_IRELATIVE:
Packit 6c4009
	  value = map->l_addr + *reloc_addr;
Packit 6c4009
	  value = ((Elf32_Addr (*) (int)) value) (GLRO(dl_hwcap));
Packit 6c4009
	  *reloc_addr = value;
Packit 6c4009
	  break;
Packit 6c4009
#endif
Packit 6c4009
	default:
Packit 6c4009
	  _dl_reloc_bad_type (map, r_type, 0);
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
# ifndef RTLD_BOOTSTRAP
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
  const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
Packit 6c4009
Packit 6c4009
  if (__builtin_expect (r_type == R_ARM_RELATIVE, 0))
Packit 6c4009
    *reloc_addr = map->l_addr + reloc->r_addend;
Packit 6c4009
  else if (__builtin_expect (r_type == R_ARM_NONE, 0))
Packit 6c4009
    return;
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
# ifndef RESOLVE_CONFLICT_FIND_MAP
Packit 6c4009
      const Elf32_Sym *const refsym = sym;
Packit 6c4009
# endif
Packit 6c4009
      struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
Packit 6c4009
      Elf32_Addr value = SYMBOL_ADDRESS (sym_map, sym, true);
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
	value = elf_ifunc_invoke (value);
Packit 6c4009
Packit 6c4009
      switch (r_type)
Packit 6c4009
	{
Packit 6c4009
#  ifndef RESOLVE_CONFLICT_FIND_MAP
Packit 6c4009
	  /* Not needed for dl-conflict.c.  */
Packit 6c4009
	case R_ARM_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 /* !RESOLVE_CONFLICT_FIND_MAP */
Packit 6c4009
	case R_ARM_GLOB_DAT:
Packit 6c4009
	case R_ARM_JUMP_SLOT:
Packit 6c4009
	case R_ARM_ABS32:
Packit 6c4009
	  *reloc_addr = value + reloc->r_addend;
Packit 6c4009
	  break;
Packit 6c4009
	case R_ARM_PC24:
Packit 6c4009
          relocate_pc24 (map, value, reloc_addr, reloc->r_addend);
Packit 6c4009
	  break;
Packit 6c4009
#if !defined RTLD_BOOTSTRAP
Packit 6c4009
	case R_ARM_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
Packit 6c4009
	case R_ARM_TLS_DTPOFF32:
Packit 6c4009
	  *reloc_addr = (sym == NULL ? 0 : sym->st_value) + reloc->r_addend;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case R_ARM_TLS_TPOFF32:
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
	case R_ARM_IRELATIVE:
Packit 6c4009
	  value = map->l_addr + reloc->r_addend;
Packit 6c4009
	  value = ((Elf32_Addr (*) (int)) value) (GLRO(dl_hwcap));
Packit 6c4009
	  *reloc_addr = value;
Packit 6c4009
	  break;
Packit 6c4009
#endif
Packit 6c4009
	default:
Packit 6c4009
	  _dl_reloc_bad_type (map, r_type, 0);
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
auto inline void
Packit 6c4009
__attribute__ ((always_inline))
Packit 6c4009
elf_machine_rel_relative (Elf32_Addr l_addr, const Elf32_Rel *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;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
# ifndef RTLD_BOOTSTRAP
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
# endif
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_Rel *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
  /* Check for unexpected PLT reloc type.  */
Packit 6c4009
  if (__builtin_expect (r_type == R_ARM_JUMP_SLOT, 1))
Packit 6c4009
    {
Packit 6c4009
      if (__builtin_expect (map->l_mach.plt, 0) == 0)
Packit 6c4009
	*reloc_addr += l_addr;
Packit 6c4009
      else
Packit 6c4009
	*reloc_addr = map->l_mach.plt;
Packit 6c4009
    }
Packit 6c4009
  else if (__builtin_expect (r_type == R_ARM_TLS_DESC, 1))
Packit 6c4009
    {
Packit 6c4009
      const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info);
Packit 6c4009
      const ElfW (Sym) *symtab = (const void *)D_PTR (map, l_info[DT_SYMTAB]);
Packit 6c4009
      const ElfW (Sym) *sym = &symtab[symndx];
Packit 6c4009
      const struct r_found_version *version = NULL;
Packit 6c4009
Packit 6c4009
      if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
Packit 6c4009
	{
Packit 6c4009
	  const ElfW (Half) *vernum =
Packit 6c4009
	    (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
Packit 6c4009
	  version = &map->l_versions[vernum[symndx] & 0x7fff];
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Always initialize TLS descriptors completely, because lazy
Packit 6c4009
	 initialization requires synchronization at every TLS access.  */
Packit 6c4009
      elf_machine_rel (map, reloc, sym, version, reloc_addr, skip_ifunc);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    _dl_reloc_bad_type (map, r_type, 1);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#endif /* RESOLVE_MAP */