(root)/
glibc-2.38/
sysdeps/
aarch64/
dl-machine.h
       1  /* Copyright (C) 1995-2023 Free Software Foundation, Inc.
       2  
       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 License as
       7     published by the Free Software Foundation; either version 2.1 of the
       8     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 "aarch64"
      23  
      24  #include <sysdep.h>
      25  #include <tls.h>
      26  #include <dl-tlsdesc.h>
      27  #include <dl-static-tls.h>
      28  #include <dl-irel.h>
      29  #include <dl-machine-rel.h>
      30  #include <cpu-features.c>
      31  
      32  /* Translate a processor specific dynamic tag to the index in l_info array.  */
      33  #define DT_AARCH64(x) (DT_AARCH64_##x - DT_LOPROC + DT_NUM)
      34  
      35  /* Return nonzero iff ELF header is compatible with the running host.  */
      36  static inline int __attribute__ ((unused))
      37  elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
      38  {
      39    return ehdr->e_machine == EM_AARCH64;
      40  }
      41  
      42  /* Return the run-time load address of the shared object.  */
      43  
      44  static inline ElfW(Addr) __attribute__ ((unused))
      45  elf_machine_load_address (void)
      46  {
      47    extern const ElfW(Ehdr) __ehdr_start attribute_hidden;
      48    return (ElfW(Addr)) &__ehdr_start;
      49  }
      50  
      51  /* Return the link-time address of _DYNAMIC.  */
      52  
      53  static inline ElfW(Addr) __attribute__ ((unused))
      54  elf_machine_dynamic (void)
      55  {
      56    extern ElfW(Dyn) _DYNAMIC[] attribute_hidden;
      57    return (ElfW(Addr)) _DYNAMIC - elf_machine_load_address ();
      58  }
      59  
      60  /* Set up the loaded object described by L so its unrelocated PLT
      61     entries will jump to the on-demand fixup code in dl-runtime.c.  */
      62  
      63  static inline int __attribute__ ((unused))
      64  elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
      65  			   int lazy, int profile)
      66  {
      67    if (l->l_info[DT_JMPREL] && lazy)
      68      {
      69        ElfW(Addr) *got;
      70        extern void _dl_runtime_resolve (ElfW(Word));
      71        extern void _dl_runtime_profile (ElfW(Word));
      72  
      73        got = (ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]);
      74        if (got[1])
      75  	{
      76  	  l->l_mach.plt = got[1] + l->l_addr;
      77  	}
      78        got[1] = (ElfW(Addr)) l;
      79  
      80        /* The got[2] entry contains the address of a function which gets
      81  	 called to get the address of a so far unresolved function and
      82  	 jump to it.  The profiling extension of the dynamic linker allows
      83  	 to intercept the calls to collect information.  In this case we
      84  	 don't store the address in the GOT so that all future calls also
      85  	 end in this function.  */
      86        if ( profile)
      87  	{
      88  	   got[2] = (ElfW(Addr)) &_dl_runtime_profile;
      89  
      90  	  if (GLRO(dl_profile) != NULL
      91  	      && _dl_name_match_p (GLRO(dl_profile), l))
      92  	    /* Say that we really want profiling and the timers are
      93  	       started.  */
      94  	    GL(dl_profile_map) = l;
      95  	}
      96        else
      97  	{
      98  	  /* This function will get called to fix up the GOT entry
      99  	     indicated by the offset on the stack, and then jump to
     100  	     the resolved address.  */
     101  	  got[2] = (ElfW(Addr)) &_dl_runtime_resolve;
     102  	}
     103      }
     104  
     105    return lazy;
     106  }
     107  
     108  /* In elf/rtld.c _dl_start should be global so dl-start.S can reference it.  */
     109  #define RTLD_START asm (".globl _dl_start");
     110  
     111  #define elf_machine_type_class(type)					\
     112    ((((type) == R_AARCH64_JUMP_SLOT ||					\
     113       (type) == R_AARCH64_TLS_DTPMOD ||					\
     114       (type) == R_AARCH64_TLS_DTPREL ||					\
     115       (type) == R_AARCH64_TLS_TPREL ||					\
     116       (type) == R_AARCH64_TLSDESC) * ELF_RTYPE_CLASS_PLT)		\
     117     | (((type) == R_AARCH64_COPY) * ELF_RTYPE_CLASS_COPY))
     118  
     119  #define ELF_MACHINE_JMP_SLOT	AARCH64_R(JUMP_SLOT)
     120  
     121  #define DL_PLATFORM_INIT dl_platform_init ()
     122  
     123  static inline void __attribute__ ((unused))
     124  dl_platform_init (void)
     125  {
     126    if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
     127      /* Avoid an empty string which would disturb us.  */
     128      GLRO(dl_platform) = NULL;
     129  
     130  #ifdef SHARED
     131    /* init_cpu_features has been called early from __libc_start_main in
     132       static executable.  */
     133    init_cpu_features (&GLRO(dl_aarch64_cpu_features));
     134  #endif
     135  }
     136  
     137  
     138  static inline ElfW(Addr)
     139  elf_machine_fixup_plt (struct link_map *map, lookup_t t,
     140  		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
     141  		       const ElfW(Rela) *reloc,
     142  		       ElfW(Addr) *reloc_addr,
     143  		       ElfW(Addr) value)
     144  {
     145    return *reloc_addr = value;
     146  }
     147  
     148  /* Return the final value of a plt relocation.  */
     149  static inline ElfW(Addr)
     150  elf_machine_plt_value (struct link_map *map,
     151  		       const ElfW(Rela) *reloc,
     152  		       ElfW(Addr) value)
     153  {
     154    return value;
     155  }
     156  
     157  #endif
     158  
     159  /* Names of the architecture-specific auditing callback functions.  */
     160  #define ARCH_LA_PLTENTER aarch64_gnu_pltenter
     161  #define ARCH_LA_PLTEXIT  aarch64_gnu_pltexit
     162  
     163  #ifdef RESOLVE_MAP
     164  
     165  static inline void
     166  __attribute__ ((always_inline))
     167  elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
     168  		  const ElfW(Rela) *reloc, const ElfW(Sym) *sym,
     169  		  const struct r_found_version *version,
     170  		  void *const reloc_addr_arg, int skip_ifunc)
     171  {
     172    ElfW(Addr) *const reloc_addr = reloc_addr_arg;
     173    const unsigned int r_type = ELFW (R_TYPE) (reloc->r_info);
     174  
     175    if (__builtin_expect (r_type == AARCH64_R(RELATIVE), 0))
     176        *reloc_addr = map->l_addr + reloc->r_addend;
     177    else if (__builtin_expect (r_type == R_AARCH64_NONE, 0))
     178        return;
     179    else
     180      {
     181  # ifndef RTLD_BOOTSTRAP
     182        const ElfW(Sym) *const refsym = sym;
     183  # endif
     184        struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version,
     185  					      r_type);
     186        ElfW(Addr) value = SYMBOL_ADDRESS (sym_map, sym, true);
     187  
     188        if (sym != NULL
     189  	  && __glibc_unlikely (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC)
     190  	  && __glibc_likely (sym->st_shndx != SHN_UNDEF)
     191  	  && __glibc_likely (!skip_ifunc))
     192  	value = elf_ifunc_invoke (value);
     193  
     194        switch (r_type)
     195  	{
     196  	case AARCH64_R(GLOB_DAT):
     197  	case AARCH64_R(JUMP_SLOT):
     198  	  *reloc_addr = value + reloc->r_addend;
     199  	  break;
     200  
     201  # ifndef RTLD_BOOTSTRAP
     202  	case AARCH64_R(ABS32):
     203  #  ifdef __LP64__
     204  	case AARCH64_R(ABS64):
     205  #  endif
     206  	  *reloc_addr = value + reloc->r_addend;
     207  	  break;
     208  	case AARCH64_R(COPY):
     209  	  if (sym == NULL)
     210  	      break;
     211  
     212  	  if (sym->st_size > refsym->st_size
     213  	      || (GLRO(dl_verbose) && sym->st_size < refsym->st_size))
     214  	    {
     215  	      const char *strtab;
     216  
     217  	      strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
     218  	      _dl_error_printf ("\
     219  %s: Symbol `%s' has different size in shared object, consider re-linking\n",
     220  				RTLD_PROGNAME, strtab + refsym->st_name);
     221  	    }
     222  	  memcpy (reloc_addr_arg, (void *) value,
     223  		  sym->st_size < refsym->st_size
     224  		  ? sym->st_size : refsym->st_size);
     225  	  break;
     226  
     227  	case AARCH64_R(TLSDESC):
     228  	  {
     229  	    struct tlsdesc volatile *td =
     230  	      (struct tlsdesc volatile *)reloc_addr;
     231  	    if (! sym)
     232  	      {
     233  		td->arg = (void*)reloc->r_addend;
     234  		td->entry = _dl_tlsdesc_undefweak;
     235  	      }
     236  	    else
     237  	      {
     238  # ifndef SHARED
     239  		CHECK_STATIC_TLS (map, sym_map);
     240  # else
     241  		if (!TRY_STATIC_TLS (map, sym_map))
     242  		  {
     243  		    td->arg = _dl_make_tlsdesc_dynamic
     244  		      (sym_map, sym->st_value + reloc->r_addend);
     245  		    td->entry = _dl_tlsdesc_dynamic;
     246  		  }
     247  		else
     248  # endif
     249  		  {
     250  		    td->arg = (void*)(sym->st_value + sym_map->l_tls_offset
     251  				      + reloc->r_addend);
     252  		    td->entry = _dl_tlsdesc_return;
     253  		  }
     254  	      }
     255  	    break;
     256  	  }
     257  
     258  	case AARCH64_R(TLS_DTPMOD):
     259  	  if (sym_map != NULL)
     260  	    {
     261  	      *reloc_addr = sym_map->l_tls_modid;
     262  	    }
     263  	  break;
     264  
     265  	case AARCH64_R(TLS_DTPREL):
     266  	  if (sym)
     267  	    *reloc_addr = sym->st_value + reloc->r_addend;
     268  	  break;
     269  
     270  	case AARCH64_R(TLS_TPREL):
     271  	  if (sym)
     272  	    {
     273  	      CHECK_STATIC_TLS (map, sym_map);
     274  	      *reloc_addr =
     275  		sym->st_value + reloc->r_addend + sym_map->l_tls_offset;
     276  	    }
     277  	  break;
     278  
     279  	case AARCH64_R(IRELATIVE):
     280  	  value = map->l_addr + reloc->r_addend;
     281  	  if (__glibc_likely (!skip_ifunc))
     282  	    value = elf_ifunc_invoke (value);
     283  	  *reloc_addr = value;
     284  	  break;
     285  # endif /* !RTLD_BOOTSTRAP */
     286  
     287  	default:
     288  	  _dl_reloc_bad_type (map, r_type, 0);
     289  	  break;
     290  	}
     291      }
     292  }
     293  
     294  static inline void
     295  __attribute__ ((always_inline))
     296  elf_machine_rela_relative (ElfW(Addr) l_addr,
     297  			   const ElfW(Rela) *reloc,
     298  			   void *const reloc_addr_arg)
     299  {
     300    ElfW(Addr) *const reloc_addr = reloc_addr_arg;
     301    *reloc_addr = l_addr + reloc->r_addend;
     302  }
     303  
     304  static inline void
     305  __attribute__ ((always_inline))
     306  elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
     307  		      ElfW(Addr) l_addr,
     308  		      const ElfW(Rela) *reloc,
     309  		      int skip_ifunc)
     310  {
     311    ElfW(Addr) *const reloc_addr = (void *) (l_addr + reloc->r_offset);
     312    const unsigned int r_type = ELFW (R_TYPE) (reloc->r_info);
     313    /* Check for unexpected PLT reloc type.  */
     314    if (__builtin_expect (r_type == AARCH64_R(JUMP_SLOT), 1))
     315      {
     316        if (__glibc_unlikely (map->l_info[DT_AARCH64 (VARIANT_PCS)] != NULL))
     317  	{
     318  	  /* Check the symbol table for variant PCS symbols.  */
     319  	  const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info);
     320  	  const ElfW (Sym) *symtab =
     321  	    (const void *)D_PTR (map, l_info[DT_SYMTAB]);
     322  	  const ElfW (Sym) *sym = &symtab[symndx];
     323  	  if (__glibc_unlikely (sym->st_other & STO_AARCH64_VARIANT_PCS))
     324  	    {
     325  	      /* Avoid lazy resolution of variant PCS symbols.  */
     326  	      const struct r_found_version *version = NULL;
     327  	      if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
     328  		{
     329  		  const ElfW (Half) *vernum =
     330  		    (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
     331  		  version = &map->l_versions[vernum[symndx] & 0x7fff];
     332  		}
     333  	      elf_machine_rela (map, scope, reloc, sym, version, reloc_addr,
     334  				skip_ifunc);
     335  	      return;
     336  	    }
     337  	}
     338  
     339        if (map->l_mach.plt == 0)
     340  	*reloc_addr += l_addr;
     341        else
     342  	*reloc_addr = map->l_mach.plt;
     343      }
     344    else if (__builtin_expect (r_type == AARCH64_R(TLSDESC), 1))
     345      {
     346        const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info);
     347        const ElfW (Sym) *symtab = (const void *)D_PTR (map, l_info[DT_SYMTAB]);
     348        const ElfW (Sym) *sym = &symtab[symndx];
     349        const struct r_found_version *version = NULL;
     350  
     351        if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
     352  	{
     353  	  const ElfW (Half) *vernum =
     354  	    (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
     355  	  version = &map->l_versions[vernum[symndx] & 0x7fff];
     356  	}
     357  
     358        /* Always initialize TLS descriptors completely, because lazy
     359  	 initialization requires synchronization at every TLS access.  */
     360        elf_machine_rela (map, scope, reloc, sym, version, reloc_addr,
     361  			skip_ifunc);
     362      }
     363    else if (__glibc_unlikely (r_type == AARCH64_R(IRELATIVE)))
     364      {
     365        ElfW(Addr) value = map->l_addr + reloc->r_addend;
     366        if (__glibc_likely (!skip_ifunc))
     367  	value = elf_ifunc_invoke (value);
     368        *reloc_addr = value;
     369      }
     370    else
     371      _dl_reloc_bad_type (map, r_type, 1);
     372  }
     373  
     374  #endif