Blame sysdeps/arm/dl-machine.h

Packit Service 82fcde
/* Machine-dependent ELF dynamic relocation inline functions.  ARM version.
Packit Service 82fcde
   Copyright (C) 1995-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library.  If not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#ifndef dl_machine_h
Packit Service 82fcde
#define dl_machine_h
Packit Service 82fcde
Packit Service 82fcde
#define ELF_MACHINE_NAME "ARM"
Packit Service 82fcde
Packit Service 82fcde
#include <sys/param.h>
Packit Service 82fcde
#include <tls.h>
Packit Service 82fcde
#include <dl-tlsdesc.h>
Packit Service 82fcde
#include <dl-irel.h>
Packit Service 82fcde
Packit Service 82fcde
#ifndef CLEAR_CACHE
Packit Service 82fcde
# error CLEAR_CACHE definition required to handle TEXTREL
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* Return nonzero iff ELF header is compatible with the running host.  */
Packit Service 82fcde
static inline int __attribute__ ((unused))
Packit Service 82fcde
elf_machine_matches_host (const Elf32_Ehdr *ehdr)
Packit Service 82fcde
{
Packit Service 82fcde
  return ehdr->e_machine == EM_ARM;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Return the link-time address of _DYNAMIC.  Conveniently, this is the
Packit Service 82fcde
   first element of the GOT.  */
Packit Service 82fcde
static inline Elf32_Addr __attribute__ ((unused))
Packit Service 82fcde
elf_machine_dynamic (void)
Packit Service 82fcde
{
Packit Service 82fcde
  /* Declaring this hidden ensures that a PC-relative reference is used.  */
Packit Service 82fcde
  extern const Elf32_Addr _GLOBAL_OFFSET_TABLE_[] attribute_hidden;
Packit Service 82fcde
  return _GLOBAL_OFFSET_TABLE_[0];
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Return the run-time load address of the shared object.  */
Packit Service 82fcde
static inline Elf32_Addr __attribute__ ((unused))
Packit Service 82fcde
elf_machine_load_address (void)
Packit Service 82fcde
{
Packit Service 82fcde
  Elf32_Addr pcrel_addr;
Packit Service 82fcde
#ifdef SHARED
Packit Service 82fcde
  extern Elf32_Addr __dl_start (void *) asm ("_dl_start");
Packit Service 82fcde
  Elf32_Addr got_addr = (Elf32_Addr) &__dl_start;
Packit Service 82fcde
  asm ("adr %0, _dl_start" : "=r" (pcrel_addr));
Packit Service 82fcde
#else
Packit Service 82fcde
  extern Elf32_Addr __dl_relocate_static_pie (void *)
Packit Service 82fcde
    asm ("_dl_relocate_static_pie") attribute_hidden;
Packit Service 82fcde
  Elf32_Addr got_addr = (Elf32_Addr) &__dl_relocate_static_pie;
Packit Service 82fcde
  asm ("adr %0, _dl_relocate_static_pie" : "=r" (pcrel_addr));
Packit Service 82fcde
#endif
Packit Service 82fcde
#ifdef __thumb__
Packit Service 82fcde
  /* Clear the low bit of the function address.
Packit Service 82fcde
Packit Service 82fcde
     NOTE: got_addr is from GOT table whose lsb is always set by linker if it's
Packit Service 82fcde
     Thumb function address.  PCREL_ADDR comes from PC-relative calculation
Packit Service 82fcde
     which will finish during assembling.  GAS assembler before the fix for
Packit Service 82fcde
     PR gas/21458 was not setting the lsb but does after that.  Always do the
Packit Service 82fcde
     strip for both, so the code works with various combinations of glibc and
Packit Service 82fcde
     Binutils.  */
Packit Service 82fcde
  got_addr &= ~(Elf32_Addr) 1;
Packit Service 82fcde
  pcrel_addr &= ~(Elf32_Addr) 1;
Packit Service 82fcde
#endif
Packit Service 82fcde
  return pcrel_addr - got_addr;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Set up the loaded object described by L so its unrelocated PLT
Packit Service 82fcde
   entries will jump to the on-demand fixup code in dl-runtime.c.  */
Packit Service 82fcde
Packit Service 82fcde
static inline int __attribute__ ((unused))
Packit Service 82fcde
elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
Packit Service 82fcde
{
Packit Service 82fcde
  Elf32_Addr *got;
Packit Service 82fcde
  extern void _dl_runtime_resolve (Elf32_Word);
Packit Service 82fcde
  extern void _dl_runtime_profile (Elf32_Word);
Packit Service 82fcde
Packit Service 82fcde
  if (l->l_info[DT_JMPREL] && lazy)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* patb: this is different than i386 */
Packit Service 82fcde
      /* The GOT entries for functions in the PLT have not yet been filled
Packit Service 82fcde
	 in.  Their initial contents will arrange when called to push an
Packit Service 82fcde
	 index into the .got section, load ip with &_GLOBAL_OFFSET_TABLE_[3],
Packit Service 82fcde
	 and then jump to _GLOBAL_OFFSET_TABLE[2].  */
Packit Service 82fcde
      got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
Packit Service 82fcde
      /* If a library is prelinked but we have to relocate anyway,
Packit Service 82fcde
	 we have to be able to undo the prelinking of .got.plt.
Packit Service 82fcde
	 The prelinker saved us here address of .plt.  */
Packit Service 82fcde
      if (got[1])
Packit Service 82fcde
	l->l_mach.plt = got[1] + l->l_addr;
Packit Service 82fcde
      got[1] = (Elf32_Addr) l;	/* Identify this shared object.  */
Packit Service 82fcde
Packit Service 82fcde
      /* The got[2] entry contains the address of a function which gets
Packit Service 82fcde
	 called to get the address of a so far unresolved function and
Packit Service 82fcde
	 jump to it.  The profiling extension of the dynamic linker allows
Packit Service 82fcde
	 to intercept the calls to collect information.  In this case we
Packit Service 82fcde
	 don't store the address in the GOT so that all future calls also
Packit Service 82fcde
	 end in this function.  */
Packit Service 82fcde
      if (profile)
Packit Service 82fcde
	{
Packit Service 82fcde
	  got[2] = (Elf32_Addr) &_dl_runtime_profile;
Packit Service 82fcde
Packit Service 82fcde
	  if (GLRO(dl_profile) != NULL
Packit Service 82fcde
	      && _dl_name_match_p (GLRO(dl_profile), l))
Packit Service 82fcde
	    /* Say that we really want profiling and the timers are
Packit Service 82fcde
	       started.  */
Packit Service 82fcde
	    GL(dl_profile_map) = l;
Packit Service 82fcde
	}
Packit Service 82fcde
      else
Packit Service 82fcde
	/* This function will get called to fix up the GOT entry indicated by
Packit Service 82fcde
	   the offset on the stack, and then jump to the resolved address.  */
Packit Service 82fcde
	got[2] = (Elf32_Addr) &_dl_runtime_resolve;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return lazy;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
#if defined(ARCH_HAS_BX)
Packit Service 82fcde
#define BX(x) "bx\t" #x
Packit Service 82fcde
#else
Packit Service 82fcde
#define BX(x) "mov\tpc, " #x
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* Mask identifying addresses reserved for the user program,
Packit Service 82fcde
   where the dynamic linker should not map anything.  */
Packit Service 82fcde
#define ELF_MACHINE_USER_ADDRESS_MASK	0xf8000000UL
Packit Service 82fcde
Packit Service 82fcde
/* Initial entry point code for the dynamic linker.
Packit Service 82fcde
   The C function `_dl_start' is the real entry point;
Packit Service 82fcde
   its return value is the user program's entry point.  */
Packit Service 82fcde
Packit Service 82fcde
#define RTLD_START asm ("\
Packit Service 82fcde
.text\n\
Packit Service 82fcde
.globl _start\n\
Packit Service 82fcde
.type _start, %function\n\
Packit Service 82fcde
.globl _dl_start_user\n\
Packit Service 82fcde
.type _dl_start_user, %function\n\
Packit Service 82fcde
_start:\n\
Packit Service 82fcde
	@ we are PIC code, so get global offset table\n\
Packit Service 82fcde
	ldr	sl, .L_GET_GOT\n\
Packit Service 82fcde
	@ See if we were run as a command with the executable file\n\
Packit Service 82fcde
	@ name as an extra leading argument.\n\
Packit Service 82fcde
	ldr	r4, .L_SKIP_ARGS\n\
Packit Service 82fcde
	@ at start time, all the args are on the stack\n\
Packit Service 82fcde
	mov	r0, sp\n\
Packit Service 82fcde
	bl	_dl_start\n\
Packit Service 82fcde
	@ returns user entry point in r0\n\
Packit Service 82fcde
_dl_start_user:\n\
Packit Service 82fcde
	adr	r6, .L_GET_GOT\n\
Packit Service 82fcde
	add	sl, sl, r6\n\
Packit Service 82fcde
	ldr	r4, [sl, r4]\n\
Packit Service 82fcde
	@ save the entry point in another register\n\
Packit Service 82fcde
	mov	r6, r0\n\
Packit Service 82fcde
	@ get the original arg count\n\
Packit Service 82fcde
	ldr	r1, [sp]\n\
Packit Service 82fcde
	@ get the argv address\n\
Packit Service 82fcde
	add	r2, sp, #4\n\
Packit Service 82fcde
	@ Fix up the stack if necessary.\n\
Packit Service 82fcde
	cmp	r4, #0\n\
Packit Service 82fcde
	bne	.L_fixup_stack\n\
Packit Service 82fcde
.L_done_fixup:\n\
Packit Service 82fcde
	@ compute envp\n\
Packit Service 82fcde
	add	r3, r2, r1, lsl #2\n\
Packit Service 82fcde
	add	r3, r3, #4\n\
Packit Service 82fcde
	@ now we call _dl_init\n\
Packit Service 82fcde
	ldr	r0, .L_LOADED\n\
Packit Service 82fcde
	ldr	r0, [sl, r0]\n\
Packit Service 82fcde
	@ call _dl_init\n\
Packit Service 82fcde
	bl	_dl_init(PLT)\n\
Packit Service 82fcde
	@ load the finalizer function\n\
Packit Service 82fcde
	ldr	r0, .L_FINI_PROC\n\
Packit Service 82fcde
	add	r0, sl, r0\n\
Packit Service 82fcde
	@ jump to the user_s entry point\n\
Packit Service 82fcde
	" BX(r6) "\n\
Packit Service 82fcde
\n\
Packit Service 82fcde
	@ iWMMXt and EABI targets require the stack to be eight byte\n\
Packit Service 82fcde
	@ aligned - shuffle arguments etc.\n\
Packit Service 82fcde
.L_fixup_stack:\n\
Packit Service 82fcde
	@ subtract _dl_skip_args from original arg count\n\
Packit Service 82fcde
	sub	r1, r1, r4\n\
Packit Service 82fcde
	@ store the new argc in the new stack location\n\
Packit Service 82fcde
	str	r1, [sp]\n\
Packit Service 82fcde
	@ find the first unskipped argument\n\
Packit Service 82fcde
	mov	r3, r2\n\
Packit Service 82fcde
	add	r4, r2, r4, lsl #2\n\
Packit Service 82fcde
	@ shuffle argv down\n\
Packit Service 82fcde
1:	ldr	r5, [r4], #4\n\
Packit Service 82fcde
	str	r5, [r3], #4\n\
Packit Service 82fcde
	cmp	r5, #0\n\
Packit Service 82fcde
	bne	1b\n\
Packit Service 82fcde
	@ shuffle envp down\n\
Packit Service 82fcde
1:	ldr	r5, [r4], #4\n\
Packit Service 82fcde
	str	r5, [r3], #4\n\
Packit Service 82fcde
	cmp	r5, #0\n\
Packit Service 82fcde
	bne	1b\n\
Packit Service 82fcde
	@ shuffle auxv down\n\
Packit Service 82fcde
1:	ldmia	r4!, {r0, r5}\n\
Packit Service 82fcde
	stmia	r3!, {r0, r5}\n\
Packit Service 82fcde
	cmp	r0, #0\n\
Packit Service 82fcde
	bne	1b\n\
Packit Service 82fcde
	@ Update _dl_argv\n\
Packit Service 82fcde
	ldr	r3, .L_ARGV\n\
Packit Service 82fcde
	str	r2, [sl, r3]\n\
Packit Service 82fcde
	b	.L_done_fixup\n\
Packit Service 82fcde
\n\
Packit Service 82fcde
.L_GET_GOT:\n\
Packit Service 82fcde
	.word	_GLOBAL_OFFSET_TABLE_ - .L_GET_GOT\n\
Packit Service 82fcde
.L_SKIP_ARGS:\n\
Packit Service 82fcde
	.word	_dl_skip_args(GOTOFF)\n\
Packit Service 82fcde
.L_FINI_PROC:\n\
Packit Service 82fcde
	.word	_dl_fini(GOTOFF)\n\
Packit Service 82fcde
.L_ARGV:\n\
Packit Service 82fcde
	.word	_dl_argv(GOTOFF)\n\
Packit Service 82fcde
.L_LOADED:\n\
Packit Service 82fcde
	.word	_rtld_local(GOTOFF)\n\
Packit Service 82fcde
.previous\n\
Packit Service 82fcde
");
Packit Service 82fcde
Packit Service 82fcde
/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
Packit Service 82fcde
   TLS variable, so undefined references should not be allowed to
Packit Service 82fcde
   define the value.
Packit Service 82fcde
   ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve to one
Packit Service 82fcde
   of the main executable's symbols, as for a COPY reloc.
Packit Service 82fcde
   ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA iff TYPE describes relocation against
Packit Service 82fcde
   protected data whose address may be external due to copy relocation.  */
Packit Service 82fcde
#ifndef RTLD_BOOTSTRAP
Packit Service 82fcde
# define elf_machine_type_class(type) \
Packit Service 82fcde
  ((((type) == R_ARM_JUMP_SLOT || (type) == R_ARM_TLS_DTPMOD32		\
Packit Service 82fcde
     || (type) == R_ARM_TLS_DTPOFF32 || (type) == R_ARM_TLS_TPOFF32	\
Packit Service 82fcde
     || (type) == R_ARM_TLS_DESC)					\
Packit Service 82fcde
    * ELF_RTYPE_CLASS_PLT)						\
Packit Service 82fcde
   | (((type) == R_ARM_COPY) * ELF_RTYPE_CLASS_COPY)			\
Packit Service 82fcde
   | (((type) == R_ARM_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA))
Packit Service 82fcde
#else
Packit Service 82fcde
#define elf_machine_type_class(type) \
Packit Service 82fcde
  ((((type) == R_ARM_JUMP_SLOT) * ELF_RTYPE_CLASS_PLT)	\
Packit Service 82fcde
   | (((type) == R_ARM_COPY) * ELF_RTYPE_CLASS_COPY)	\
Packit Service 82fcde
   | (((type) == R_ARM_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA))
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
Packit Service 82fcde
#define ELF_MACHINE_JMP_SLOT	R_ARM_JUMP_SLOT
Packit Service 82fcde
Packit Service 82fcde
/* ARM never uses Elf32_Rela relocations for the dynamic linker.
Packit Service 82fcde
   Prelinked libraries may use Elf32_Rela though.  */
Packit Service 82fcde
#define ELF_MACHINE_PLT_REL 1
Packit Service 82fcde
Packit Service 82fcde
/* We define an initialization functions.  This is called very early in
Packit Service 82fcde
   _dl_sysdep_start.  */
Packit Service 82fcde
#define DL_PLATFORM_INIT dl_platform_init ()
Packit Service 82fcde
Packit Service 82fcde
static inline void __attribute__ ((unused))
Packit Service 82fcde
dl_platform_init (void)
Packit Service 82fcde
{
Packit Service 82fcde
  if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
Packit Service 82fcde
    /* Avoid an empty string which would disturb us.  */
Packit Service 82fcde
    GLRO(dl_platform) = NULL;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static inline Elf32_Addr
Packit Service 82fcde
elf_machine_fixup_plt (struct link_map *map, lookup_t t,
Packit Service 82fcde
		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
Packit Service 82fcde
		       const Elf32_Rel *reloc,
Packit Service 82fcde
		       Elf32_Addr *reloc_addr, Elf32_Addr value)
Packit Service 82fcde
{
Packit Service 82fcde
  return *reloc_addr = value;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Return the final value of a plt relocation.  */
Packit Service 82fcde
static inline Elf32_Addr
Packit Service 82fcde
elf_machine_plt_value (struct link_map *map, const Elf32_Rel *reloc,
Packit Service 82fcde
		       Elf32_Addr value)
Packit Service 82fcde
{
Packit Service 82fcde
  return value;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
#endif /* !dl_machine_h */
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* ARM never uses Elf32_Rela relocations for the dynamic linker.
Packit Service 82fcde
   Prelinked libraries may use Elf32_Rela though.  */
Packit Service 82fcde
#define ELF_MACHINE_NO_RELA defined RTLD_BOOTSTRAP
Packit Service 82fcde
#define ELF_MACHINE_NO_REL 0
Packit Service 82fcde
Packit Service 82fcde
/* Names of the architecture-specific auditing callback functions.  */
Packit Service 82fcde
#define ARCH_LA_PLTENTER arm_gnu_pltenter
Packit Service 82fcde
#define ARCH_LA_PLTEXIT arm_gnu_pltexit
Packit Service 82fcde
Packit Service 82fcde
#ifdef RESOLVE_MAP
Packit Service 82fcde
/* Handle a PC24 reloc, including the out-of-range case.  */
Packit Service 82fcde
auto void
Packit Service 82fcde
relocate_pc24 (struct link_map *map, Elf32_Addr value,
Packit Service 82fcde
               Elf32_Addr *const reloc_addr, Elf32_Sword addend)
Packit Service 82fcde
{
Packit Service 82fcde
  Elf32_Addr new_value;
Packit Service 82fcde
Packit Service 82fcde
  /* Set NEW_VALUE based on V, and return true iff it overflows 24 bits.  */
Packit Service 82fcde
  inline bool set_new_value (Elf32_Addr v)
Packit Service 82fcde
  {
Packit Service 82fcde
    new_value = v + addend - (Elf32_Addr) reloc_addr;
Packit Service 82fcde
    Elf32_Addr topbits = new_value & 0xfe000000;
Packit Service 82fcde
    return topbits != 0xfe000000 && topbits != 0x00000000;
Packit Service 82fcde
  }
Packit Service 82fcde
Packit Service 82fcde
  if (set_new_value (value))
Packit Service 82fcde
    {
Packit Service 82fcde
      /* The PC-relative address doesn't fit in 24 bits!  */
Packit Service 82fcde
Packit Service 82fcde
      static void *fix_page;
Packit Service 82fcde
      static size_t fix_offset;
Packit Service 82fcde
      if (fix_page == NULL)
Packit Service 82fcde
        {
Packit Service 82fcde
          void *new_page = __mmap (NULL, GLRO(dl_pagesize),
Packit Service 82fcde
                                   PROT_READ | PROT_WRITE | PROT_EXEC,
Packit Service 82fcde
                                   MAP_PRIVATE | MAP_ANON, -1, 0);
Packit Service 82fcde
          if (new_page == MAP_FAILED)
Packit Service 82fcde
            _dl_signal_error (0, map->l_name, NULL,
Packit Service 82fcde
                              "could not map page for fixup");
Packit Service 82fcde
          fix_page = new_page;
Packit Service 82fcde
          assert (fix_offset == 0);
Packit Service 82fcde
        }
Packit Service 82fcde
Packit Service 82fcde
      Elf32_Word *fix_address = fix_page + fix_offset;
Packit Service 82fcde
      fix_address[0] = 0xe51ff004;	/* ldr pc, [pc, #-4] */
Packit Service 82fcde
      fix_address[1] = value;
Packit Service 82fcde
Packit Service 82fcde
      fix_offset += sizeof fix_address[0] * 2;
Packit Service 82fcde
      if (fix_offset >= GLRO(dl_pagesize))
Packit Service 82fcde
        {
Packit Service 82fcde
          fix_page = NULL;
Packit Service 82fcde
          fix_offset = 0;
Packit Service 82fcde
        }
Packit Service 82fcde
Packit Service 82fcde
      if (set_new_value ((Elf32_Addr) fix_address))
Packit Service 82fcde
        _dl_signal_error (0, map->l_name, NULL,
Packit Service 82fcde
                          "R_ARM_PC24 relocation out of range");
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  *reloc_addr = (*reloc_addr & 0xff000000) | ((new_value >> 2) & 0x00ffffff);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
Packit Service 82fcde
   MAP is the object containing the reloc.  */
Packit Service 82fcde
Packit Service 82fcde
auto inline void
Packit Service 82fcde
__attribute__ ((always_inline))
Packit Service 82fcde
elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
Packit Service 82fcde
		 const Elf32_Sym *sym, const struct r_found_version *version,
Packit Service 82fcde
		 void *const reloc_addr_arg, int skip_ifunc)
Packit Service 82fcde
{
Packit Service 82fcde
  Elf32_Addr *const reloc_addr = reloc_addr_arg;
Packit Service 82fcde
  const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
Packit Service 82fcde
Packit Service 82fcde
#if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
Packit Service 82fcde
  if (__builtin_expect (r_type == R_ARM_RELATIVE, 0))
Packit Service 82fcde
    {
Packit Service 82fcde
# if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
Packit Service 82fcde
      /* This is defined in rtld.c, but nowhere in the static libc.a;
Packit Service 82fcde
	 make the reference weak so static programs can still link.
Packit Service 82fcde
	 This declaration cannot be done when compiling rtld.c
Packit Service 82fcde
	 (i.e. #ifdef RTLD_BOOTSTRAP) because rtld.c contains the
Packit Service 82fcde
	 common defn for _dl_rtld_map, which is incompatible with a
Packit Service 82fcde
	 weak decl in the same file.  */
Packit Service 82fcde
#  ifndef SHARED
Packit Service 82fcde
      weak_extern (_dl_rtld_map);
Packit Service 82fcde
#  endif
Packit Service 82fcde
      if (map != &GL(dl_rtld_map)) /* Already done in rtld itself.  */
Packit Service 82fcde
# endif
Packit Service 82fcde
	*reloc_addr += map->l_addr;
Packit Service 82fcde
    }
Packit Service 82fcde
# ifndef RTLD_BOOTSTRAP
Packit Service 82fcde
  else if (__builtin_expect (r_type == R_ARM_NONE, 0))
Packit Service 82fcde
    return;
Packit Service 82fcde
# endif
Packit Service 82fcde
  else
Packit Service 82fcde
#endif
Packit Service 82fcde
    {
Packit Service 82fcde
      const Elf32_Sym *const refsym = sym;
Packit Service 82fcde
      struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
Packit Service 82fcde
      Elf32_Addr value = SYMBOL_ADDRESS (sym_map, sym, true);
Packit Service 82fcde
Packit Service 82fcde
      if (sym != NULL
Packit Service 82fcde
	  && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)
Packit Service 82fcde
	  && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1)
Packit Service 82fcde
	  && __builtin_expect (!skip_ifunc, 1))
Packit Service 82fcde
	value = elf_ifunc_invoke (value);
Packit Service 82fcde
Packit Service 82fcde
      switch (r_type)
Packit Service 82fcde
	{
Packit Service 82fcde
	case R_ARM_COPY:
Packit Service 82fcde
	  if (sym == NULL)
Packit Service 82fcde
	    /* This can happen in trace mode if an object could not be
Packit Service 82fcde
	       found.  */
Packit Service 82fcde
	    break;
Packit Service 82fcde
	  if (sym->st_size > refsym->st_size
Packit Service 82fcde
	      || (GLRO(dl_verbose) && sym->st_size < refsym->st_size))
Packit Service 82fcde
	    {
Packit Service 82fcde
	      const char *strtab;
Packit Service 82fcde
Packit Service 82fcde
	      strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
Packit Service 82fcde
	      _dl_error_printf ("\
Packit Service 82fcde
%s: Symbol `%s' has different size in shared object, consider re-linking\n",
Packit Service 82fcde
				RTLD_PROGNAME, strtab + refsym->st_name);
Packit Service 82fcde
	    }
Packit Service 82fcde
	  memcpy (reloc_addr_arg, (void *) value,
Packit Service 82fcde
		  MIN (sym->st_size, refsym->st_size));
Packit Service 82fcde
	  break;
Packit Service 82fcde
	case R_ARM_GLOB_DAT:
Packit Service 82fcde
	case R_ARM_JUMP_SLOT:
Packit Service 82fcde
# ifdef RTLD_BOOTSTRAP
Packit Service 82fcde
	  /* Fix weak undefined references.  */
Packit Service 82fcde
	  if (sym != NULL && sym->st_value == 0)
Packit Service 82fcde
	    *reloc_addr = 0;
Packit Service 82fcde
	  else
Packit Service 82fcde
# endif
Packit Service 82fcde
	    *reloc_addr = value;
Packit Service 82fcde
	  break;
Packit Service 82fcde
	case R_ARM_ABS32:
Packit Service 82fcde
	  {
Packit Service 82fcde
	    struct unaligned
Packit Service 82fcde
	      {
Packit Service 82fcde
		Elf32_Addr x;
Packit Service 82fcde
	      } __attribute__ ((packed, may_alias));
Packit Service 82fcde
# ifndef RTLD_BOOTSTRAP
Packit Service 82fcde
	   /* This is defined in rtld.c, but nowhere in the static
Packit Service 82fcde
	      libc.a; make the reference weak so static programs can
Packit Service 82fcde
	      still link.  This declaration cannot be done when
Packit Service 82fcde
	      compiling rtld.c (i.e.  #ifdef RTLD_BOOTSTRAP) because
Packit Service 82fcde
	      rtld.c contains the common defn for _dl_rtld_map, which
Packit Service 82fcde
	      is incompatible with a weak decl in the same file.  */
Packit Service 82fcde
#  ifndef SHARED
Packit Service 82fcde
	    weak_extern (_dl_rtld_map);
Packit Service 82fcde
#  endif
Packit Service 82fcde
	    if (map == &GL(dl_rtld_map))
Packit Service 82fcde
	      /* Undo the relocation done here during bootstrapping.
Packit Service 82fcde
		 Now we will relocate it anew, possibly using a
Packit Service 82fcde
		 binding found in the user program or a loaded library
Packit Service 82fcde
		 rather than the dynamic linker's built-in definitions
Packit Service 82fcde
		 used while loading those libraries.  */
Packit Service 82fcde
	      value -= SYMBOL_ADDRESS (map, refsym, true);
Packit Service 82fcde
# endif
Packit Service 82fcde
	    /* Support relocations on mis-aligned offsets.  */
Packit Service 82fcde
	    ((struct unaligned *) reloc_addr)->x += value;
Packit Service 82fcde
	    break;
Packit Service 82fcde
	  }
Packit Service 82fcde
	case R_ARM_TLS_DESC:
Packit Service 82fcde
	  {
Packit Service 82fcde
	    struct tlsdesc *td = (struct tlsdesc *)reloc_addr;
Packit Service 82fcde
Packit Service 82fcde
# ifndef RTLD_BOOTSTRAP
Packit Service 82fcde
	    if (! sym)
Packit Service 82fcde
	      td->entry = _dl_tlsdesc_undefweak;
Packit Service 82fcde
	    else
Packit Service 82fcde
# endif
Packit Service 82fcde
	      {
Packit Service 82fcde
		if (ELF32_R_SYM (reloc->r_info) == STN_UNDEF)
Packit Service 82fcde
		  value = td->argument.value;
Packit Service 82fcde
		else
Packit Service 82fcde
		  value = sym->st_value;
Packit Service 82fcde
Packit Service 82fcde
# ifndef RTLD_BOOTSTRAP
Packit Service 82fcde
#  ifndef SHARED
Packit Service 82fcde
		CHECK_STATIC_TLS (map, sym_map);
Packit Service 82fcde
#  else
Packit Service 82fcde
		if (!TRY_STATIC_TLS (map, sym_map))
Packit Service 82fcde
		  {
Packit Service 82fcde
		    td->argument.pointer
Packit Service 82fcde
		      = _dl_make_tlsdesc_dynamic (sym_map, value);
Packit Service 82fcde
		    td->entry = _dl_tlsdesc_dynamic;
Packit Service 82fcde
		  }
Packit Service 82fcde
		else
Packit Service 82fcde
#  endif
Packit Service 82fcde
# endif
Packit Service 82fcde
		{
Packit Service 82fcde
		  td->argument.value = value + sym_map->l_tls_offset;
Packit Service 82fcde
		  td->entry = _dl_tlsdesc_return;
Packit Service 82fcde
		}
Packit Service 82fcde
	      }
Packit Service 82fcde
	    }
Packit Service 82fcde
	    break;
Packit Service 82fcde
	case R_ARM_PC24:
Packit Service 82fcde
          relocate_pc24 (map, value, reloc_addr,
Packit Service 82fcde
                         /* Sign-extend the 24-bit addend in the
Packit Service 82fcde
                            instruction (which counts instructions), and
Packit Service 82fcde
                            then shift it up two so as to count bytes.  */
Packit Service 82fcde
                         (((Elf32_Sword) *reloc_addr << 8) >> 8) << 2);
Packit Service 82fcde
	  break;
Packit Service 82fcde
#if !defined RTLD_BOOTSTRAP
Packit Service 82fcde
	case R_ARM_TLS_DTPMOD32:
Packit Service 82fcde
	  /* Get the information from the link map returned by the
Packit Service 82fcde
	     resolv function.  */
Packit Service 82fcde
	  if (sym_map != NULL)
Packit Service 82fcde
	    *reloc_addr = sym_map->l_tls_modid;
Packit Service 82fcde
	  break;
Packit Service 82fcde
Packit Service 82fcde
	case R_ARM_TLS_DTPOFF32:
Packit Service 82fcde
	  if (sym != NULL)
Packit Service 82fcde
	    *reloc_addr += sym->st_value;
Packit Service 82fcde
	  break;
Packit Service 82fcde
Packit Service 82fcde
	case R_ARM_TLS_TPOFF32:
Packit Service 82fcde
	  if (sym != NULL)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      CHECK_STATIC_TLS (map, sym_map);
Packit Service 82fcde
	      *reloc_addr += sym->st_value + sym_map->l_tls_offset;
Packit Service 82fcde
	    }
Packit Service 82fcde
	  break;
Packit Service 82fcde
	case R_ARM_IRELATIVE:
Packit Service 82fcde
	  value = map->l_addr + *reloc_addr;
Packit Service 82fcde
	  value = ((Elf32_Addr (*) (int)) value) (GLRO(dl_hwcap));
Packit Service 82fcde
	  *reloc_addr = value;
Packit Service 82fcde
	  break;
Packit Service 82fcde
#endif
Packit Service 82fcde
	default:
Packit Service 82fcde
	  _dl_reloc_bad_type (map, r_type, 0);
Packit Service 82fcde
	  break;
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
# ifndef RTLD_BOOTSTRAP
Packit Service 82fcde
auto inline void
Packit Service 82fcde
__attribute__ ((always_inline))
Packit Service 82fcde
elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
Packit Service 82fcde
		  const Elf32_Sym *sym, const struct r_found_version *version,
Packit Service 82fcde
		  void *const reloc_addr_arg, int skip_ifunc)
Packit Service 82fcde
{
Packit Service 82fcde
  Elf32_Addr *const reloc_addr = reloc_addr_arg;
Packit Service 82fcde
  const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
Packit Service 82fcde
Packit Service 82fcde
  if (__builtin_expect (r_type == R_ARM_RELATIVE, 0))
Packit Service 82fcde
    *reloc_addr = map->l_addr + reloc->r_addend;
Packit Service 82fcde
  else if (__builtin_expect (r_type == R_ARM_NONE, 0))
Packit Service 82fcde
    return;
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
# ifndef RESOLVE_CONFLICT_FIND_MAP
Packit Service 82fcde
      const Elf32_Sym *const refsym = sym;
Packit Service 82fcde
# endif
Packit Service 82fcde
      struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
Packit Service 82fcde
      Elf32_Addr value = SYMBOL_ADDRESS (sym_map, sym, true);
Packit Service 82fcde
Packit Service 82fcde
      if (sym != NULL
Packit Service 82fcde
	  && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)
Packit Service 82fcde
	  && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1)
Packit Service 82fcde
	  && __builtin_expect (!skip_ifunc, 1))
Packit Service 82fcde
	value = elf_ifunc_invoke (value);
Packit Service 82fcde
Packit Service 82fcde
      switch (r_type)
Packit Service 82fcde
	{
Packit Service 82fcde
#  ifndef RESOLVE_CONFLICT_FIND_MAP
Packit Service 82fcde
	  /* Not needed for dl-conflict.c.  */
Packit Service 82fcde
	case R_ARM_COPY:
Packit Service 82fcde
	  if (sym == NULL)
Packit Service 82fcde
	    /* This can happen in trace mode if an object could not be
Packit Service 82fcde
	       found.  */
Packit Service 82fcde
	    break;
Packit Service 82fcde
	  if (sym->st_size > refsym->st_size
Packit Service 82fcde
	      || (GLRO(dl_verbose) && sym->st_size < refsym->st_size))
Packit Service 82fcde
	    {
Packit Service 82fcde
	      const char *strtab;
Packit Service 82fcde
Packit Service 82fcde
	      strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
Packit Service 82fcde
	      _dl_error_printf ("\
Packit Service 82fcde
%s: Symbol `%s' has different size in shared object, consider re-linking\n",
Packit Service 82fcde
				RTLD_PROGNAME, strtab + refsym->st_name);
Packit Service 82fcde
	    }
Packit Service 82fcde
	  memcpy (reloc_addr_arg, (void *) value,
Packit Service 82fcde
		  MIN (sym->st_size, refsym->st_size));
Packit Service 82fcde
	  break;
Packit Service 82fcde
#  endif /* !RESOLVE_CONFLICT_FIND_MAP */
Packit Service 82fcde
	case R_ARM_GLOB_DAT:
Packit Service 82fcde
	case R_ARM_JUMP_SLOT:
Packit Service 82fcde
	case R_ARM_ABS32:
Packit Service 82fcde
	  *reloc_addr = value + reloc->r_addend;
Packit Service 82fcde
	  break;
Packit Service 82fcde
	case R_ARM_PC24:
Packit Service 82fcde
          relocate_pc24 (map, value, reloc_addr, reloc->r_addend);
Packit Service 82fcde
	  break;
Packit Service 82fcde
#if !defined RTLD_BOOTSTRAP
Packit Service 82fcde
	case R_ARM_TLS_DTPMOD32:
Packit Service 82fcde
	  /* Get the information from the link map returned by the
Packit Service 82fcde
	     resolv function.  */
Packit Service 82fcde
	  if (sym_map != NULL)
Packit Service 82fcde
	    *reloc_addr = sym_map->l_tls_modid;
Packit Service 82fcde
	  break;
Packit Service 82fcde
Packit Service 82fcde
	case R_ARM_TLS_DTPOFF32:
Packit Service 82fcde
	  *reloc_addr = (sym == NULL ? 0 : sym->st_value) + reloc->r_addend;
Packit Service 82fcde
	  break;
Packit Service 82fcde
Packit Service 82fcde
	case R_ARM_TLS_TPOFF32:
Packit Service 82fcde
	  if (sym != NULL)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      CHECK_STATIC_TLS (map, sym_map);
Packit Service 82fcde
	      *reloc_addr = (sym->st_value + sym_map->l_tls_offset
Packit Service 82fcde
			     + reloc->r_addend);
Packit Service 82fcde
	    }
Packit Service 82fcde
	  break;
Packit Service 82fcde
	case R_ARM_IRELATIVE:
Packit Service 82fcde
	  value = map->l_addr + reloc->r_addend;
Packit Service 82fcde
	  value = ((Elf32_Addr (*) (int)) value) (GLRO(dl_hwcap));
Packit Service 82fcde
	  *reloc_addr = value;
Packit Service 82fcde
	  break;
Packit Service 82fcde
#endif
Packit Service 82fcde
	default:
Packit Service 82fcde
	  _dl_reloc_bad_type (map, r_type, 0);
Packit Service 82fcde
	  break;
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
# endif
Packit Service 82fcde
Packit Service 82fcde
auto inline void
Packit Service 82fcde
__attribute__ ((always_inline))
Packit Service 82fcde
elf_machine_rel_relative (Elf32_Addr l_addr, const Elf32_Rel *reloc,
Packit Service 82fcde
			  void *const reloc_addr_arg)
Packit Service 82fcde
{
Packit Service 82fcde
  Elf32_Addr *const reloc_addr = reloc_addr_arg;
Packit Service 82fcde
  *reloc_addr += l_addr;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
# ifndef RTLD_BOOTSTRAP
Packit Service 82fcde
auto inline void
Packit Service 82fcde
__attribute__ ((always_inline))
Packit Service 82fcde
elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
Packit Service 82fcde
			   void *const reloc_addr_arg)
Packit Service 82fcde
{
Packit Service 82fcde
  Elf32_Addr *const reloc_addr = reloc_addr_arg;
Packit Service 82fcde
  *reloc_addr = l_addr + reloc->r_addend;
Packit Service 82fcde
}
Packit Service 82fcde
# endif
Packit Service 82fcde
Packit Service 82fcde
auto inline void
Packit Service 82fcde
__attribute__ ((always_inline))
Packit Service 82fcde
elf_machine_lazy_rel (struct link_map *map,
Packit Service 82fcde
		      Elf32_Addr l_addr, const Elf32_Rel *reloc,
Packit Service 82fcde
		      int skip_ifunc)
Packit Service 82fcde
{
Packit Service 82fcde
  Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
Packit Service 82fcde
  const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
Packit Service 82fcde
  /* Check for unexpected PLT reloc type.  */
Packit Service 82fcde
  if (__builtin_expect (r_type == R_ARM_JUMP_SLOT, 1))
Packit Service 82fcde
    {
Packit Service 82fcde
      if (__builtin_expect (map->l_mach.plt, 0) == 0)
Packit Service 82fcde
	*reloc_addr += l_addr;
Packit Service 82fcde
      else
Packit Service 82fcde
	*reloc_addr = map->l_mach.plt;
Packit Service 82fcde
    }
Packit Service 82fcde
  else if (__builtin_expect (r_type == R_ARM_TLS_DESC, 1))
Packit Service 82fcde
    {
Packit Service 82fcde
      const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info);
Packit Service 82fcde
      const ElfW (Sym) *symtab = (const void *)D_PTR (map, l_info[DT_SYMTAB]);
Packit Service 82fcde
      const ElfW (Sym) *sym = &symtab[symndx];
Packit Service 82fcde
      const struct r_found_version *version = NULL;
Packit Service 82fcde
Packit Service 82fcde
      if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
Packit Service 82fcde
	{
Packit Service 82fcde
	  const ElfW (Half) *vernum =
Packit Service 82fcde
	    (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
Packit Service 82fcde
	  version = &map->l_versions[vernum[symndx] & 0x7fff];
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      /* Always initialize TLS descriptors completely, because lazy
Packit Service 82fcde
	 initialization requires synchronization at every TLS access.  */
Packit Service 82fcde
      elf_machine_rel (map, reloc, sym, version, reloc_addr, skip_ifunc);
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    _dl_reloc_bad_type (map, r_type, 1);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
#endif /* RESOLVE_MAP */