(root)/
glibc-2.38/
sysdeps/
csky/
dl-machine.h
       1  /* Machine-dependent ELF dynamic relocation inline functions.  C-SKY version.
       2     Copyright (C) 2018-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 "csky"
      23  
      24  #include <sys/param.h>
      25  #include <sysdep.h>
      26  #include <dl-tls.h>
      27  #include <dl-static-tls.h>
      28  #include <dl-machine-rel.h>
      29  
      30  /* Return nonzero if ELF header is compatible with the running host.  */
      31  static inline int
      32  elf_machine_matches_host (const Elf32_Ehdr *ehdr)
      33  {
      34    return ehdr->e_machine == EM_CSKY;
      35  }
      36  
      37  /* Return the link-time address of _DYNAMIC.
      38     This must be inlined in a function which uses global data.  */
      39  static inline Elf32_Addr
      40  elf_machine_dynamic (void)
      41  {
      42    register Elf32_Addr *got __asm__ ("gb");
      43    return *got;
      44  }
      45  
      46  /* Return the run-time load address ,of the shared object.  */
      47  static inline Elf32_Addr
      48  elf_machine_load_address (void)
      49  {
      50    extern Elf32_Addr __dl_start (void *) asm ("_dl_start");
      51    Elf32_Addr got_addr = (Elf32_Addr) &__dl_start;
      52    Elf32_Addr pcrel_addr;
      53    asm  ("grs %0,_dl_start\n" : "=r" (pcrel_addr));
      54  
      55    return pcrel_addr - got_addr;
      56  }
      57  
      58  
      59  /* Set up the loaded object described by L so its unrelocated PLT
      60     entries will jump to the on-demand fixup code in dl-runtime.c.  */
      61  
      62  static inline int __attribute__ ((always_inline))
      63  elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
      64  			   int lazy, int profile)
      65  {
      66    Elf32_Addr *got;
      67    extern void _dl_runtime_resolve (Elf32_Word);
      68  
      69    if (l->l_info[DT_JMPREL] && lazy)
      70      {
      71        /* The GOT entries for functions in the PLT have not yet been
      72  	 filled in.  Their initial contents will arrange when called
      73  	 to push an offset into the .rela.plt section, push
      74  	 _GLOBAL_OFFSET_TABLE_[1], and then jump to
      75  	 _GLOBAL_OFFSET_TABLE_[2].  */
      76        got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
      77  
      78        if (got[1])
      79  	l->l_mach.plt = got[1] + l->l_addr;
      80        got[1] = (Elf32_Addr) l; /* Identify this shared object.  */
      81  
      82        /* The got[2] entry contains the address of a function which gets
      83  	 called to get the address of a so far unresolved function and
      84  	 jump to it.  The profiling extension of the dynamic linker allows
      85  	 to intercept the calls to collect information.  In this case we
      86  	 don't store the address in the GOT so that all future calls also
      87  	 end in this function.  */
      88  	got[2] = (Elf32_Addr) &_dl_runtime_resolve;
      89      }
      90    return lazy;
      91  }
      92  
      93  /* Mask identifying addresses reserved for the user program,
      94     where the dynamic linker should not map anything.  */
      95  #define ELF_MACHINE_USER_ADDRESS_MASK 0x80000000UL
      96  
      97  /* Initial entry point code for the dynamic linker.
      98     The C function `_dl_start' is the real entry point;
      99     its return value is the user program's entry point.  */
     100  #define RTLD_START asm ("\
     101  .text\n\
     102  .globl _start\n\
     103  .type _start, @function\n\
     104  .globl _dl_start_user\n\
     105  .type _dl_start_user, @function\n\
     106  _start:\n\
     107  	grs	gb, .Lgetpc1\n\
     108  .Lgetpc1:\n\
     109  	lrw	t0, .Lgetpc1@GOTPC\n\
     110  	addu	gb, t0\n\
     111  	mov	a0, sp\n\
     112  	lrw	t1, _dl_start@GOTOFF\n\
     113  	addu	t1, gb\n\
     114  	jsr	t1\n\
     115  _dl_start_user:\n\
     116  	/* store program entry address in r10 */ \n\
     117  	mov	r10, a0\n\
     118  	/* Get argc */\n\
     119  	ldw	a1, (sp, 0)\n\
     120  	/* Get **argv */\n\
     121  	mov	a2, sp\n\
     122  	addi	a2, 4\n\
     123  	cmpnei	r11, 0\n\
     124  	mov	a3, a1\n\
     125  	lsli	a3, 2\n\
     126  	add	a3, a2\n\
     127  	addi	a3, 4\n\
     128  	lrw	a0, _rtld_local@GOTOFF\n\
     129  	addu	a0, gb\n\
     130  	ldw	a0, (a0, 0)\n\
     131  	lrw	t1, _dl_init@PLT\n\
     132  	addu	t1, gb\n\
     133  	ldw	t1, (t1)\n\
     134  	jsr	t1\n\
     135  	lrw	a0, _dl_fini@GOTOFF\n\
     136  	addu	a0, gb\n\
     137  	jmp	r10\n\
     138  ");
     139  
     140  /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
     141     TLS variable, so undefined references should not be allowed to
     142     define the value.
     143     ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
     144     of the main executable's symbols, as for a COPY reloc.  */
     145  #ifndef RTLD_BOOTSTRAP
     146  # define elf_machine_type_class(type) \
     147    ((((type) == R_CKCORE_JUMP_SLOT || (type) == R_CKCORE_TLS_DTPMOD32	   \
     148       || (type) == R_CKCORE_TLS_DTPOFF32 || (type) == R_CKCORE_TLS_TPOFF32) \
     149      * ELF_RTYPE_CLASS_PLT)						   \
     150     | (((type) == R_CKCORE_COPY) * ELF_RTYPE_CLASS_COPY))
     151  #else
     152  # define elf_machine_type_class(type) \
     153    ((((type) == R_CKCORE_JUMP_SLOT     \
     154     | (((type) == R_CKCORE_COPY) * ELF_RTYPE_CLASS_COPY))
     155  #endif
     156  
     157  /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
     158  #define ELF_MACHINE_JMP_SLOT R_CKCORE_JUMP_SLOT
     159  
     160  /* We define an initialization functions.  This is called very early in
     161     _dl_sysdep_start.  */
     162  #define DL_PLATFORM_INIT dl_platform_init ()
     163  
     164  static inline void __attribute__ ((unused))
     165  dl_platform_init (void)
     166  {
     167    if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
     168      /* Avoid an empty string which would disturb us.  */
     169      GLRO(dl_platform) = NULL;
     170  }
     171  
     172  static inline Elf32_Addr
     173  elf_machine_fixup_plt (struct link_map *map, lookup_t t,
     174  		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
     175  		       const Elf32_Rela *reloc,
     176  		       Elf32_Addr *reloc_addr, Elf32_Addr value)
     177  {
     178    return *reloc_addr = value;
     179  }
     180  
     181  /* Return the final value of a plt relocation.  On the csky the JMP_SLOT
     182     relocation ignores the addend.  */
     183  static inline Elf32_Addr
     184  elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
     185  		       Elf32_Addr value)
     186  {
     187    return value;
     188  }
     189  
     190  /* Names of the architecture-specific auditing callback functions.  */
     191  #define ARCH_LA_PLTENTER csky_gnu_pltenter
     192  #define ARCH_LA_PLTEXIT csky_gnu_pltexit
     193  
     194  #endif /* !dl_machine_h */
     195  #ifdef RESOLVE_MAP
     196  
     197  /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
     198     MAP is the object containing the reloc.  */
     199  
     200  static inline void __attribute__ ((unused, always_inline))
     201  elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
     202  		  const Elf32_Rela *reloc, const Elf32_Sym *sym,
     203  		  const struct r_found_version *version,
     204  		  void *const reloc_addr_arg, int skip_ifunc)
     205  {
     206    Elf32_Addr *const reloc_addr = reloc_addr_arg;
     207    const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
     208    unsigned short __attribute__ ((unused)) *opcode16_addr;
     209    Elf32_Addr __attribute__ ((unused)) insn_opcode = 0x0;
     210  
     211    if (__builtin_expect (r_type == R_CKCORE_RELATIVE, 0))
     212      *reloc_addr = map->l_addr + reloc->r_addend;
     213    else
     214      {
     215        const Elf32_Sym *const refsym = sym;
     216        struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version,
     217  					      r_type);
     218        ElfW(Addr) value = SYMBOL_ADDRESS (sym_map, sym, true);
     219        opcode16_addr = (unsigned short *)reloc_addr;
     220  
     221        switch (r_type)
     222  	{
     223  	case R_CKCORE_COPY:
     224  	  if (sym == NULL)
     225  	    /* This can happen in trace mode if an object could not be
     226  	       found.  */
     227  	    break;
     228  	  if (sym->st_size > refsym->st_size
     229  	      || (sym->st_size < refsym->st_size && GLRO(dl_verbose)))
     230  	    {
     231  	      const char *strtab;
     232  
     233  	      strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
     234  	      _dl_error_printf ("\
     235  %s: Symbol `%s' has different size in shared object, consider re-linking\n",
     236  				rtld_progname ?: "<program name unknown>",
     237  				strtab + refsym->st_name);
     238  	    }
     239  	  memcpy (reloc_addr_arg, (void *) value,
     240  		  MIN (sym->st_size, refsym->st_size));
     241  	  break;
     242  	case R_CKCORE_GLOB_DAT:
     243  	case R_CKCORE_JUMP_SLOT:
     244  	  *reloc_addr = value;
     245  	  break;
     246  	case R_CKCORE_ADDR32:
     247  	  *reloc_addr = value + reloc->r_addend;
     248  	  break;
     249  	case R_CKCORE_PCREL32:
     250  	  *reloc_addr = value + reloc->r_addend - (Elf32_Addr) reloc_addr;
     251  	  break;
     252  #if defined(__CK810__) || defined(__CK807__)
     253  	case R_CKCORE_ADDR_HI16:
     254  	  insn_opcode = (*opcode16_addr << 16) | (*(opcode16_addr + 1));
     255  	  insn_opcode = (insn_opcode & 0xffff0000)
     256  			    | (((value + reloc->r_addend) >> 16) & 0xffff);
     257  	  *(opcode16_addr++) = (unsigned short)(insn_opcode >> 16);
     258  	  *opcode16_addr = (unsigned short)(insn_opcode & 0xffff);
     259  	  break;
     260  	case R_CKCORE_ADDR_LO16:
     261  	  insn_opcode = (*opcode16_addr << 16) | (*(opcode16_addr + 1));
     262  	  insn_opcode = (insn_opcode & 0xffff0000)
     263  			    | ((value + reloc->r_addend) & 0xffff);
     264  	   *(opcode16_addr++) = (unsigned short)(insn_opcode >> 16);
     265  	   *opcode16_addr = (unsigned short)(insn_opcode & 0xffff);
     266  	   break;
     267  	case R_CKCORE_PCREL_IMM26BY2:
     268  	{
     269  	  unsigned int offset = ((value + reloc->r_addend
     270  				  - (unsigned int)reloc_addr) >> 1);
     271  	  insn_opcode = (*opcode16_addr << 16) | (*(opcode16_addr + 1));
     272  	  if (offset > 0x3ffffff){
     273  	    const char *strtab;
     274  	    strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
     275  
     276  	    _dl_error_printf ("\
     277  %s:The reloc R_CKCORE_PCREL_IMM26BY2 cannot reach the symbol '%s'.\n",
     278  	      rtld_progname ?: "<program name unknown>",
     279  	      strtab + refsym->st_name);
     280  	    break;
     281  	  }
     282  	  insn_opcode = (insn_opcode & ~0x3ffffff) | offset;
     283  	  *(opcode16_addr++) = (unsigned short)(insn_opcode >> 16);
     284  	  *opcode16_addr = (unsigned short)(insn_opcode & 0xffff);
     285  	  break;
     286  	}
     287  	case R_CKCORE_PCREL_JSR_IMM26BY2:
     288  	  break;
     289  #endif
     290  #ifndef RTLD_BOOTSTRAP
     291  	case R_CKCORE_TLS_DTPMOD32:
     292  	/* Get the information from the link map returned by the
     293  	   resolv function.  */
     294  	  if (sym_map != NULL)
     295  	    *reloc_addr = sym_map->l_tls_modid;
     296  	  break;
     297  	case R_CKCORE_TLS_DTPOFF32:
     298  	  if (sym != NULL)
     299  	    *reloc_addr =(sym == NULL ? 0 : sym->st_value) + reloc->r_addend;
     300  	  break;
     301  	case R_CKCORE_TLS_TPOFF32:
     302  	  if (sym != NULL)
     303  	    {
     304  	      CHECK_STATIC_TLS (map, sym_map);
     305  	      *reloc_addr = (sym->st_value + sym_map->l_tls_offset
     306  			     + reloc->r_addend);
     307  	    }
     308  	  break;
     309  #endif /* !RTLD_BOOTSTRAP */
     310  	case R_CKCORE_NONE:
     311  	  break;
     312  	default:
     313  	  break;
     314  	}
     315      }
     316  }
     317  
     318  static inline void __attribute__ ((unused, always_inline))
     319  elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
     320  			   void *const reloc_addr_arg)
     321  {
     322    Elf32_Addr *const reloc_addr = reloc_addr_arg;
     323    *reloc_addr = l_addr + reloc->r_addend;
     324  }
     325  
     326  static inline void __attribute__ ((unused, always_inline))
     327  elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
     328  		      Elf32_Addr l_addr, const Elf32_Rela *reloc,
     329  		      int skip_ifunc)
     330  {
     331    Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
     332    const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
     333    if (ELF32_R_TYPE (reloc->r_info) == R_CKCORE_JUMP_SLOT)
     334      {
     335        /* Check for unexpected PLT reloc type.  */
     336        if (__builtin_expect (r_type == R_CKCORE_JUMP_SLOT, 1))
     337  	{
     338  	  if (__builtin_expect (map->l_mach.plt, 0) == 0)
     339  	    *reloc_addr = l_addr + reloc->r_addend;
     340  	  else
     341  	    *reloc_addr = map->l_mach.plt;
     342  	}
     343      }
     344  }
     345  
     346  #endif /* RESOLVE_MAP */