1  /* Machine-dependent ELF dynamic relocation inline functions.  PA-RISC version.
       2     Copyright (C) 1995-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library.  If not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #ifndef dl_machine_h
      20  #define dl_machine_h 1
      21  
      22  #define ELF_MACHINE_NAME "hppa"
      23  
      24  #include <sys/param.h>
      25  #include <assert.h>
      26  #include <string.h>
      27  #include <link.h>
      28  #include <errno.h>
      29  #include <dl-fptr.h>
      30  #include <abort-instr.h>
      31  #include <tls.h>
      32  #include <dl-static-tls.h>
      33  #include <dl-machine-rel.h>
      34  
      35  /* These two definitions must match the definition of the stub in
      36     bfd/elf32-hppa.c (see plt_stub[]).
      37  
      38     a. Define the size of the *entire* stub we place at the end of the PLT
      39     table (right up against the GOT).
      40  
      41     b. Define the number of bytes back from the GOT to the entry point of
      42     the PLT stub. You see the PLT stub must be entered in the middle
      43     so it can depwi to find it's own address (long jump stub)
      44  
      45     c. Define the size of a single PLT entry so we can jump over the
      46     last entry to get the stub address */
      47  
      48  #define SIZEOF_PLT_STUB (7*4)
      49  #define GOT_FROM_PLT_STUB (4*4)
      50  #define PLT_ENTRY_SIZE (2*4)
      51  
      52  /* The gp slot in the function descriptor contains the relocation offset
      53     before resolution.  To distinguish between a resolved gp value and an
      54     unresolved relocation offset we set an unused bit in the relocation
      55     offset.  This would allow us to do a synchronzied two word update
      56     using this bit (interlocked update), but instead of waiting for the
      57     update we simply recompute the gp value given that we know the ip.  */
      58  #define PA_GP_RELOC 1
      59  
      60  /* Initialize the function descriptor table before relocations */
      61  static inline void
      62  __hppa_init_bootstrap_fdesc_table (struct link_map *map)
      63  {
      64    ElfW(Addr) *boot_table;
      65  
      66    /* Careful: this will be called before got has been relocated... */
      67    ELF_MACHINE_LOAD_ADDRESS(boot_table,_dl_boot_fptr_table);
      68  
      69    map->l_mach.fptr_table_len = ELF_MACHINE_BOOT_FPTR_TABLE_LEN;
      70    map->l_mach.fptr_table = boot_table;
      71  }
      72  
      73  #define ELF_MACHINE_BEFORE_RTLD_RELOC(map, dynamic_info)	\
      74  	__hppa_init_bootstrap_fdesc_table (map);		\
      75  	_dl_fptr_init();
      76  
      77  /* Return nonzero iff ELF header is compatible with the running host.  */
      78  static inline int
      79  elf_machine_matches_host (const Elf32_Ehdr *ehdr)
      80  {
      81    return ehdr->e_machine == EM_PARISC;
      82  }
      83  
      84  /* Return the link-time address of _DYNAMIC.  */
      85  static inline Elf32_Addr
      86  elf_machine_dynamic (void) __attribute__ ((const));
      87  
      88  static inline Elf32_Addr
      89  elf_machine_dynamic (void)
      90  {
      91    Elf32_Addr dynamic;
      92  
      93    asm ("bl	1f,%0\n"
      94  "	addil	L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 1),%0\n"
      95  "1:	ldw	R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 5)(%%r1),%0\n"
      96         : "=r" (dynamic) : : "r1");
      97  
      98    return dynamic;
      99  }
     100  
     101  /* Return the run-time load address of the shared object.  */
     102  static inline Elf32_Addr
     103  elf_machine_load_address (void) __attribute__ ((const));
     104  
     105  static inline Elf32_Addr
     106  elf_machine_load_address (void)
     107  {
     108    Elf32_Addr dynamic;
     109  
     110    asm (
     111  "	bl	1f,%0\n"
     112  "	addil	L'_DYNAMIC - ($PIC_pcrel$0 - 1),%0\n"
     113  "1:	ldo	R'_DYNAMIC - ($PIC_pcrel$0 - 5)(%%r1),%0\n"
     114     : "=r" (dynamic) : : "r1");
     115  
     116    return dynamic - elf_machine_dynamic ();
     117  }
     118  
     119  /* Fixup a PLT entry to bounce directly to the function at VALUE. */
     120  static inline struct fdesc __attribute__ ((always_inline))
     121  elf_machine_fixup_plt (struct link_map *map, lookup_t t,
     122  		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
     123  		       const Elf32_Rela *reloc,
     124  		       Elf32_Addr *reloc_addr, struct fdesc value)
     125  {
     126    volatile Elf32_Addr *rfdesc = reloc_addr;
     127    /* map is the link_map for the caller, t is the link_map for the object
     128       being called */
     129  
     130    /* We would like the function descriptor to be double word aligned.  This
     131       helps performance (ip and gp then reside on the same cache line) and
     132       we can update the pair atomically with a single store.  The linker
     133       now ensures this alignment but we still have to handle old code.  */
     134    if ((unsigned int)reloc_addr & 7)
     135      {
     136        /* Need to ensure that the gp is visible before the code
     137           entry point is updated */
     138        rfdesc[1] = value.gp;
     139        atomic_full_barrier();
     140        rfdesc[0] = value.ip;
     141      }
     142    else
     143      {
     144        /* Update pair atomically with floating point store.  */
     145        union { ElfW(Word) v[2]; double d; } u;
     146  
     147        u.v[0] = value.ip;
     148        u.v[1] = value.gp;
     149        *(volatile double *)rfdesc = u.d;
     150      }
     151    return value;
     152  }
     153  
     154  /* Return the final value of a plt relocation.  */
     155  static inline struct fdesc
     156  elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
     157  		       struct fdesc value)
     158  {
     159    /* We are rela only, return a function descriptor as a plt entry. */
     160    return (struct fdesc) { value.ip + reloc->r_addend, value.gp };
     161  }
     162  
     163  /* Set up the loaded object described by L so its unrelocated PLT
     164     entries will jump to the on-demand fixup code in dl-runtime.c.  */
     165  
     166  static inline int
     167  elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
     168  			   int lazy, int profile)
     169  {
     170    Elf32_Addr *got = NULL;
     171    Elf32_Addr l_addr, iplt, jmprel, end_jmprel, r_type, r_sym;
     172    const Elf32_Rela *reloc;
     173    struct fdesc *fptr;
     174    static union {
     175      unsigned char c[8];
     176      Elf32_Addr i[2];
     177    } sig = {{0x00,0xc0,0xff,0xee, 0xde,0xad,0xbe,0xef}};
     178  
     179    /* Initialize dp register for main executable.  */
     180    if (l->l_main_map)
     181      {
     182        register Elf32_Addr dp asm ("%r27");
     183  
     184        dp = D_PTR (l, l_info[DT_PLTGOT]);
     185        asm volatile ("" : : "r" (dp));
     186      }
     187  
     188    /* If we don't have a PLT we can just skip all this... */
     189    if (__builtin_expect (l->l_info[DT_JMPREL] == NULL,0))
     190      return lazy;
     191  
     192    /* All paths use these values */
     193    l_addr = l->l_addr;
     194    jmprel = D_PTR(l, l_info[DT_JMPREL]);
     195    end_jmprel = jmprel + l->l_info[DT_PLTRELSZ]->d_un.d_val;
     196  
     197    extern void _dl_runtime_resolve (void);
     198    extern void _dl_runtime_profile (void);
     199  
     200    /* Linking lazily */
     201    if (lazy)
     202      {
     203        /* FIXME: Search for the got, but backwards through the relocs, technically we should
     204  	 find it on the first try. However, assuming the relocs got out of order the
     205  	 routine is made a bit more robust by searching them all in case of failure. */
     206        for (iplt = (end_jmprel - sizeof (Elf32_Rela)); iplt >= jmprel; iplt -= sizeof (Elf32_Rela))
     207  	{
     208  
     209  	  reloc = (const Elf32_Rela *) iplt;
     210  	  r_type = ELF32_R_TYPE (reloc->r_info);
     211  	  r_sym = ELF32_R_SYM (reloc->r_info);
     212  
     213  	  got = (Elf32_Addr *) (reloc->r_offset + l_addr + PLT_ENTRY_SIZE + SIZEOF_PLT_STUB);
     214  
     215  	  /* If we aren't an IPLT, and we aren't NONE then it's a bad reloc */
     216  	  if (__builtin_expect (r_type != R_PARISC_IPLT, 0))
     217  	    {
     218  	      if (__builtin_expect (r_type != R_PARISC_NONE, 0))
     219  		_dl_reloc_bad_type (l, r_type, 1);
     220  	      continue;
     221  	    }
     222  
     223  	  /* Check for the plt_stub that binutils placed here for us
     224  	     to use with _dl_runtime_resolve  */
     225  	  if (got[-2] != sig.i[0] || got[-1] != sig.i[1])
     226  	    {
     227  	      got = NULL; /* Not the stub... keep looking */
     228  	    }
     229  	  else
     230  	    {
     231  	      /* Found the GOT! */
     232  	      register Elf32_Addr ltp __asm__ ("%r19");
     233  
     234  	      /* Identify this shared object. Second entry in the got. */
     235  	      got[1] = (Elf32_Addr) l;
     236  
     237  	      /* This function will be called to perform the relocation. */
     238  	      if (__builtin_expect (!profile, 1))
     239  		{
     240  		  /* If a static application called us, then _dl_runtime_resolve is not
     241  		     a function descriptor, but the *real* address of the function... */
     242  		  if((unsigned long) &_dl_runtime_resolve & 3)
     243  		    {
     244  		      got[-2] = (Elf32_Addr) ((struct fdesc *)
     245  				  ((unsigned long) &_dl_runtime_resolve & ~3))->ip;
     246  		    }
     247  		  else
     248  		    {
     249  		      /* Static executable! */
     250  		      got[-2] = (Elf32_Addr) &_dl_runtime_resolve;
     251  		    }
     252  		}
     253  	      else
     254  		{
     255  		  if (GLRO(dl_profile) != NULL
     256  		      && _dl_name_match_p (GLRO(dl_profile), l))
     257  		    {
     258  		      /* This is the object we are looking for.  Say that
     259  			 we really want profiling and the timers are
     260  			 started.  */
     261  		      GL(dl_profile_map) = l;
     262  		    }
     263  
     264  		  if((unsigned long) &_dl_runtime_profile & 3)
     265  		    {
     266  		      got[-2] = (Elf32_Addr) ((struct fdesc *)
     267  				  ((unsigned long) &_dl_runtime_profile & ~3))->ip;
     268  		    }
     269  		  else
     270  		    {
     271  		      /* Static executable */
     272  		      got[-2] = (Elf32_Addr) &_dl_runtime_profile;
     273  		    }
     274  		}
     275  	      /* Plunk in the gp of this function descriptor so we
     276  		 can make the call to _dl_runtime_xxxxxx */
     277  	      got[-1] = ltp;
     278  	      break;
     279  	      /* Done looking for the GOT, and stub is setup */
     280  	    } /* else we found the GOT */
     281  	} /* for, walk the relocs backwards */
     282  
     283        if(!got)
     284  	return 0; /* No lazy linking for you! */
     285  
     286        /* Process all the relocs, now that we know the GOT... */
     287        for (iplt = jmprel; iplt < end_jmprel; iplt += sizeof (Elf32_Rela))
     288  	{
     289  	  reloc = (const Elf32_Rela *) iplt;
     290  	  r_type = ELF32_R_TYPE (reloc->r_info);
     291  	  r_sym = ELF32_R_SYM (reloc->r_info);
     292  
     293  	  if (__builtin_expect (r_type == R_PARISC_IPLT, 1))
     294  	    {
     295  	      fptr = (struct fdesc *) (reloc->r_offset + l_addr);
     296  	      if (r_sym != 0)
     297  		{
     298  		  /* Relocate the pointer to the stub.  */
     299  		  fptr->ip = (Elf32_Addr) got - GOT_FROM_PLT_STUB;
     300  
     301  		  /* Instead of the LTP value, we put the reloc offset
     302  		     here.  The trampoline code will load the proper
     303  		     LTP and pass the reloc offset to the fixup
     304  		     function.  */
     305  		  fptr->gp = (iplt - jmprel) | PA_GP_RELOC;
     306  		} /* r_sym != 0 */
     307  	      else
     308  		{
     309  		  /* Relocate this *ABS* entry.  */
     310  		  fptr->ip = reloc->r_addend + l_addr;
     311  		  fptr->gp = D_PTR (l, l_info[DT_PLTGOT]);
     312  		}
     313  	    } /* r_type == R_PARISC_IPLT */
     314  	} /* for all the relocations */
     315      } /* if lazy */
     316    else
     317      {
     318        for (iplt = jmprel; iplt < end_jmprel; iplt += sizeof (Elf32_Rela))
     319  	{
     320  	  reloc = (const Elf32_Rela *) iplt;
     321  	  r_type = ELF32_R_TYPE (reloc->r_info);
     322  	  r_sym = ELF32_R_SYM (reloc->r_info);
     323  
     324  	  if (__builtin_expect ((r_type == R_PARISC_IPLT) && (r_sym == 0), 1))
     325  	    {
     326  	      fptr = (struct fdesc *) (reloc->r_offset + l_addr);
     327  	      /* Relocate this *ABS* entry, set only the gp, the rest is set later
     328  		 when elf_machine_rela_relative is called (WITHOUT the linkmap)  */
     329  	      fptr->gp = D_PTR (l, l_info[DT_PLTGOT]);
     330  	    } /* r_type == R_PARISC_IPLT */
     331  	} /* for all the relocations */
     332      }
     333    return lazy;
     334  }
     335  
     336  
     337  /* Names of the architecture-specific auditing callback functions.  */
     338  #define ARCH_LA_PLTENTER hppa_gnu_pltenter
     339  #define ARCH_LA_PLTEXIT hppa_gnu_pltexit
     340  
     341  /* Adjust DL_STACK_END to get value we want in __libc_stack_end.  */
     342  #define DL_STACK_END(cookie) \
     343    ((void *) (((long) (cookie)) + 0x160))
     344  
     345  /* Initial entry point code for the dynamic linker.
     346     The C function `_dl_start' is the real entry point;
     347     its return value is the user program's entry point.  */
     348  
     349  #define RTLD_START \
     350  /* Set up dp for any non-PIC lib constructors that may be called.  */	\
     351  static struct link_map * __attribute__((used))				\
     352  set_dp (struct link_map *map)						\
     353  {									\
     354    register Elf32_Addr dp asm ("%r27");					\
     355    dp = D_PTR (map, l_info[DT_PLTGOT]);					\
     356    asm volatile ("" : : "r" (dp));					\
     357    return map;								\
     358  }									\
     359  									\
     360  asm (									\
     361  "	.text\n"							\
     362  "	.globl _start\n"						\
     363  "	.type _start,@function\n"					\
     364  "_start:\n"								\
     365  	/* The kernel does not give us an initial stack frame. */	\
     366  "	ldo	64(%sp),%sp\n"						\
     367  									\
     368  	/* We need the LTP, and we need it now.				\
     369  	   $PIC_pcrel$0 points 8 bytes past the current instruction,	\
     370  	   just like a branch reloc.  This sequence gets us the		\
     371  	   runtime address of _DYNAMIC. */				\
     372  "	bl	0f,%r19\n"						\
     373  "	addil	L'_DYNAMIC - ($PIC_pcrel$0 - 1),%r19\n"			\
     374  "0:	ldo	R'_DYNAMIC - ($PIC_pcrel$0 - 5)(%r1),%r26\n"		\
     375  									\
     376  	/* The link time address is stored in the first entry of the	\
     377  	   GOT.  */							\
     378  "	addil	L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 9),%r19\n"	\
     379  "	ldw	R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 13)(%r1),%r20\n" \
     380  									\
     381  "	sub	%r26,%r20,%r20\n"	/* Calculate load offset */	\
     382  									\
     383  	/* Rummage through the dynamic entries, looking for		\
     384  	   DT_PLTGOT.  */						\
     385  "	ldw,ma	8(%r26),%r19\n"						\
     386  "1:	cmpib,=,n 3,%r19,2f\n"	/* tag == DT_PLTGOT? */			\
     387  "	cmpib,<>,n 0,%r19,1b\n"						\
     388  "	ldw,ma	8(%r26),%r19\n"						\
     389  									\
     390  	/* Uh oh!  We didn't find one.  Abort. */			\
     391  "	iitlbp	%r0,(%sr0,%r0)\n"					\
     392  									\
     393  "2:	ldw	-4(%r26),%r19\n"	/* Found it, load value. */	\
     394  "	add	%r19,%r20,%r19\n"	/* And add the load offset. */	\
     395  									\
     396  	/* Our initial stack layout is rather different from everyone	\
     397  	   else's due to the unique PA-RISC ABI.  As far as I know it	\
     398  	   looks like this:						\
     399  									\
     400  	   -----------------------------------  (this frame created above) \
     401  	   |         32 bytes of magic       |				\
     402  	   |---------------------------------|				\
     403  	   | 32 bytes argument/sp save area  |				\
     404  	   |---------------------------------|  ((current->mm->env_end)	\
     405  	   |         N bytes of slack        |	 + 63 & ~63)		\
     406  	   |---------------------------------|				\
     407  	   |      envvar and arg strings     |				\
     408  	   |---------------------------------|				\
     409  	   |	    ELF auxiliary info	     |				\
     410  	   |         (up to 28 words)        |				\
     411  	   |---------------------------------|				\
     412  	   |  Environment variable pointers  |				\
     413  	   |         upwards to NULL	     |				\
     414  	   |---------------------------------|				\
     415  	   |        Argument pointers        |				\
     416  	   |         upwards to NULL	     |				\
     417  	   |---------------------------------|				\
     418  	   |          argc (1 word)          |				\
     419  	   -----------------------------------				\
     420  									\
     421  	  So, obviously, we can't just pass %sp to _dl_start.  That's	\
     422  	  okay, argv-4 will do just fine.				\
     423  									\
     424  	  This is always within range so we'll be okay. */		\
     425  "	bl	_dl_start,%rp\n"					\
     426  "	ldo	-4(%r24),%r26\n"					\
     427  									\
     428  "	.globl _dl_start_user\n"					\
     429  "	.type _dl_start_user,@function\n"				\
     430  "_dl_start_user:\n"							\
     431  	/* Save the entry point in %r3. */				\
     432  "	copy	%ret0,%r3\n"						\
     433  									\
     434  	/* The loader adjusts argc, argv, env, and the aux vectors	\
     435  	   directly on the stack to remove any arguments used for	\
     436  	   direct loader invocation.  Thus, argc and argv must be	\
     437  	   reloaded from from _dl_argc and _dl_argv.  */		\
     438  									\
     439  	/* Load main_map from _rtld_local and setup dp. */		\
     440  "	addil	LT'_rtld_local,%r19\n"					\
     441  "	ldw	RT'_rtld_local(%r1),%r26\n"				\
     442  "	bl	set_dp, %r2\n"						\
     443  "	ldw	0(%r26),%r26\n"						\
     444  "	copy	%ret0,%r26\n"						\
     445  									\
     446  	/* Load argc from _dl_argc.  */					\
     447  "	addil	LT'_dl_argc,%r19\n"					\
     448  "	ldw	RT'_dl_argc(%r1),%r20\n"				\
     449  "	ldw	0(%r20),%r25\n"						\
     450  "	stw	%r25,-40(%sp)\n"					\
     451  									\
     452  	/* Same for argv with _dl_argv.  */				\
     453  "	addil	LT'_dl_argv,%r19\n"					\
     454  "	ldw	RT'_dl_argv(%r1),%r20\n"				\
     455  "	ldw	0(%r20),%r24\n"						\
     456  "	stw	%r24,-44(%sp)\n"					\
     457  									\
     458  	/* envp = argv + argc + 1 */					\
     459  "	sh2add	%r25,%r24,%r23\n"					\
     460  									\
     461  	/* Call _dl_init(main_map, argc, argv, envp). */		\
     462  "	bl	_dl_init,%r2\n"						\
     463  "	ldo	4(%r23),%r23\n"	/* delay slot */			\
     464  									\
     465  	/* Reload argc, argv to the registers start.S expects.  */	\
     466  "	ldw	-40(%sp),%r25\n"					\
     467  "	ldw	-44(%sp),%r24\n"					\
     468  									\
     469  	/* _dl_fini is a local function in the loader, so we construct	\
     470  	   a false OPD here and pass this to the application.  */	\
     471  	/* FIXME: Should be able to use P%, and LR RR to have the	\
     472  	   the linker construct a proper OPD.  */			\
     473  "	.section .data\n"						\
     474  "__dl_fini_plabel:\n"							\
     475  "	.word	_dl_fini\n"						\
     476  "	.word	0xdeadbeef\n"						\
     477  "	.previous\n"							\
     478  									\
     479  	/* %r3 contains a function pointer, we need to mask out the	\
     480  	   lower bits and load the gp and jump address. */		\
     481  "	depi	0,31,2,%r3\n"						\
     482  "	ldw	0(%r3),%r2\n"						\
     483  "	addil	LT'__dl_fini_plabel,%r19\n"				\
     484  "	ldw	RT'__dl_fini_plabel(%r1),%r23\n"			\
     485  "	stw	%r19,4(%r23)\n"						\
     486  "	ldw	4(%r3),%r19\n"	/* load the object's gp */		\
     487  "	bv	%r0(%r2)\n"						\
     488  "	depi	2,31,2,%r23\n"	/* delay slot */			\
     489  );
     490  
     491  /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
     492     a TLS variable, so references should not be allowed to define the value.
     493     ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve to one
     494     of the main executable's symbols, as for a COPY reloc.  */
     495  #if !defined RTLD_BOOTSTRAP
     496  # define elf_machine_type_class(type)				\
     497    ((((type) == R_PARISC_IPLT					\
     498    || (type) == R_PARISC_EPLT					\
     499    || (type) == R_PARISC_TLS_DTPMOD32				\
     500    || (type) == R_PARISC_TLS_DTPOFF32				\
     501    || (type) == R_PARISC_TLS_TPREL32)				\
     502    * ELF_RTYPE_CLASS_PLT)					\
     503    | (((type) == R_PARISC_COPY) * ELF_RTYPE_CLASS_COPY))
     504  #else
     505  #define elf_machine_type_class(type)				\
     506   ((((type) == R_PARISC_IPLT					\
     507     || (type) == R_PARISC_EPLT)					\
     508     * ELF_RTYPE_CLASS_PLT)					\
     509     | (((type) == R_PARISC_COPY) * ELF_RTYPE_CLASS_COPY))
     510  #endif
     511  
     512  /* Used by the runtime in fixup to figure out if reloc is *really* PLT */
     513  #define ELF_MACHINE_JMP_SLOT R_PARISC_IPLT
     514  #define ELF_MACHINE_SIZEOF_JMP_SLOT PLT_ENTRY_SIZE
     515  
     516  /* Return the address of the entry point. */
     517  #define ELF_MACHINE_START_ADDRESS(map, start)			\
     518  ({								\
     519  	ElfW(Addr) addr;					\
     520  	DL_DT_FUNCTION_ADDRESS(map, start, static, addr)	\
     521  	addr;							\
     522  })
     523  
     524  /* We define an initialization functions.  This is called very early in
     525   *    _dl_sysdep_start.  */
     526  #define DL_PLATFORM_INIT dl_platform_init ()
     527  
     528  static inline void __attribute__ ((unused))
     529  dl_platform_init (void)
     530  {
     531  	if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
     532  	/* Avoid an empty string which would disturb us.  */
     533  		GLRO(dl_platform) = NULL;
     534  }
     535  
     536  #endif /* !dl_machine_h */
     537  
     538  /* These are only actually used where RESOLVE_MAP is defined, anyway. */
     539  #ifdef RESOLVE_MAP
     540  
     541  #define reassemble_21(as21) \
     542    (  (((as21) & 0x100000) >> 20) \
     543     | (((as21) & 0x0ffe00) >> 8) \
     544     | (((as21) & 0x000180) << 7) \
     545     | (((as21) & 0x00007c) << 14) \
     546     | (((as21) & 0x000003) << 12))
     547  
     548  #define reassemble_14(as14) \
     549    (  (((as14) & 0x1fff) << 1) \
     550     | (((as14) & 0x2000) >> 13))
     551  
     552  static void __attribute__((always_inline))
     553  elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
     554  		  const Elf32_Rela *reloc,
     555  		  const Elf32_Sym *sym,
     556  		  const struct r_found_version *version,
     557  		  void *const reloc_addr_arg,
     558  		  int skip_ifunc)
     559  {
     560    Elf32_Addr *const reloc_addr = reloc_addr_arg;
     561    const Elf32_Sym *const refsym = sym;
     562    unsigned long const r_type = ELF32_R_TYPE (reloc->r_info);
     563    struct link_map *sym_map;
     564    Elf32_Addr value;
     565  
     566    /* RESOLVE_MAP will return a null value for undefined syms, and
     567       non-null for all other syms.  In particular, relocs with no
     568       symbol (symbol index of zero), also called *ABS* relocs, will be
     569       resolved to MAP.  (The first entry in a symbol table is all
     570       zeros, and an all zero Elf32_Sym has a binding of STB_LOCAL.)
     571       See RESOLVE_MAP definition in elf/dl-reloc.c  */
     572  # ifdef RTLD_BOOTSTRAP
     573    sym_map = map;
     574  # else
     575    sym_map = RESOLVE_MAP (map, scope, &sym, version, r_type);
     576  # endif
     577  
     578    if (sym_map)
     579      {
     580        value = SYMBOL_ADDRESS (sym_map, sym, true);
     581        value += reloc->r_addend;
     582      }
     583    else
     584      value = 0;
     585  
     586    switch (r_type)
     587      {
     588      case R_PARISC_DIR32:
     589        /* .eh_frame can have unaligned relocs.  */
     590        if ((unsigned long) reloc_addr_arg & 3)
     591  	{
     592  	  char *rel_addr = (char *) reloc_addr_arg;
     593  	  rel_addr[0] = value >> 24;
     594  	  rel_addr[1] = value >> 16;
     595  	  rel_addr[2] = value >> 8;
     596  	  rel_addr[3] = value;
     597  	  return;
     598  	}
     599        break;
     600  
     601      case R_PARISC_DIR21L:
     602        {
     603  	unsigned int insn = *(unsigned int *)reloc_addr;
     604  	value = (SYMBOL_ADDRESS (sym_map, sym, true)
     605  		 + ((reloc->r_addend + 0x1000) & -0x2000));
     606  	value = value >> 11;
     607  	insn = (insn &~ 0x1fffff) | reassemble_21 (value);
     608  	*(unsigned int *)reloc_addr = insn;
     609        }
     610        return;
     611  
     612      case R_PARISC_DIR14R:
     613        {
     614  	unsigned int insn = *(unsigned int *)reloc_addr;
     615  	value = ((SYMBOL_ADDRESS (sym_map, sym, true) & 0x7ff)
     616  		 + (((reloc->r_addend & 0x1fff) ^ 0x1000) - 0x1000));
     617  	insn = (insn &~ 0x3fff) | reassemble_14 (value);
     618  	*(unsigned int *)reloc_addr = insn;
     619        }
     620        return;
     621  
     622      case R_PARISC_PLABEL32:
     623        /* Easy rule: If there is a symbol and it is global, then we
     624  	 need to make a dynamic function descriptor.  Otherwise we
     625  	 have the address of a PLT slot for a local symbol which we
     626  	 know to be unique. */
     627        if (sym == NULL
     628  	  || sym_map == NULL
     629  	  || ELF32_ST_BIND (sym->st_info) == STB_LOCAL)
     630  	{
     631  	  break;
     632  	}
     633        /* Set bit 30 to indicate to $$dyncall that this is a PLABEL.
     634  	 We have to do this outside of the generic function descriptor
     635  	 code, since it doesn't know about our requirement for setting
     636  	 protection bits */
     637        value = (Elf32_Addr)((unsigned int)_dl_make_fptr (sym_map, sym, value) | 2);
     638        break;
     639  
     640      case R_PARISC_PLABEL21L:
     641      case R_PARISC_PLABEL14R:
     642        {
     643  	unsigned int insn = *(unsigned int *)reloc_addr;
     644  
     645  	if (__builtin_expect (sym == NULL, 0))
     646  	  break;
     647  
     648  	value = (Elf32_Addr)((unsigned int)_dl_make_fptr (sym_map, sym, value) | 2);
     649  
     650  	if (r_type == R_PARISC_PLABEL21L)
     651  	  {
     652  	    value >>= 11;
     653  	    insn = (insn &~ 0x1fffff) | reassemble_21 (value);
     654  	  }
     655  	else
     656  	  {
     657  	    value &= 0x7ff;
     658  	    insn = (insn &~ 0x3fff) | reassemble_14 (value);
     659  	  }
     660  
     661  	*(unsigned int *)reloc_addr = insn;
     662        }
     663        return;
     664  
     665      case R_PARISC_IPLT:
     666        if (__builtin_expect (sym_map != NULL, 1))
     667  	{
     668  	  elf_machine_fixup_plt (NULL, sym_map, NULL, NULL, reloc, reloc_addr,
     669  				 DL_FIXUP_MAKE_VALUE(sym_map, value));
     670  	}
     671        else
     672  	{
     673  	  /* If we get here, it's a (weak) undefined sym.  */
     674  	  elf_machine_fixup_plt (NULL, map, NULL, NULL, reloc, reloc_addr,
     675  				 DL_FIXUP_MAKE_VALUE(map, value));
     676  	}
     677        return;
     678  
     679      case R_PARISC_COPY:
     680        if (__builtin_expect (sym == NULL, 0))
     681  	/* This can happen in trace mode if an object could not be
     682  	   found.  */
     683  	break;
     684        if (__builtin_expect (sym->st_size > refsym->st_size, 0)
     685  	  || (__builtin_expect (sym->st_size < refsym->st_size, 0)
     686  	      && __builtin_expect (GLRO(dl_verbose), 0)))
     687  	{
     688  	  const char *strtab;
     689  
     690  	  strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
     691  	  _dl_error_printf ("%s: Symbol `%s' has different size in shared object, "
     692  			    "consider re-linking\n",
     693  			    RTLD_PROGNAME, strtab + refsym->st_name);
     694  	}
     695        memcpy (reloc_addr_arg, (void *) value,
     696  	      MIN (sym->st_size, refsym->st_size));
     697        return;
     698  
     699  #if !defined RTLD_BOOTSTRAP
     700      case R_PARISC_TLS_DTPMOD32:
     701        value = sym_map->l_tls_modid;
     702        break;
     703  
     704      case R_PARISC_TLS_DTPOFF32:
     705        /* During relocation all TLS symbols are defined and used.
     706  	 Therefore the offset is already correct.  */
     707        if (sym != NULL)
     708  	*reloc_addr = sym->st_value + reloc->r_addend;
     709        return;
     710  
     711      case R_PARISC_TLS_TPREL32:
     712        /* The offset is negative, forward from the thread pointer */
     713        if (sym != NULL)
     714  	{
     715  	  CHECK_STATIC_TLS (map, sym_map);
     716  	  value = sym_map->l_tls_offset + sym->st_value + reloc->r_addend;
     717  	}
     718        break;
     719  #endif	/* use TLS */
     720  
     721      case R_PARISC_NONE:	/* Alright, Wilbur. */
     722        return;
     723  
     724      default:
     725        _dl_reloc_bad_type (map, r_type, 0);
     726      }
     727  
     728    *reloc_addr = value;
     729  }
     730  
     731  /* hppa doesn't have an R_PARISC_RELATIVE reloc, but uses relocs with
     732     ELF32_R_SYM (info) == 0 for a similar purpose.  */
     733  static void __attribute__((always_inline))
     734  elf_machine_rela_relative (Elf32_Addr l_addr,
     735  			   const Elf32_Rela *reloc,
     736  			   void *const reloc_addr_arg)
     737  {
     738    unsigned long const r_type = ELF32_R_TYPE (reloc->r_info);
     739    Elf32_Addr *const reloc_addr = reloc_addr_arg;
     740    static char msgbuf[] = { "Unknown" };
     741    struct link_map map;
     742    Elf32_Addr value;
     743  
     744    value = l_addr + reloc->r_addend;
     745  
     746    if (ELF32_R_SYM (reloc->r_info) != 0){
     747      _dl_error_printf ("%s: In elf_machine_rela_relative "
     748  		      "ELF32_R_SYM (reloc->r_info) != 0. Aborting.",
     749  		      RTLD_PROGNAME);
     750      ABORT_INSTRUCTION;  /* Crash. */
     751    }
     752  
     753    switch (r_type)
     754      {
     755      case R_PARISC_DIR32:
     756        /* .eh_frame can have unaligned relocs.  */
     757        if ((unsigned long) reloc_addr_arg & 3)
     758  	{
     759  	  char *rel_addr = (char *) reloc_addr_arg;
     760  	  rel_addr[0] = value >> 24;
     761  	  rel_addr[1] = value >> 16;
     762  	  rel_addr[2] = value >> 8;
     763  	  rel_addr[3] = value;
     764  	  return;
     765  	}
     766        break;
     767  
     768      case R_PARISC_PLABEL32:
     769        break;
     770  
     771      case R_PARISC_IPLT: /* elf_machine_runtime_setup already set gp */
     772        break;
     773  
     774      case R_PARISC_NONE:
     775        return;
     776  
     777      default: /* Bad reloc, map unknown (really it's the current map) */
     778        map.l_name = msgbuf;
     779        _dl_reloc_bad_type (&map, r_type, 0);
     780        return;
     781      }
     782  
     783    *reloc_addr = value;
     784  }
     785  
     786  static void __attribute__((always_inline))
     787  elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
     788  		      Elf32_Addr l_addr, const Elf32_Rela *reloc,
     789  		      int skip_ifunc)
     790  {
     791    /* We don't have anything to do here.  elf_machine_runtime_setup has
     792       done all the relocs already.  */
     793  }
     794  
     795  #endif /* RESOLVE_MAP */