Blame sysdeps/hppa/dl-machine.h

Packit 6c4009
/* Machine-dependent ELF dynamic relocation inline functions.  PA-RISC version.
Packit 6c4009
   Copyright (C) 1995-2018 Free Software Foundation, Inc.
Packit 6c4009
   Contributed by David Huggins-Daines <dhd@debian.org>
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 1
Packit 6c4009
Packit 6c4009
#define ELF_MACHINE_NAME "hppa"
Packit 6c4009
Packit 6c4009
#include <sys/param.h>
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <link.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <dl-fptr.h>
Packit 6c4009
#include <abort-instr.h>
Packit 6c4009
#include <tls.h>
Packit 6c4009
Packit 6c4009
/* These two definitions must match the definition of the stub in
Packit 6c4009
   bfd/elf32-hppa.c (see plt_stub[]).
Packit 6c4009
Packit 6c4009
   a. Define the size of the *entire* stub we place at the end of the PLT
Packit 6c4009
   table (right up against the GOT).
Packit 6c4009
Packit 6c4009
   b. Define the number of bytes back from the GOT to the entry point of
Packit 6c4009
   the PLT stub. You see the PLT stub must be entered in the middle
Packit 6c4009
   so it can depwi to find it's own address (long jump stub)
Packit 6c4009
Packit 6c4009
   c. Define the size of a single PLT entry so we can jump over the
Packit 6c4009
   last entry to get the stub address */
Packit 6c4009
Packit 6c4009
#define SIZEOF_PLT_STUB (7*4)
Packit 6c4009
#define GOT_FROM_PLT_STUB (4*4)
Packit 6c4009
#define PLT_ENTRY_SIZE (2*4)
Packit 6c4009
Packit 6c4009
/* Initialize the function descriptor table before relocations */
Packit 6c4009
static inline void
Packit 6c4009
__hppa_init_bootstrap_fdesc_table (struct link_map *map)
Packit 6c4009
{
Packit 6c4009
  ElfW(Addr) *boot_table;
Packit 6c4009
Packit 6c4009
  /* Careful: this will be called before got has been relocated... */
Packit 6c4009
  ELF_MACHINE_LOAD_ADDRESS(boot_table,_dl_boot_fptr_table);
Packit 6c4009
Packit 6c4009
  map->l_mach.fptr_table_len = ELF_MACHINE_BOOT_FPTR_TABLE_LEN;
Packit 6c4009
  map->l_mach.fptr_table = boot_table;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info)		\
Packit 6c4009
	__hppa_init_bootstrap_fdesc_table (BOOTSTRAP_MAP);	\
Packit 6c4009
	_dl_fptr_init();
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
  return ehdr->e_machine == EM_PARISC;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Return the link-time address of _DYNAMIC.  */
Packit 6c4009
static inline Elf32_Addr
Packit 6c4009
elf_machine_dynamic (void) __attribute__ ((const));
Packit 6c4009
Packit 6c4009
static inline Elf32_Addr
Packit 6c4009
elf_machine_dynamic (void)
Packit 6c4009
{
Packit 6c4009
  Elf32_Addr dynamic;
Packit 6c4009
Packit 6c4009
  asm ("bl	1f,%0\n"
Packit 6c4009
"	addil	L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 1),%0\n"
Packit 6c4009
"1:	ldw	R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 5)(%%r1),%0\n"
Packit 6c4009
       : "=r" (dynamic) : : "r1");
Packit 6c4009
Packit 6c4009
  return dynamic;
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) __attribute__ ((const));
Packit 6c4009
Packit 6c4009
static inline Elf32_Addr
Packit 6c4009
elf_machine_load_address (void)
Packit 6c4009
{
Packit 6c4009
  Elf32_Addr dynamic;
Packit 6c4009
Packit 6c4009
  asm (
Packit 6c4009
"	bl	1f,%0\n"
Packit 6c4009
"	addil	L'_DYNAMIC - ($PIC_pcrel$0 - 1),%0\n"
Packit 6c4009
"1:	ldo	R'_DYNAMIC - ($PIC_pcrel$0 - 5)(%%r1),%0\n"
Packit 6c4009
   : "=r" (dynamic) : : "r1");
Packit 6c4009
Packit 6c4009
  return dynamic - elf_machine_dynamic ();
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Fixup a PLT entry to bounce directly to the function at VALUE. */
Packit 6c4009
static inline struct fdesc __attribute__ ((always_inline))
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, struct fdesc value)
Packit 6c4009
{
Packit 6c4009
  volatile Elf32_Addr *rfdesc = reloc_addr;
Packit 6c4009
  /* map is the link_map for the caller, t is the link_map for the object
Packit 6c4009
     being called */
Packit 6c4009
  rfdesc[1] = value.gp;
Packit 6c4009
  /* Need to ensure that the gp is visible before the code
Packit 6c4009
     entry point is updated */
Packit 6c4009
  rfdesc[0] = value.ip;
Packit 6c4009
  return value;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Return the final value of a plt relocation.  */
Packit 6c4009
static inline struct fdesc
Packit 6c4009
elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
Packit 6c4009
		       struct fdesc value)
