(root)/
glibc-2.38/
sysdeps/
sh/
dl-machine.h
       1  /* Machine-dependent ELF dynamic relocation inline functions.  SH version.
       2     Copyright (C) 1999-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
      21  
      22  #define ELF_MACHINE_NAME "SH"
      23  
      24  #include <sys/param.h>
      25  #include <sysdep.h>
      26  #include <assert.h>
      27  #include <dl-static-tls.h>
      28  #include <dl-machine-rel.h>
      29  
      30  /* Return nonzero iff ELF header is compatible with the running host.  */
      31  static inline int __attribute__ ((unused))
      32  elf_machine_matches_host (const Elf32_Ehdr *ehdr)
      33  {
      34    return ehdr->e_machine == EM_SH;
      35  }
      36  
      37  
      38  /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
      39     first element of the GOT.  This must be inlined in a function which
      40     uses global data.  */
      41  static inline Elf32_Addr __attribute__ ((unused))
      42  elf_machine_dynamic (void)
      43  {
      44    register Elf32_Addr *got;
      45    asm ("mov r12,%0" :"=r" (got));
      46    return *got;
      47  }
      48  
      49  
      50  /* Return the run-time load address of the shared object.  */
      51  static inline Elf32_Addr __attribute__ ((unused))
      52  elf_machine_load_address (void)
      53  {
      54    Elf32_Addr addr;
      55    asm ("mov.l 1f,r0\n\
      56  	mov.l 3f,r2\n\
      57  	add r12,r2\n\
      58  	mov.l @(r0,r12),r0\n\
      59  	bra 2f\n\
      60  	 sub r0,r2\n\
      61  	.align 2\n\
      62  	1: .long _dl_start@GOT\n\
      63  	3: .long _dl_start@GOTOFF\n\
      64  	2: mov r2,%0"
      65         : "=r" (addr) : : "r0", "r1", "r2");
      66    return addr;
      67  }
      68  
      69  
      70  /* Set up the loaded object described by L so its unrelocated PLT
      71     entries will jump to the on-demand fixup code in dl-runtime.c.  */
      72  
      73  static inline int __attribute__ ((unused, always_inline))
      74  elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
      75  			   int lazy, int profile)
      76  {
      77    Elf32_Addr *got;
      78    extern void _dl_runtime_resolve (Elf32_Word);
      79    extern void _dl_runtime_profile (Elf32_Word);
      80  
      81    if (l->l_info[DT_JMPREL] && lazy)
      82      {
      83        /* The GOT entries for functions in the PLT have not yet been filled
      84  	 in.  Their initial contents will arrange when called to load an
      85  	 offset into the .rela.plt section and _GLOBAL_OFFSET_TABLE_[1],
      86  	 and then jump to _GLOBAL_OFFSET_TABLE[2].  */
      87        got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
      88        /* If a library is prelinked but we have to relocate anyway,
      89  	 we have to be able to undo the prelinking of .got.plt.
      90  	 The prelinker saved us here address of .plt + 36.  */
      91        if (got[1])
      92  	{
      93  	  l->l_mach.plt = got[1] + l->l_addr;
      94  	  l->l_mach.gotplt = (Elf32_Addr) &got[3];
      95  	}
      96        got[1] = (Elf32_Addr) l;	/* Identify this shared object.	 */
      97  
      98        /* The got[2] entry contains the address of a function which gets
      99  	 called to get the address of a so far unresolved function and
     100  	 jump to it.  The profiling extension of the dynamic linker allows
     101  	 to intercept the calls to collect information.	 In this case we
     102  	 don't store the address in the GOT so that all future calls also
     103  	 end in this function.	*/
     104        if (profile)
     105  	{
     106  	  got[2] = (Elf32_Addr) &_dl_runtime_profile;
     107  	  /* Say that we really want profiling and the timers are started.  */
     108  	  if (GLRO(dl_profile) != NULL
     109  	      && _dl_name_match_p (GLRO(dl_profile), l))
     110  	    GL(dl_profile_map) = l;
     111  	}
     112        else
     113  	/* This function will get called to fix up the GOT entry indicated by
     114  	   the offset on the stack, and then jump to the resolved address.  */
     115  	got[2] = (Elf32_Addr) &_dl_runtime_resolve;
     116      }
     117    return lazy;
     118  }
     119  
     120  #define ELF_MACHINE_RUNTIME_FIXUP_ARGS int plt_type
     121  #define ELF_MACHINE_RUNTIME_FIXUP_PARAMS plt_type
     122  
     123  /* Mask identifying addresses reserved for the user program,
     124     where the dynamic linker should not map anything.  */
     125  #define ELF_MACHINE_USER_ADDRESS_MASK	0x80000000UL
     126  
     127  /* Initial entry point code for the dynamic linker.
     128     The C function `_dl_start' is the real entry point;
     129     its return value is the user program's entry point.	*/
     130  
     131  #define RTLD_START asm ("\
     132  .text\n\
     133  .globl _start\n\
     134  .globl _dl_start_user\n\
     135  _start:\n\
     136  	mov r15,r4\n\
     137  	mov.l .L_dl_start,r1\n\
     138  	mova .L_dl_start,r0\n\
     139  	add r1,r0\n\
     140  	jsr @r0\n\
     141  	 nop\n\
     142  _dl_start_user:\n\
     143  	! Save the user entry point address in r8.\n\
     144  	mov r0,r8\n\
     145  	! Point r12 at the GOT.\n\
     146  	mov.l 1f,r12\n\
     147  	mova 1f,r0\n\
     148  	bra 2f\n\
     149  	 add r0,r12\n\
     150  	.align 2\n\
     151  1:	.long _GLOBAL_OFFSET_TABLE_\n\
     152  2:	! Get the original argument count.\n\
     153  	mov.l @r15,r5\n\
     154  	! Compute argv address and envp.\n\
     155  	mov r15,r6\n\
     156  	add #4,r6\n\
     157  	mov r5,r7\n\
     158  	shll2 r7\n\
     159  	add r15,r7\n\
     160  	add #8,r7\n\
     161  	mov.l .L_dl_loaded,r0\n\
     162  	mov.l @(r0,r12),r0\n\
     163  	mov.l @r0,r4\n\
     164  	! Call _dl_init.\n\
     165  	mov.l .L_dl_init,r1\n\
     166  	mova .L_dl_init,r0\n\
     167  	add r1,r0\n\
     168  	jsr @r0\n\
     169  	 nop\n\
     170  1:	! Pass our finalizer function to the user in r4, as per ELF ABI.\n\
     171  	mov.l .L_dl_fini,r0\n\
     172  	mov.l @(r0,r12),r4\n\
     173  	! Jump to the user's entry point.\n\
     174  	jmp @r8\n\
     175  	 nop\n\
     176  	.align 2\n\
     177  .L_dl_start:\n\
     178  	.long _dl_start@PLT\n\
     179  .L_dl_init:\n\
     180  	.long _dl_init@PLT\n\
     181  .L_dl_loaded:\n\
     182  	.long _rtld_local@GOT\n\
     183  .L_dl_fini:\n\
     184  	.long _dl_fini@GOT\n\
     185  	.type __fpscr_values,@object\n\
     186  	.global __fpscr_values\n\
     187  __fpscr_values:\n\
     188  	.long   0\n\
     189  	.long   0x80000\n\
     190  	.weak __fpscr_values\n\
     191  .previous\n\
     192  ");
     193  
     194  /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
     195     TLS variable, so undefined references should not be allowed to
     196     define the value.
     197     ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve to one
     198     of the main executable's symbols, as for a COPY reloc.  */
     199  #define elf_machine_type_class(type) \
     200    ((((type) == R_SH_JMP_SLOT || (type) == R_SH_TLS_DTPMOD32		      \
     201       || (type) == R_SH_TLS_DTPOFF32 || (type) == R_SH_TLS_TPOFF32)	      \
     202      * ELF_RTYPE_CLASS_PLT)						      \
     203     | (((type) == R_SH_COPY) * ELF_RTYPE_CLASS_COPY))
     204  
     205  /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
     206  #define ELF_MACHINE_JMP_SLOT	R_SH_JMP_SLOT
     207  
     208  /* We define an initialization functions.  This is called very early in
     209     _dl_sysdep_start.  */
     210  #define DL_PLATFORM_INIT dl_platform_init ()
     211  
     212  static inline void __attribute__ ((unused))
     213  dl_platform_init (void)
     214  {
     215    if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
     216      /* Avoid an empty string which would disturb us.  */
     217      GLRO(dl_platform) = NULL;
     218  }
     219  
     220  static inline Elf32_Addr
     221  elf_machine_fixup_plt (struct link_map *map, lookup_t t,
     222  		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
     223  		       const Elf32_Rela *reloc,
     224  		       Elf32_Addr *reloc_addr, Elf32_Addr value)
     225  {
     226    return *reloc_addr = value;
     227  }
     228  
     229  /* Return the final value of a plt relocation.	*/
     230  static inline Elf32_Addr
     231  elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
     232  		       Elf32_Addr value)
     233  {
     234    return value + reloc->r_addend;
     235  }
     236  
     237  #define ARCH_LA_PLTENTER sh_gnu_pltenter
     238  #define ARCH_LA_PLTEXIT sh_gnu_pltexit
     239  
     240  #endif /* !dl_machine_h */
     241  
     242  #ifdef RESOLVE_MAP
     243  
     244  /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
     245     MAP is the object containing the reloc.  */
     246  
     247  static inline void
     248  __attribute ((always_inline))
     249  elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
     250  		  const Elf32_Rela *reloc, const Elf32_Sym *sym,
     251  		  const struct r_found_version *version,
     252  		  void *const reloc_addr_arg, int skip_ifunc)
     253  {
     254    Elf32_Addr *const reloc_addr = reloc_addr_arg;
     255    const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
     256    Elf32_Addr value;
     257  
     258  #define COPY_UNALIGNED_WORD(swp, twp, align) \
     259    { \
     260      void *__s = (swp), *__t = (twp); \
     261      unsigned char *__s1 = __s, *__t1 = __t; \
     262      unsigned short *__s2 = __s, *__t2 = __t; \
     263      unsigned long *__s4 = __s, *__t4 = __t; \
     264      switch ((align)) \
     265      { \
     266      case 0: \
     267        *__t4 = *__s4; \
     268        break; \
     269      case 2: \
     270        *__t2++ = *__s2++; \
     271        *__t2 = *__s2; \
     272        break; \
     273      default: \
     274        *__t1++ = *__s1++; \
     275        *__t1++ = *__s1++; \
     276        *__t1++ = *__s1++; \
     277        *__t1 = *__s1; \
     278        break; \
     279      } \
     280    }
     281  
     282    if (__glibc_unlikely (r_type == R_SH_RELATIVE))
     283      {
     284  #ifndef RTLD_BOOTSTRAP
     285        if (map != &GL(dl_rtld_map)) /* Already done in rtld itself.	 */
     286  #endif
     287  	{
     288  	  if (reloc->r_addend)
     289  	    value = map->l_addr + reloc->r_addend;
     290  	  else
     291  	    {
     292  	      COPY_UNALIGNED_WORD (reloc_addr_arg, &value,
     293  				   (int) reloc_addr_arg & 3);
     294  	      value += map->l_addr;
     295  	    }
     296  	  COPY_UNALIGNED_WORD (&value, reloc_addr_arg,
     297  			       (int) reloc_addr_arg & 3);
     298  	}
     299      }
     300  #ifndef RTLD_BOOTSTRAP
     301    else if (__glibc_unlikely (r_type == R_SH_NONE))
     302      return;
     303  #endif
     304    else
     305      {
     306        const Elf32_Sym *const refsym = sym;
     307        struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version,
     308  					      r_type);
     309  
     310        value = SYMBOL_ADDRESS (sym_map, sym, true);
     311        value += reloc->r_addend;
     312  
     313        switch (r_type)
     314  	{
     315  	case R_SH_COPY:
     316  	  if (sym == NULL)
     317  	    /* This can happen in trace mode if an object could not be
     318  	       found.  */
     319  	    break;
     320  	  if (sym->st_size > refsym->st_size
     321  	      || (sym->st_size < refsym->st_size && GLRO(dl_verbose)))
     322  	    {
     323  	      const char *strtab;
     324  
     325  	      strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
     326  	      _dl_error_printf ("\
     327  %s: Symbol `%s' has different size in shared object, consider re-linking\n",
     328  				RTLD_PROGNAME, strtab + refsym->st_name);
     329  	    }
     330  	  memcpy (reloc_addr_arg, (void *) value,
     331  		  MIN (sym->st_size, refsym->st_size));
     332  	  break;
     333  	case R_SH_GLOB_DAT:
     334  	case R_SH_JMP_SLOT:
     335  	  /* These addresses are always aligned.  */
     336  	  *reloc_addr = value;
     337  	  break;
     338  	  /* XXX Remove TLS relocations which are not needed.  */
     339  	case R_SH_TLS_DTPMOD32:
     340  #ifdef RTLD_BOOTSTRAP
     341  	  /* During startup the dynamic linker is always the module
     342  	     with index 1.
     343  	     XXX If this relocation is necessary move before RESOLVE
     344  	     call.  */
     345  	  *reloc_addr = 1;
     346  #else
     347  	  /* Get the information from the link map returned by the
     348  	     resolv function.  */
     349  	  if (sym_map != NULL)
     350  	    *reloc_addr = sym_map->l_tls_modid;
     351  #endif
     352  	  break;
     353  	case R_SH_TLS_DTPOFF32:
     354  #ifndef RTLD_BOOTSTRAP
     355  	  /* During relocation all TLS symbols are defined and used.
     356  	     Therefore the offset is already correct.  */
     357  	  if (sym != NULL)
     358  	    *reloc_addr = sym->st_value;
     359  #endif
     360  	  break;
     361  	case R_SH_TLS_TPOFF32:
     362  	  /* The offset is positive, afterward from the thread pointer.  */
     363  #ifdef RTLD_BOOTSTRAP
     364  	  *reloc_addr = map->l_tls_offset + sym->st_value + reloc->r_addend;
     365  #else
     366  	  /* We know the offset of object the symbol is contained in.
     367  	     It is a positive value which will be added to the thread
     368  	     pointer.  To get the variable position in the TLS block
     369  	     we add the offset from that of the TLS block.  */
     370  	  if (sym != NULL)
     371  	    {
     372  	      CHECK_STATIC_TLS (map, sym_map);
     373  	      *reloc_addr = sym_map->l_tls_offset + sym->st_value
     374  			    + reloc->r_addend;
     375  	    }
     376  #endif
     377  	  break;
     378  	case R_SH_DIR32:
     379  	  {
     380  #if !defined RTLD_BOOTSTRAP
     381  	   /* This is defined in rtld.c, but nowhere in the static
     382  	      libc.a; make the reference weak so static programs can
     383  	      still link.  This declaration cannot be done when
     384  	      compiling rtld.c (i.e. #ifdef RTLD_BOOTSTRAP) because
     385  	      rtld.c contains the common defn for _dl_rtld_map, which
     386  	      is incompatible with a weak decl in the same file.  */
     387  # ifndef SHARED
     388  	    weak_extern (_dl_rtld_map);
     389  # endif
     390  	    if (map == &GL(dl_rtld_map))
     391  	      /* Undo the relocation done here during bootstrapping.
     392  		 Now we will relocate it anew, possibly using a
     393  		 binding found in the user program or a loaded library
     394  		 rather than the dynamic linker's built-in definitions
     395  		 used while loading those libraries.  */
     396  	      value -= SYMBOL_ADDRESS (map, refsym, true) + reloc->r_addend;
     397  #endif
     398  	    COPY_UNALIGNED_WORD (&value, reloc_addr_arg,
     399  				 (int) reloc_addr_arg & 3);
     400  	    break;
     401  	  }
     402  	case R_SH_REL32:
     403  	  value = (value - (Elf32_Addr) reloc_addr);
     404  	  COPY_UNALIGNED_WORD (&value, reloc_addr_arg,
     405  			       (int) reloc_addr_arg & 3);
     406  	  break;
     407  	default:
     408  	  _dl_reloc_bad_type (map, r_type, 0);
     409  	  break;
     410  	}
     411      }
     412  }
     413  
     414  static inline void
     415  __attribute__ ((always_inline))
     416  elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
     417  			   void *const reloc_addr_arg)
     418  {
     419    Elf32_Addr value;
     420  
     421    if (reloc->r_addend)
     422      value = l_addr + reloc->r_addend;
     423    else
     424      {
     425        COPY_UNALIGNED_WORD (reloc_addr_arg, &value, (int) reloc_addr_arg & 3);
     426        value += l_addr;
     427      }
     428    COPY_UNALIGNED_WORD (&value, reloc_addr_arg, (int) reloc_addr_arg & 3);
     429  
     430  #undef COPY_UNALIGNED_WORD
     431  }
     432  
     433  static inline void
     434  __attribute__ ((always_inline))
     435  elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
     436  		      Elf32_Addr l_addr, const Elf32_Rela *reloc,
     437  		      int skip_ifunc)
     438  {
     439    Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
     440    /* Check for unexpected PLT reloc type.  */
     441    if (ELF32_R_TYPE (reloc->r_info) == R_SH_JMP_SLOT)
     442      {
     443        if (__builtin_expect (map->l_mach.plt, 0) == 0)
     444  	*reloc_addr += l_addr;
     445        else
     446  	*reloc_addr =
     447  	  map->l_mach.plt
     448  	  + (((Elf32_Addr) reloc_addr) - map->l_mach.gotplt) * 7;
     449      }
     450    else
     451      _dl_reloc_bad_type (map, ELF32_R_TYPE (reloc->r_info), 1);
     452  }
     453  
     454  #endif /* RESOLVE_MAP */