(root)/
glibc-2.38/
sysdeps/
ia64/
dl-machine.h
       1  /* Machine-dependent ELF dynamic relocation inline functions.  IA-64 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 "ia64"
      23  
      24  #include <assert.h>
      25  #include <string.h>
      26  #include <link.h>
      27  #include <errno.h>
      28  #include <dl-fptr.h>
      29  #include <tls.h>
      30  #include <dl-static-tls.h>
      31  #include <dl-machine-rel.h>
      32  
      33  /* Translate a processor specific dynamic tag to the index
      34     in l_info array.  */
      35  #define DT_IA_64(x) (DT_IA_64_##x - DT_LOPROC + DT_NUM)
      36  
      37  static inline void __attribute__ ((always_inline))
      38  __ia64_init_bootstrap_fdesc_table (struct link_map *map)
      39  {
      40    Elf64_Addr *boot_table;
      41  
      42    /* careful: this will be called before got has been relocated... */
      43    asm (";; addl %0 = @gprel (_dl_boot_fptr_table), gp" : "=r"(boot_table));
      44  
      45    map->l_mach.fptr_table_len = ELF_MACHINE_BOOT_FPTR_TABLE_LEN;
      46    map->l_mach.fptr_table = boot_table;
      47  }
      48  
      49  #define ELF_MACHINE_BEFORE_RTLD_RELOC(map, dynamic_info)		\
      50  	__ia64_init_bootstrap_fdesc_table (map);
      51  
      52  /* Return nonzero iff ELF header is compatible with the running host.  */
      53  static inline int __attribute__ ((unused))
      54  elf_machine_matches_host (const Elf64_Ehdr *ehdr)
      55  {
      56    return ehdr->e_machine == EM_IA_64;
      57  }
      58  
      59  
      60  /* Return the link-time address of _DYNAMIC.  */
      61  static inline Elf64_Addr __attribute__ ((unused, const))
      62  elf_machine_dynamic (void)
      63  {
      64    Elf64_Addr *p;
      65  
      66    __asm__ (
      67  	".section .sdata\n"
      68  	"	.type __dynamic_ltv#, @object\n"
      69  	"	.size __dynamic_ltv#, 8\n"
      70  	"__dynamic_ltv:\n"
      71  	"	data8	@ltv(_DYNAMIC#)\n"
      72  	".previous\n"
      73  	"	addl	%0 = @gprel(__dynamic_ltv#), gp ;;"
      74  	: "=r" (p));
      75  
      76    return *p;
      77  }
      78  
      79  
      80  /* Return the run-time load address of the shared object.  */
      81  static inline Elf64_Addr __attribute__ ((unused))
      82  elf_machine_load_address (void)
      83  {
      84    Elf64_Addr ip;
      85    int *p;
      86  
      87    __asm__ (
      88  	"1:	mov %0 = ip\n"
      89  	".section .sdata\n"
      90  	"2:	data4	@ltv(1b)\n"
      91  	"       .align 8\n"
      92  	".previous\n"
      93  	"	addl	%1 = @gprel(2b), gp ;;"
      94  	: "=r" (ip), "=r" (p));
      95  
      96    return ip - (Elf64_Addr) *p;
      97  }
      98  
      99  /* Set up the loaded object described by L so its unrelocated PLT
     100     entries will jump to the on-demand fixup code in dl-runtime.c.  */
     101  
     102  static inline int __attribute__ ((unused, always_inline))
     103  elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
     104  			   int lazy, int profile)
     105  {
     106    extern void _dl_runtime_resolve (void);
     107    extern void _dl_runtime_profile (void);
     108  
     109    if (lazy)
     110      {
     111        register Elf64_Addr gp __asm__ ("gp");
     112        Elf64_Addr *reserve, doit;
     113  
     114        /*
     115         * Careful with the typecast here or it will try to add l-l_addr
     116         * pointer elements
     117         */
     118        reserve = ((Elf64_Addr *)
     119  		 (l->l_info[DT_IA_64 (PLT_RESERVE)]->d_un.d_ptr + l->l_addr));
     120        /* Identify this shared object.  */
     121        reserve[0] = (Elf64_Addr) l;
     122  
     123        /* This function will be called to perform the relocation.  */
     124        if (!profile)
     125  	doit = (Elf64_Addr) ELF_PTR_TO_FDESC (&_dl_runtime_resolve)->ip;
     126        else
     127  	{
     128  	  if (GLRO(dl_profile) != NULL
     129  	      && _dl_name_match_p (GLRO(dl_profile), l))
     130  	    {
     131  	      /* This is the object we are looking for.  Say that we really
     132  		 want profiling and the timers are started.  */
     133  	      GL(dl_profile_map) = l;
     134  	    }
     135  	  doit = (Elf64_Addr) ELF_PTR_TO_FDESC (&_dl_runtime_profile)->ip;
     136  	}
     137  
     138        reserve[1] = doit;
     139        reserve[2] = gp;
     140      }
     141  
     142    return lazy;
     143  }
     144  
     145  /* Names of the architecture-specific auditing callback functions.  */
     146  #define ARCH_LA_PLTENTER ia64_gnu_pltenter
     147  #define ARCH_LA_PLTEXIT ia64_gnu_pltexit
     148  
     149  /* Undo the adds out0 = 16, sp below to get at the value we want in
     150     __libc_stack_end.  */
     151  #define DL_STACK_END(cookie) \
     152    ((void *) (((long) (cookie)) - 16))
     153  
     154  /* Initial entry point code for the dynamic linker.
     155     The C function `_dl_start' is the real entry point;
     156     its return value is the user program's entry point.  */
     157  
     158  #define RTLD_START asm (						      \
     159  ".text\n"								      \
     160  "	.global _start#\n"						      \
     161  "	.proc _start#\n"						      \
     162  "_start:\n"								      \
     163  "0:	{ .mii\n"							      \
     164  "	  .prologue\n"							      \
     165  "	  .save rp, r0\n"						      \
     166  "	  .body\n"							      \
     167  "	  .prologue\n"							      \
     168  "	  .save ar.pfs, r32\n"						      \
     169  "	  alloc loc0 = ar.pfs, 0, 3, 4, 0\n"				      \
     170  "	  .body\n"							      \
     171  "	  mov r2 = ip\n"						      \
     172  "	  addl r3 = @gprel(0b), r0\n"					      \
     173  "	  ;;\n"								      \
     174  "	}\n"								      \
     175  "	{ .mlx\n"							      \
     176  "	  /* Calculate the GP, and save a copy in loc1.  */\n"		      \
     177  "	  sub gp = r2, r3\n"						      \
     178  "	  movl r8 = 0x9804c0270033f\n"					      \
     179  "	  ;;\n"								      \
     180  "	}\n"								      \
     181  "	{ .mii\n"							      \
     182  "	  mov ar.fpsr = r8\n"						      \
     183  "	  sub loc1 = r2, r3\n"						      \
     184  "	  /* _dl_start wants a pointer to the pointer to the arg block and\n" \
     185  "	     the arg block starts with an integer, thus the magic 16. */\n"   \
     186  "	  adds out0 = 16, sp\n"						      \
     187  "	}\n"								      \
     188  "	{ .bbb\n"							      \
     189  "	  br.call.sptk.many b0 = _dl_start#\n"				      \
     190  "	  ;;\n"								      \
     191  "	}\n"								      \
     192  "	.endp _start#\n"						      \
     193  "	/* FALLTHRU */\n"						      \
     194  "	.global _dl_start_user#\n"					      \
     195  "	.proc _dl_start_user#\n"					      \
     196  "_dl_start_user:\n"							      \
     197  "	 .prologue\n"							      \
     198  "	 .save rp, r0\n"						      \
     199  "	  .body\n"							      \
     200  "	 .prologue\n"							      \
     201  "	 .save ar.pfs, r32\n"						      \
     202  "	 .body\n"							      \
     203  "	{ .mii\n"							      \
     204  "	  /* Save the pointer to the user entry point fptr in loc2.  */\n"    \
     205  "	  mov loc2 = ret0\n"						      \
     206  "	  addl r2 = @ltoff(_dl_argc), gp\n"				      \
     207  "	  ;;\n"								      \
     208  "	}\n"								      \
     209  "	{ .mii\n"							      \
     210  "	  ld8 out1 = [r2]	/* Get the _dl_argc address.  */\n"	      \
     211  "	  addl r3 = @ltoff(_dl_argv), gp\n"				      \
     212  "	  ;;\n"								      \
     213  "	}\n"								      \
     214  "	{ .mmi\n"							      \
     215  "	  ld8 out2 = [r3]	/* Get the _dl_argv address.  */\n"	      \
     216  "	  ld8 out1 = [out1]	/* Get the adjusted _dl_argc.  */\n"	      \
     217  "	  addl r2 = @gprel(_rtld_local), gp\n"				      \
     218  "	  ;;\n"								      \
     219  "	}\n"								      \
     220  "	{ .mmi\n"							      \
     221  "	  sxt4 out3 = out1	/* envp = argv + argc + 1  */\n" 	      \
     222  "	  ;;\n"								      \
     223  "	}\n"								      \
     224  "	{ .mmi\n"							      \
     225  "	  adds out3 = 1, out3\n"					      \
     226  "	  ;;\n"								      \
     227  "	}\n"								      \
     228  "	{ .mmi\n"							      \
     229  "	  ld8 out2 = [out2]	/* Get the adjusted _dl_argv.  */\n"	      \
     230  "	  shladd out3 = out3, 3, r0\n"					      \
     231  "	  ;;\n"								      \
     232  "	}\n"								      \
     233  "	{ .mmb\n"							      \
     234  "	  add out3 = out3, out2\n"					      \
     235  "	  ld8 out0 = [r2]	/* Get the linkmap. */\n"		      \
     236  "	  br.call.sptk.many b0 = _dl_init#\n"				      \
     237  "	}\n"								      \
     238  "	/* Pass our finalizer function to the user,\n"			      \
     239  "	   and jump to the user's entry point.  */\n"			      \
     240  "	{ .mmi\n"							      \
     241  "	  ld8 r3 = [loc2], 8\n"						      \
     242  "	  mov b0 = r0\n"						      \
     243  "	}\n"								      \
     244  "	{ .mmi\n"							      \
     245  "	  addl ret0 = @ltoff(@fptr(_dl_fini#)), gp\n"			      \
     246  "	  ;;\n"								      \
     247  "	  mov b6 = r3\n"						      \
     248  "	}\n"								      \
     249  "	{ .mmi\n"							      \
     250  "	  ld8 ret0 = [ret0]\n"						      \
     251  "	  ld8 gp = [loc2]\n"						      \
     252  "	  mov ar.pfs = loc0\n"						      \
     253  "	  ;;\n"								      \
     254  "	}\n"								      \
     255  "	{ .mfb\n"							      \
     256  "	  br.sptk.many b6\n"						      \
     257  "	  ;;\n"								      \
     258  "	}\n"								      \
     259  "	.endp _dl_start_user#\n"					      \
     260  ".previous\n");
     261  
     262  
     263  #ifndef RTLD_START_SPECIAL_INIT
     264  #define RTLD_START_SPECIAL_INIT /* nothing */
     265  #endif
     266  
     267  /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or TLS
     268     variable, so undefined references should not be allowed to define the
     269     value.
     270     ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve to one
     271     of the main executable's symbols, as for a COPY reloc, which we don't
     272     use.  */
     273  /* ??? Ignore *MSB for now.  */
     274  #define elf_machine_type_class(type) \
     275    (((type) == R_IA64_IPLTLSB || (type) == R_IA64_DTPMOD64LSB		      \
     276      || (type) == R_IA64_DTPREL64LSB || (type) == R_IA64_TPREL64LSB)	      \
     277     * ELF_RTYPE_CLASS_PLT)
     278  
     279  /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
     280  #define ELF_MACHINE_JMP_SLOT	 R_IA64_IPLTLSB
     281  
     282  /* Return the address of the entry point. */
     283  #define ELF_MACHINE_START_ADDRESS(map, start)			\
     284  ({								\
     285  	ElfW(Addr) addr;					\
     286  	DL_DT_FUNCTION_ADDRESS(map, start, static, addr)	\
     287  	addr;							\
     288  })
     289  
     290  /* Fixup a PLT entry to bounce directly to the function at VALUE.  */
     291  static inline struct fdesc __attribute__ ((always_inline))
     292  elf_machine_fixup_plt (struct link_map *l, lookup_t t,
     293  		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
     294  		       const Elf64_Rela *reloc,
     295  		       Elf64_Addr *reloc_addr, struct fdesc value)
     296  {
     297    /* l is the link_map for the caller, t is the link_map for the object
     298     * being called */
     299    /* got has already been relocated in elf_get_dynamic_info() */
     300    reloc_addr[1] = value.gp;
     301    /* we need a "release" here to ensure that the gp is visible before
     302       the code entry point is updated: */
     303    ((volatile Elf64_Addr *) reloc_addr)[0] = value.ip;
     304    return value;
     305  }
     306  
     307  /* Return the final value of a plt relocation.  */
     308  static inline struct fdesc
     309  elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
     310  		       struct fdesc value)
     311  {
     312    /* No need to handle rel vs rela since IA64 is rela only */
     313    return (struct fdesc) { value.ip + reloc->r_addend, value.gp };
     314  }
     315  
     316  #endif /* !dl_machine_h */
     317  
     318  #ifdef RESOLVE_MAP
     319  
     320  #define R_IA64_TYPE(R)	 ((R) & -8)
     321  #define R_IA64_FORMAT(R) ((R) & 7)
     322  
     323  #define R_IA64_FORMAT_32MSB	4
     324  #define R_IA64_FORMAT_32LSB	5
     325  #define R_IA64_FORMAT_64MSB	6
     326  #define R_IA64_FORMAT_64LSB	7
     327  
     328  
     329  /* Perform the relocation specified by RELOC and SYM (which is fully
     330     resolved).  MAP is the object containing the reloc.  */
     331  static inline void
     332  __attribute ((always_inline))
     333  elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
     334  		  const Elf64_Rela *reloc,
     335  		  const Elf64_Sym *sym,
     336  		  const struct r_found_version *version,
     337  		  void *const reloc_addr_arg,
     338  		  int skip_ifunc)
     339  {
     340    Elf64_Addr *const reloc_addr = reloc_addr_arg;
     341    const unsigned long int r_type = ELF64_R_TYPE (reloc->r_info);
     342    Elf64_Addr value;
     343  
     344    /* We cannot use a switch here because we cannot locate the switch
     345       jump table until we've self-relocated.  */
     346  
     347  #if !defined RTLD_BOOTSTRAP
     348    if (__builtin_expect (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_REL64LSB),
     349  			0))
     350      {
     351        assert (ELF64_R_TYPE (reloc->r_info) == R_IA64_REL64LSB);
     352        value = *reloc_addr + map->l_addr;
     353      }
     354    else
     355  #endif
     356      if (__builtin_expect (r_type == R_IA64_NONE, 0))
     357        return;
     358    else
     359      {
     360        struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version,
     361  					      r_type);
     362  
     363        /* RESOLVE_MAP() will return NULL if it fail to locate the symbol.  */
     364        if (sym_map != NULL)
     365  	{
     366  	  value = SYMBOL_ADDRESS (sym_map, sym, true) + reloc->r_addend;
     367  
     368  	  if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_DIR64LSB))
     369  	    ;/* No adjustment.  */
     370  	  else if (r_type == R_IA64_IPLTLSB)
     371  	    {
     372  	      elf_machine_fixup_plt (NULL, NULL, NULL, NULL, reloc, reloc_addr,
     373  				     DL_FIXUP_MAKE_VALUE (sym_map, value));
     374  	      return;
     375  	    }
     376  	  else if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_FPTR64LSB))
     377  	    value = _dl_make_fptr (sym_map, sym, value);
     378  	  else if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_PCREL64LSB))
     379  	    value -= (Elf64_Addr) reloc_addr & -16;
     380  	  else if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_DTPMOD64LSB))
     381  #ifdef RTLD_BOOTSTRAP
     382  	    /* During startup the dynamic linker is always index 1.  */
     383  	    value = 1;
     384  #else
     385  	    /* Get the information from the link map returned by the
     386  	       resolv function.  */
     387  	    value = sym_map->l_tls_modid;
     388  	  else if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_DTPREL64LSB))
     389  	    value -= sym_map->l_addr;
     390  #endif
     391  	  else if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_TPREL64LSB))
     392  	    {
     393  #ifndef RTLD_BOOTSTRAP
     394  	      CHECK_STATIC_TLS (map, sym_map);
     395  #endif
     396  	      value += sym_map->l_tls_offset - sym_map->l_addr;
     397  	    }
     398  	  else
     399  	    _dl_reloc_bad_type (map, r_type, 0);
     400  	}
     401        else
     402  	value = 0;
     403      }
     404  
     405    /* ??? Ignore MSB and Instruction format for now.  */
     406    if (R_IA64_FORMAT (r_type) == R_IA64_FORMAT_64LSB)
     407      *reloc_addr = value;
     408    else if (R_IA64_FORMAT (r_type) == R_IA64_FORMAT_32LSB)
     409      *(int *) reloc_addr = value;
     410    else if (r_type == R_IA64_IPLTLSB)
     411      {
     412        reloc_addr[0] = 0;
     413        reloc_addr[1] = 0;
     414      }
     415    else
     416      _dl_reloc_bad_type (map, r_type, 0);
     417  }
     418  
     419  /* Let do-rel.h know that on IA-64 if l_addr is 0, all RELATIVE relocs
     420     can be skipped.  */
     421  #define ELF_MACHINE_REL_RELATIVE 1
     422  
     423  static inline void
     424  __attribute ((always_inline))
     425  elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
     426  			   void *const reloc_addr_arg)
     427  {
     428    Elf64_Addr *const reloc_addr = reloc_addr_arg;
     429    /* ??? Ignore MSB and Instruction format for now.  */
     430    assert (ELF64_R_TYPE (reloc->r_info) == R_IA64_REL64LSB);
     431  
     432    *reloc_addr += l_addr;
     433  }
     434  
     435  /* Perform a RELATIVE reloc on the .got entry that transfers to the .plt.  */
     436  static inline void
     437  __attribute ((always_inline))
     438  elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
     439  		      Elf64_Addr l_addr, const Elf64_Rela *reloc,
     440  		      int skip_ifunc)
     441  {
     442    Elf64_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
     443    const unsigned long int r_type = ELF64_R_TYPE (reloc->r_info);
     444  
     445    if (r_type == R_IA64_IPLTLSB)
     446      {
     447        reloc_addr[0] += l_addr;
     448        reloc_addr[1] += l_addr;
     449      }
     450    else if (r_type == R_IA64_NONE)
     451      return;
     452    else
     453      _dl_reloc_bad_type (map, r_type, 1);
     454  }
     455  
     456  #endif /* RESOLVE_MAP */