Packit 6c4009
{
Packit 6c4009
  /* We are rela only, return a function descriptor as a plt entry. */
Packit 6c4009
  return (struct fdesc) { value.ip + reloc->r_addend, value.gp };
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 *got = NULL;
Packit 6c4009
  Elf32_Addr l_addr, iplt, jmprel, end_jmprel, r_type, r_sym;
Packit 6c4009
  const Elf32_Rela *reloc;
Packit 6c4009
  struct fdesc *fptr;
Packit 6c4009
  static union {
Packit 6c4009
    unsigned char c[8];
Packit 6c4009
    Elf32_Addr i[2];
Packit 6c4009
  } sig = {{0x00,0xc0,0xff,0xee, 0xde,0xad,0xbe,0xef}};
Packit 6c4009
Packit 6c4009
  /* If we don't have a PLT we can just skip all this... */
Packit 6c4009
  if (__builtin_expect (l->l_info[DT_JMPREL] == NULL,0))
Packit 6c4009
    return lazy;
Packit 6c4009
Packit 6c4009
  /* All paths use these values */
Packit 6c4009
  l_addr = l->l_addr;
Packit 6c4009
  jmprel = D_PTR(l, l_info[DT_JMPREL]);
Packit 6c4009
  end_jmprel = jmprel + l->l_info[DT_PLTRELSZ]->d_un.d_val;
Packit 6c4009
Packit 6c4009
  extern void _dl_runtime_resolve (void);
Packit 6c4009
  extern void _dl_runtime_profile (void);
Packit 6c4009
Packit 6c4009
  /* Linking lazily */
Packit 6c4009
  if (lazy)
Packit 6c4009
    {
Packit 6c4009
      /* FIXME: Search for the got, but backwards through the relocs, technically we should
Packit 6c4009
	 find it on the first try. However, assuming the relocs got out of order the
Packit 6c4009
	 routine is made a bit more robust by searching them all in case of failure. */
Packit 6c4009
      for (iplt = (end_jmprel - sizeof(Elf32_Rela)); iplt >= jmprel; iplt -= sizeof (Elf32_Rela))
Packit 6c4009
	{
Packit 6c4009
Packit 6c4009
	  reloc = (const Elf32_Rela *) iplt;
Packit 6c4009
	  r_type = ELF32_R_TYPE (reloc->r_info);
Packit 6c4009
	  r_sym = ELF32_R_SYM (reloc->r_info);
Packit 6c4009
Packit 6c4009
	  got = (Elf32_Addr *) (reloc->r_offset + l_addr + PLT_ENTRY_SIZE + SIZEOF_PLT_STUB);
Packit 6c4009
Packit 6c4009
	  /* If we aren't an IPLT, and we aren't NONE then it's a bad reloc */
Packit 6c4009
	  if (__builtin_expect (r_type != R_PARISC_IPLT, 0))
Packit 6c4009
	    {
Packit 6c4009
	      if (__builtin_expect (r_type != R_PARISC_NONE, 0))
Packit 6c4009
		_dl_reloc_bad_type (l, r_type, 1);
Packit 6c4009
	      continue;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* Check for the plt_stub that binutils placed here for us
Packit 6c4009
	     to use with _dl_runtime_resolve  */
Packit 6c4009
	  if (got[-2] != sig.i[0] || got[-1] != sig.i[1])
Packit 6c4009
	    {
Packit 6c4009
	      got = NULL; /* Not the stub... keep looking */
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    {
Packit 6c4009
	      /* Found the GOT! */
Packit 6c4009
	      register Elf32_Addr ltp __asm__ ("%r19");
Packit 6c4009
Packit 6c4009
	      /* Identify this shared object. Second entry in the got. */
Packit 6c4009
	      got[1] = (Elf32_Addr) l;
Packit 6c4009
Packit 6c4009
	      /* This function will be called to perform the relocation. */
Packit 6c4009
	      if (__builtin_expect (!profile, 1))
Packit 6c4009
		{
Packit 6c4009
		  /* If a static application called us, then _dl_runtime_resolve is not
Packit 6c4009
		     a function descriptor, but the *real* address of the function... */
Packit 6c4009
		  if((unsigned long) &_dl_runtime_resolve & 3)
Packit 6c4009
		    {
Packit 6c4009
		      got[-2] = (Elf32_Addr) ((struct fdesc *)
Packit 6c4009
				  ((unsigned long) &_dl_runtime_resolve & ~3))->ip;
Packit 6c4009
		    }
Packit 6c4009
		  else
Packit 6c4009
		    {
Packit 6c4009
		      /* Static executable! */
Packit 6c4009
		      got[-2] = (Elf32_Addr) &_dl_runtime_resolve;
Packit 6c4009
		    }
Packit 6c4009
		}
Packit 6c4009
	      else
Packit 6c4009
		{
Packit 6c4009
		  if (GLRO(dl_profile) != NULL
Packit 6c4009
		      && _dl_name_match_p (GLRO(dl_profile), l))
Packit 6c4009
		    {
Packit 6c4009
		      /* This is the object we are looking for.  Say that
Packit 6c4009
			 we really want profiling and the timers are
Packit 6c4009
			 started.  */
Packit 6c4009
		      GL(dl_profile_map) = l;
Packit 6c4009
		    }
Packit 6c4009
Packit 6c4009
		  if((unsigned long) &_dl_runtime_profile & 3)
Packit 6c4009
		    {
Packit 6c4009
		      got[-2] = (Elf32_Addr) ((struct fdesc *)
Packit 6c4009
				  ((unsigned long) &_dl_runtime_profile & ~3))->ip;
Packit 6c4009
		    }
Packit 6c4009
		  else
Packit 6c4009
		    {
Packit 6c4009
		      /* Static executable */
Packit 6c4009
		      got[-2] = (Elf32_Addr) &_dl_runtime_profile;
Packit 6c4009
		    }
Packit 6c4009
		}
Packit 6c4009
	      /* Plunk in the gp of this function descriptor so we
Packit 6c4009
		 can make the call to _dl_runtime_xxxxxx */
Packit 6c4009
	      got[-1] = ltp;
Packit 6c4009
	      break;
Packit 6c4009
	      /* Done looking for the GOT, and stub is setup */
Packit 6c4009
	    } /* else we found the GOT */
Packit 6c4009
	} /* for, walk the relocs backwards */
Packit 6c4009
Packit 6c4009
      if(!got)
Packit 6c4009
	return 0; /* No lazy linking for you! */
Packit 6c4009
Packit 6c4009
      /* Process all the relocs, now that we know the GOT... */
Packit 6c4009
      for (iplt = jmprel; iplt < end_jmprel; iplt += sizeof (Elf32_Rela))
Packit 6c4009
	{
Packit 6c4009
	  reloc = (const Elf32_Rela *) iplt;
Packit 6c4009
	  r_type = ELF32_R_TYPE (reloc->r_info);
Packit 6c4009
	  r_sym = ELF32_R_SYM (reloc->r_info);
Packit 6c4009
Packit 6c4009
	  if (__builtin_expect (r_type == R_PARISC_IPLT, 1))
Packit 6c4009
	    {
Packit 6c4009
	      fptr = (struct fdesc *) (reloc->r_offset + l_addr);
Packit 6c4009
	      if (r_sym != 0)
Packit 6c4009
		{
Packit 6c4009
		  /* Relocate the pointer to the stub.  */
Packit 6c4009
		  fptr->ip = (Elf32_Addr) got - GOT_FROM_PLT_STUB;
Packit 6c4009
Packit 6c4009
		  /* Instead of the LTP value, we put the reloc offset
Packit 6c4009
		     here.  The trampoline code will load the proper
Packit 6c4009
		     LTP and pass the reloc offset to the fixup
Packit 6c4009
		     function.  */
Packit 6c4009
		  fptr->gp = iplt - jmprel;
Packit 6c4009
		} /* r_sym != 0 */
Packit 6c4009
	      else
Packit 6c4009
		{
Packit 6c4009
		  /* Relocate this *ABS* entry.  */
Packit 6c4009
		  fptr->ip = reloc->r_addend + l_addr;
Packit 6c4009
		  fptr->gp = D_PTR (l, l_info[DT_PLTGOT]);
Packit 6c4009
		}
Packit 6c4009
	    } /* r_type == R_PARISC_IPLT */
Packit 6c4009
	} /* for all the relocations */
Packit 6c4009
    } /* if lazy */
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      for (iplt = jmprel; iplt < end_jmprel; iplt += sizeof (Elf32_Rela))
Packit 6c4009
	{
Packit 6c4009
	  reloc = (const Elf32_Rela *) iplt;
Packit 6c4009
	  r_type = ELF32_R_TYPE (reloc->r_info);
Packit 6c4009
	  r_sym = ELF32_R_SYM (reloc->r_info);
Packit 6c4009
Packit 6c4009
	  if (__builtin_expect ((r_type == R_PARISC_IPLT) && (r_sym == 0), 1))
Packit 6c4009
	    {
Packit 6c4009
	      fptr = (struct fdesc *) (reloc->r_offset + l_addr);
Packit 6c4009
	      /* Relocate this *ABS* entry, set only the gp, the rest is set later
Packit 6c4009
		 when elf_machine_rela_relative is called (WITHOUT the linkmap)  */
Packit 6c4009
	      fptr->gp = D_PTR (l, l_info[DT_PLTGOT]);
Packit 6c4009
	    } /* r_type == R_PARISC_IPLT */
Packit 6c4009
	} /* for all the relocations */
Packit 6c4009
    }
Packit 6c4009
  return lazy;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Names of the architecture-specific auditing callback functions.  */
Packit 6c4009
#define ARCH_LA_PLTENTER hppa_gnu_pltenter
Packit 6c4009
#define ARCH_LA_PLTEXIT hppa_gnu_pltexit
Packit 6c4009
Packit 6c4009
/* Adjust DL_STACK_END to get value we want in __libc_stack_end.  */
Packit 6c4009
#define DL_STACK_END(cookie) \
Packit 6c4009
  ((void *) (((long) (cookie)) + 0x160))
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 \
Packit 6c4009
/* Set up dp for any non-PIC lib constructors that may be called.  */	\
Packit 6c4009
static struct link_map * __attribute__((used))				\
Packit 6c4009
set_dp (struct link_map *map)						\
Packit 6c4009
{									\
Packit 6c4009
  register Elf32_Addr dp asm ("%r27");					\
Packit 6c4009
  dp = D_PTR (map, l_info[DT_PLTGOT]);					\
Packit 6c4009
  asm volatile ("" : : "r" (dp));					\
Packit 6c4009
  return map;								\
Packit 6c4009
}									\
Packit 6c4009
									\
Packit 6c4009
asm (									\
Packit 6c4009
"	.text\n"							\
Packit 6c4009
"	.globl _start\n"						\
Packit 6c4009
"	.type _start,@function\n"					\
Packit 6c4009
"_start:\n"								\
Packit 6c4009
	/* The kernel does not give us an initial stack frame. */	\
Packit 6c4009
"	ldo	64(%sp),%sp\n"						\
Packit 6c4009
	/* Save the relevant arguments (yes, those are the correct	\
Packit 6c4009
	   registers, the kernel is weird) in their stack slots. */	\
Packit 6c4009
"	stw	%r25,-40(%sp)\n" /* argc */				\
Packit 6c4009
"	stw	%r24,-44(%sp)\n" /* argv */				\
Packit 6c4009
									\
Packit 6c4009
	/* We need the LTP, and we need it now.				\
Packit 6c4009
	   $PIC_pcrel$0 points 8 bytes past the current instruction,	\
Packit 6c4009
	   just like a branch reloc.  This sequence gets us the		\
Packit 6c4009
	   runtime address of _DYNAMIC. */				\
Packit 6c4009
"	bl	0f,%r19\n"						\
Packit 6c4009
"	addil	L'_DYNAMIC - ($PIC_pcrel$0 - 1),%r19\n"			\
Packit 6c4009
"0:	ldo	R'_DYNAMIC - ($PIC_pcrel$0 - 5)(%r1),%r26\n"		\
Packit 6c4009
									\
Packit 6c4009
	/* The link time address is stored in the first entry of the	\
Packit 6c4009
	   GOT.  */							\
Packit 6c4009
"	addil	L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 9),%r19\n"	\
Packit 6c4009
"	ldw	R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 13)(%r1),%r20\n" \
Packit 6c4009
									\
Packit 6c4009
"	sub	%r26,%r20,%r20\n"	/* Calculate load offset */	\
Packit 6c4009
									\
Packit 6c4009
	/* Rummage through the dynamic entries, looking for		\
Packit 6c4009
	   DT_PLTGOT.  */						\
Packit 6c4009
"	ldw,ma	8(%r26),%r19\n"						\
Packit 6c4009
"1:	cmpib,=,n 3,%r19,2f\n"	/* tag == DT_PLTGOT? */			\
Packit 6c4009
"	cmpib,<>,n 0,%r19,1b\n"						\
Packit 6c4009
"	ldw,ma	8(%r26),%r19\n"						\
Packit 6c4009
									\
Packit 6c4009
	/* Uh oh!  We didn't find one.  Abort. */			\
Packit 6c4009
"	iitlbp	%r0,(%sr0,%r0)\n"					\
Packit 6c4009
									\
Packit 6c4009
"2:	ldw	-4(%r26),%r19\n"	/* Found it, load value. */	\
Packit 6c4009
"	add	%r19,%r20,%r19\n"	/* And add the load offset. */	\
Packit 6c4009
									\
Packit 6c4009
	/* Our initial stack layout is rather different from everyone	\
Packit 6c4009
	   else's due to the unique PA-RISC ABI.  As far as I know it	\
Packit 6c4009
	   looks like this:						\
Packit 6c4009
									\
Packit 6c4009
	   -----------------------------------  (this frame created above) \
Packit 6c4009
	   |         32 bytes of magic       |				\
Packit 6c4009
	   |---------------------------------|				\
Packit 6c4009
	   | 32 bytes argument/sp save area  |				\
Packit 6c4009
	   |---------------------------------|  ((current->mm->env_end)	\
Packit 6c4009
	   |         N bytes of slack        |	 + 63 & ~63)		\
Packit 6c4009
	   |---------------------------------|				\
Packit 6c4009
	   |      envvar and arg strings     |				\
Packit 6c4009
	   |---------------------------------|				\
Packit 6c4009
	   |	    ELF auxiliary info	     |				\
Packit 6c4009
	   |         (up to 28 words)        |				\
Packit 6c4009
	   |---------------------------------|				\
Packit 6c4009
	   |  Environment variable pointers  |				\
Packit 6c4009
	   |         upwards to NULL	     |				\
Packit 6c4009
	   |---------------------------------|				\
Packit 6c4009
	   |        Argument pointers        |				\
Packit 6c4009
	   |         upwards to NULL	     |				\
Packit 6c4009
	   |---------------------------------|				\
Packit 6c4009
	   |          argc (1 word)          |				\
Packit 6c4009
	   -----------------------------------				\
Packit 6c4009
									\
Packit 6c4009
	  So, obviously, we can't just pass %sp to _dl_start.  That's	\
Packit 6c4009
	  okay, argv-4 will do just fine.				\
Packit 6c4009
									\
Packit 6c4009
	  The pleasant part of this is that if we need to skip		\
Packit 6c4009
	  arguments we can just decrement argc and move argv, because	\
Packit 6c4009
	  the stack pointer is utterly unrelated to the location of	\
Packit 6c4009
	  the environment and argument vectors. */			\
Packit 6c4009
									\
Packit 6c4009
	/* This is always within range so we'll be okay. */		\
Packit 6c4009
"	bl	_dl_start,%rp\n"					\
Packit 6c4009
"	ldo	-4(%r24),%r26\n"					\
Packit 6c4009
									\
Packit 6c4009
"	.globl _dl_start_user\n"					\
Packit 6c4009
"	.type _dl_start_user,@function\n"				\
Packit 6c4009
"_dl_start_user:\n"							\
Packit 6c4009
	/* Save the entry point in %r3. */				\
Packit 6c4009
"	copy	%ret0,%r3\n"						\
Packit 6c4009
									\
Packit 6c4009
	/* See if we were called as a command with the executable file	\
Packit 6c4009
	   name as an extra leading argument. */			\
Packit 6c4009
"	addil	LT'_dl_skip_args,%r19\n"				\
Packit 6c4009
"	ldw	RT'_dl_skip_args(%r1),%r20\n"				\
Packit 6c4009
"	ldw	0(%r20),%r20\n"						\
Packit 6c4009
									\
Packit 6c4009
"	ldw	-40(%sp),%r25\n"	/* argc */			\
Packit 6c4009
"	comib,=	0,%r20,.Lnofix\n"	/* FIXME: Mispredicted branch */\
Packit 6c4009
"	ldw	-44(%sp),%r24\n"	/* argv (delay slot) */		\
Packit 6c4009
									\
Packit 6c4009
"	sub	%r25,%r20,%r25\n"					\
Packit 6c4009
"	stw	%r25,-40(%sp)\n"					\
Packit 6c4009
"	sh2add	%r20,%r24,%r24\n"					\
Packit 6c4009
"	stw	%r24,-44(%sp)\n"					\
Packit 6c4009
									\
Packit 6c4009
".Lnofix:\n"								\
Packit 6c4009
"	addil	LT'_rtld_local,%r19\n"					\
Packit 6c4009
"	ldw	RT'_rtld_local(%r1),%r26\n"				\
Packit 6c4009
"	bl	set_dp, %r2\n"						\
Packit 6c4009
"	ldw	0(%r26),%r26\n"						\
Packit 6c4009
									\
Packit 6c4009
	/* Call _dl_init(_dl_loaded, argc, argv, envp). */		\
Packit 6c4009
"	copy	%r28,%r26\n"						\
Packit 6c4009
									\
Packit 6c4009
	/* envp = argv + argc + 1 */					\
Packit 6c4009
"	sh2add	%r25,%r24,%r23\n"					\
Packit 6c4009
"	bl	_dl_init,%r2\n"						\
Packit 6c4009
"	ldo	4(%r23),%r23\n"	/* delay slot */			\
Packit 6c4009
									\
Packit 6c4009
	/* Reload argc, argv to the registers start.S expects.  */	\
Packit 6c4009
"	ldw	-40(%sp),%r25\n"					\
Packit 6c4009
"	ldw	-44(%sp),%r24\n"					\
Packit 6c4009
									\
Packit 6c4009
	/* _dl_fini is a local function in the loader, so we construct	\
Packit 6c4009
	   a false OPD here and pass this to the application.  */	\
Packit 6c4009
	/* FIXME: Should be able to use P%, and LR RR to have the	\
Packit 6c4009
	   the linker construct a proper OPD.  */			\
Packit 6c4009
"	.section .data\n"						\
Packit 6c4009
"__dl_fini_plabel:\n"							\
Packit 6c4009
"	.word	_dl_fini\n"						\
Packit 6c4009
"	.word	0xdeadbeef\n"						\
Packit 6c4009
"	.previous\n"							\
Packit 6c4009
									\
Packit 6c4009
	/* %r3 contains a function pointer, we need to mask out the	\
Packit 6c4009
	   lower bits and load the gp and jump address. */		\
Packit 6c4009
"	depi	0,31,2,%r3\n"						\
Packit 6c4009
"	ldw	0(%r3),%r2\n"						\
Packit 6c4009
"	addil	LT'__dl_fini_plabel,%r19\n"				\
Packit 6c4009
"	ldw	RT'__dl_fini_plabel(%r1),%r23\n"			\
Packit 6c4009
"	stw	%r19,4(%r23)\n"						\
Packit 6c4009
"	ldw	4(%r3),%r19\n"	/* load the object's gp */		\
Packit 6c4009
"	bv	%r0(%r2)\n"						\
Packit 6c4009
"	depi	2,31,2,%r23\n"	/* delay slot */			\
Packit 6c4009
);
Packit 6c4009
Packit 6c4009
/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
Packit 6c4009
   a TLS variable, so references 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
#if !defined RTLD_BOOTSTRAP
Packit 6c4009
# define elf_machine_type_class(type)				\
Packit 6c4009
  ((((type) == R_PARISC_IPLT					\
Packit 6c4009
  || (type) == R_PARISC_EPLT					\
Packit 6c4009
  || (type) == R_PARISC_TLS_DTPMOD32				\
Packit 6c4009
  || (type) == R_PARISC_TLS_DTPOFF32				\
Packit 6c4009
  || (type) == R_PARISC_TLS_TPREL32)				\
Packit 6c4009
  * ELF_RTYPE_CLASS_PLT)					\
Packit 6c4009
  | (((type) == R_PARISC_COPY) * ELF_RTYPE_CLASS_COPY))
Packit 6c4009
#else
Packit 6c4009
#define elf_machine_type_class(type)				\
Packit 6c4009
 ((((type) == R_PARISC_IPLT					\
Packit 6c4009
   || (type) == R_PARISC_EPLT)					\
Packit 6c4009
   * ELF_RTYPE_CLASS_PLT)					\
Packit 6c4009
   | (((type) == R_PARISC_COPY) * ELF_RTYPE_CLASS_COPY))
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Used by the runtime in fixup to figure out if reloc is *really* PLT */
Packit 6c4009
#define ELF_MACHINE_JMP_SLOT R_PARISC_IPLT
Packit 6c4009
#define ELF_MACHINE_SIZEOF_JMP_SLOT PLT_ENTRY_SIZE
Packit 6c4009
Packit 6c4009
/* We only use RELA. */
Packit 6c4009
#define ELF_MACHINE_NO_REL 1
Packit 6c4009
#define ELF_MACHINE_NO_RELA 0
Packit 6c4009
Packit 6c4009
/* Return the address of the entry point. */
Packit 6c4009
#define ELF_MACHINE_START_ADDRESS(map, start)			\
Packit 6c4009
({								\
Packit 6c4009
	ElfW(Addr) addr;					\
Packit 6c4009
	DL_DT_FUNCTION_ADDRESS(map, start, static, addr)	\
Packit 6c4009
	addr;							\
Packit 6c4009
})
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
#endif /* !dl_machine_h */
Packit 6c4009
Packit 6c4009
/* These are only actually used where RESOLVE_MAP is defined, anyway. */
Packit 6c4009
#ifdef RESOLVE_MAP
Packit 6c4009
Packit 6c4009
#define reassemble_21(as21) \
Packit 6c4009
  (  (((as21) & 0x100000) >> 20) \
Packit 6c4009
   | (((as21) & 0x0ffe00) >> 8) \
Packit 6c4009
   | (((as21) & 0x000180) << 7) \
Packit 6c4009
   | (((as21) & 0x00007c) << 14) \
Packit 6c4009
   | (((as21) & 0x000003) << 12))
Packit 6c4009
Packit 6c4009
#define reassemble_14(as14) \
Packit 6c4009
  (  (((as14) & 0x1fff) << 1) \
Packit 6c4009
   | (((as14) & 0x2000) >> 13))
Packit 6c4009
Packit 6c4009
auto void __attribute__((always_inline))
Packit 6c4009
elf_machine_rela (struct link_map *map,
Packit 6c4009
		  const Elf32_Rela *reloc,
Packit 6c4009
		  const Elf32_Sym *sym,
Packit 6c4009
		  const struct r_found_version *version,
Packit 6c4009
		  void *const reloc_addr_arg,
Packit 6c4009
		  int skip_ifunc)
Packit 6c4009
{
Packit 6c4009
  Elf32_Addr *const reloc_addr = reloc_addr_arg;
Packit 6c4009
  const Elf32_Sym *const refsym = sym;
Packit 6c4009
  unsigned long const r_type = ELF32_R_TYPE (reloc->r_info);
Packit 6c4009
  struct link_map *sym_map;
Packit 6c4009
  Elf32_Addr value;
Packit 6c4009
Packit 6c4009
# if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC && !defined SHARED
Packit 6c4009
  /* This is defined in rtld.c, but nowhere in the static libc.a; make the
Packit 6c4009
     reference weak so static programs can still link.  This declaration
Packit 6c4009
     cannot be done when compiling rtld.c (i.e.  #ifdef RTLD_BOOTSTRAP)
Packit 6c4009
     because rtld.c contains the common defn for _dl_rtld_map, which is
Packit 6c4009
     incompatible with a weak decl in the same file.  */
Packit 6c4009
  weak_extern (GL(dl_rtld_map));
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
  /* RESOLVE_MAP will return a null value for undefined syms, and
Packit 6c4009
     non-null for all other syms.  In particular, relocs with no
Packit 6c4009
     symbol (symbol index of zero), also called *ABS* relocs, will be
Packit 6c4009
     resolved to MAP.  (The first entry in a symbol table is all
Packit 6c4009
     zeros, and an all zero Elf32_Sym has a binding of STB_LOCAL.)
Packit 6c4009
     See RESOLVE_MAP definition in elf/dl-reloc.c  */
Packit 6c4009
# ifdef RTLD_BOOTSTRAP
Packit 6c4009
  /* RESOLVE_MAP in rtld.c doesn't have the local sym test.  */
Packit 6c4009
  sym_map = (ELF32_ST_BIND (sym->st_info) != STB_LOCAL
Packit 6c4009
	     ? RESOLVE_MAP (&sym, version, r_type) : map);
Packit 6c4009
# else
Packit 6c4009
  sym_map = RESOLVE_MAP (&sym, version, r_type);
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
  if (sym_map)
Packit 6c4009
    {
Packit 6c4009
      value = SYMBOL_ADDRESS (sym_map, sym, true);
Packit 6c4009
      value += reloc->r_addend;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    value = 0;
Packit 6c4009
Packit 6c4009
  switch (r_type)
Packit 6c4009
    {
Packit 6c4009
    case R_PARISC_DIR32:
Packit 6c4009
      /* .eh_frame can have unaligned relocs.  */
Packit 6c4009
      if ((unsigned long) reloc_addr_arg & 3)
Packit 6c4009
	{
Packit 6c4009
	  char *rel_addr = (char *) reloc_addr_arg;
Packit 6c4009
	  rel_addr[0] = value >> 24;
Packit 6c4009
	  rel_addr[1] = value >> 16;
Packit 6c4009
	  rel_addr[2] = value >> 8;
Packit 6c4009
	  rel_addr[3] = value;
Packit 6c4009
	  return;
Packit 6c4009
	}
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PARISC_DIR21L:
Packit 6c4009
      {
Packit 6c4009
	unsigned int insn = *(unsigned int *)reloc_addr;
Packit 6c4009
	value = (SYMBOL_ADDRESS (sym_map, sym, true)
Packit 6c4009
		 + ((reloc->r_addend + 0x1000) & -0x2000));
Packit 6c4009
	value = value >> 11;
Packit 6c4009
	insn = (insn &~ 0x1fffff) | reassemble_21 (value);
Packit 6c4009
	*(unsigned int *)reloc_addr = insn;
Packit 6c4009
      }
Packit 6c4009
      return;
Packit 6c4009
Packit 6c4009
    case R_PARISC_DIR14R:
Packit 6c4009
      {
Packit 6c4009
	unsigned int insn = *(unsigned int *)reloc_addr;
Packit 6c4009
	value = ((SYMBOL_ADDRESS (sym_map, sym, true) & 0x7ff)
Packit 6c4009
		 + (((reloc->r_addend & 0x1fff) ^ 0x1000) - 0x1000));
Packit 6c4009
	insn = (insn &~ 0x3fff) | reassemble_14 (value);
Packit 6c4009
	*(unsigned int *)reloc_addr = insn;
Packit 6c4009
      }
Packit 6c4009
      return;
Packit 6c4009
Packit 6c4009
    case R_PARISC_PLABEL32:
Packit 6c4009
      /* Easy rule: If there is a symbol and it is global, then we
Packit 6c4009
	 need to make a dynamic function descriptor.  Otherwise we
Packit 6c4009
	 have the address of a PLT slot for a local symbol which we
Packit 6c4009
	 know to be unique. */
Packit 6c4009
      if (sym == NULL
Packit 6c4009
	  || sym_map == NULL
Packit 6c4009
	  || ELF32_ST_BIND (sym->st_info) == STB_LOCAL)
Packit 6c4009
	{
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
      /* Set bit 30 to indicate to $$dyncall that this is a PLABEL.
Packit 6c4009
	 We have to do this outside of the generic function descriptor
Packit 6c4009
	 code, since it doesn't know about our requirement for setting
Packit 6c4009
	 protection bits */
Packit 6c4009
      value = (Elf32_Addr)((unsigned int)_dl_make_fptr (sym_map, sym, value) | 2);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PARISC_PLABEL21L:
Packit 6c4009
    case R_PARISC_PLABEL14R:
Packit 6c4009
      {
Packit 6c4009
	unsigned int insn = *(unsigned int *)reloc_addr;
Packit 6c4009
Packit 6c4009
	if (__builtin_expect (sym == NULL, 0))
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	value = (Elf32_Addr)((unsigned int)_dl_make_fptr (sym_map, sym, value) | 2);
Packit 6c4009
Packit 6c4009
	if (r_type == R_PARISC_PLABEL21L)
Packit 6c4009
	  {
Packit 6c4009
	    value >>= 11;
Packit 6c4009
	    insn = (insn &~ 0x1fffff) | reassemble_21 (value);
Packit 6c4009
	  }
Packit 6c4009
	else
Packit 6c4009
	  {
Packit 6c4009
	    value &= 0x7ff;
Packit 6c4009
	    insn = (insn &~ 0x3fff) | reassemble_14 (value);
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	*(unsigned int *)reloc_addr = insn;
Packit 6c4009
      }
Packit 6c4009
      return;
Packit 6c4009
Packit 6c4009
    case R_PARISC_IPLT:
Packit 6c4009
      if (__builtin_expect (sym_map != NULL, 1))
Packit 6c4009
	{
Packit 6c4009
	  elf_machine_fixup_plt (NULL, sym_map, NULL, NULL, reloc, reloc_addr,
Packit 6c4009
				 DL_FIXUP_MAKE_VALUE(sym_map, value));
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  /* If we get here, it's a (weak) undefined sym.  */
Packit 6c4009
	  elf_machine_fixup_plt (NULL, map, NULL, NULL, reloc, reloc_addr,
Packit 6c4009
				 DL_FIXUP_MAKE_VALUE(map, value));
Packit 6c4009
	}
Packit 6c4009
      return;
Packit 6c4009
Packit 6c4009
    case R_PARISC_COPY:
Packit 6c4009
      if (__builtin_expect (sym == NULL, 0))
Packit 6c4009
	/* This can happen in trace mode if an object could not be
Packit 6c4009
	   found.  */
Packit 6c4009
	break;
Packit 6c4009
      if (__builtin_expect (sym->st_size > refsym->st_size, 0)
Packit 6c4009
	  || (__builtin_expect (sym->st_size < refsym->st_size, 0)
Packit 6c4009
	      && __builtin_expect (GLRO(dl_verbose), 0)))
Packit 6c4009
	{
Packit 6c4009
	  const char *strtab;
Packit 6c4009
Packit 6c4009
	  strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
Packit 6c4009
	  _dl_error_printf ("%s: Symbol `%s' has different size in shared object, "
Packit 6c4009
			    "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
      return;
Packit 6c4009
Packit 6c4009
#if !defined RTLD_BOOTSTRAP
Packit 6c4009
    case R_PARISC_TLS_DTPMOD32:
Packit 6c4009
      value = sym_map->l_tls_modid;
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PARISC_TLS_DTPOFF32:
Packit 6c4009
      /* During relocation all TLS symbols are defined and used.
Packit 6c4009
	 Therefore the offset is already correct.  */
Packit 6c4009
      if (sym != NULL)
Packit 6c4009
	*reloc_addr = sym->st_value + reloc->r_addend;
Packit 6c4009
      return;
Packit 6c4009
Packit 6c4009
    case R_PARISC_TLS_TPREL32:
Packit 6c4009
      /* The offset is negative, forward from the thread pointer */
Packit 6c4009
      if (sym != NULL)
Packit 6c4009
	{
Packit 6c4009
	  CHECK_STATIC_TLS (map, sym_map);
Packit 6c4009
	  value = sym_map->l_tls_offset + sym->st_value + reloc->r_addend;
Packit 6c4009
	}
Packit 6c4009
      break;
Packit 6c4009
#endif	/* use TLS */
Packit 6c4009
Packit 6c4009
    case R_PARISC_NONE:	/* Alright, Wilbur. */
Packit 6c4009
      return;
Packit 6c4009
Packit 6c4009
    default:
Packit 6c4009
      _dl_reloc_bad_type (map, r_type, 0);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  *reloc_addr = value;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* hppa doesn't have an R_PARISC_RELATIVE reloc, but uses relocs with
Packit 6c4009
   ELF32_R_SYM (info) == 0 for a similar purpose.  */
Packit 6c4009
auto void __attribute__((always_inline))
Packit 6c4009
elf_machine_rela_relative (Elf32_Addr l_addr,
Packit 6c4009
			   const Elf32_Rela *reloc,
Packit 6c4009
			   void *const reloc_addr_arg)
Packit 6c4009
{
Packit 6c4009
  unsigned long const r_type = ELF32_R_TYPE (reloc->r_info);
Packit 6c4009
  Elf32_Addr *const reloc_addr = reloc_addr_arg;
Packit 6c4009
  static char msgbuf[] = { "Unknown" };
Packit 6c4009
  struct link_map map;
Packit 6c4009
  Elf32_Addr value;
Packit 6c4009
Packit 6c4009
  value = l_addr + reloc->r_addend;
Packit 6c4009
Packit 6c4009
  if (ELF32_R_SYM (reloc->r_info) != 0){
Packit 6c4009
    _dl_error_printf ("%s: In elf_machine_rela_relative "
Packit 6c4009
		      "ELF32_R_SYM (reloc->r_info) != 0. Aborting.",
Packit 6c4009
		      RTLD_PROGNAME);
Packit 6c4009
    ABORT_INSTRUCTION;  /* Crash. */
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
  switch (r_type)
Packit 6c4009
    {
Packit 6c4009
    case R_PARISC_DIR32:
Packit 6c4009
      /* .eh_frame can have unaligned relocs.  */
Packit 6c4009
      if ((unsigned long) reloc_addr_arg & 3)
Packit 6c4009
	{
Packit 6c4009
	  char *rel_addr = (char *) reloc_addr_arg;
Packit 6c4009
	  rel_addr[0] = value >> 24;
Packit 6c4009
	  rel_addr[1] = value >> 16;
Packit 6c4009
	  rel_addr[2] = value >> 8;
Packit 6c4009
	  rel_addr[3] = value;
Packit 6c4009
	  return;
Packit 6c4009
	}
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PARISC_PLABEL32:
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PARISC_IPLT: /* elf_machine_runtime_setup already set gp */
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case R_PARISC_NONE:
Packit 6c4009
      return;
Packit 6c4009
Packit 6c4009
    default: /* Bad reloc, map unknown (really it's the current map) */
Packit 6c4009
      map.l_name = msgbuf;
Packit 6c4009
      _dl_reloc_bad_type (&map, r_type, 0);
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  *reloc_addr = value;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
auto void __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
  /* We don't have anything to do here.  elf_machine_runtime_setup has
Packit 6c4009
     done all the relocs already.  */
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#endif /* RESOLVE_MAP */