(root)/
glibc-2.38/
sysdeps/
i386/
dl-machine.h
       1  /* Machine-dependent ELF dynamic relocation inline functions.  i386 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
      21  
      22  #define ELF_MACHINE_NAME "i386"
      23  
      24  #include <assert.h>
      25  #include <sys/param.h>
      26  #include <sysdep.h>
      27  #include <tls.h>
      28  #include <dl-tlsdesc.h>
      29  #include <dl-static-tls.h>
      30  #include <dl-machine-rel.h>
      31  
      32  /* Return nonzero iff ELF header is compatible with the running host.  */
      33  static inline int __attribute__ ((unused))
      34  elf_machine_matches_host (const Elf32_Ehdr *ehdr)
      35  {
      36    return ehdr->e_machine == EM_386;
      37  }
      38  
      39  
      40  /* Return the run-time load address of the shared object.  */
      41  static inline Elf32_Addr __attribute__ ((unused))
      42  elf_machine_load_address (void)
      43  {
      44    extern const Elf32_Ehdr __ehdr_start attribute_hidden;
      45    return (Elf32_Addr) &__ehdr_start;
      46  }
      47  
      48  /* Return the link-time address of _DYNAMIC.  */
      49  static inline Elf32_Addr __attribute__ ((unused))
      50  elf_machine_dynamic (void)
      51  {
      52    extern Elf32_Dyn _DYNAMIC[] attribute_hidden;
      53    return (Elf32_Addr) _DYNAMIC - elf_machine_load_address ();
      54  }
      55  
      56  /* Set up the loaded object described by L so its unrelocated PLT
      57     entries will jump to the on-demand fixup code in dl-runtime.c.  */
      58  
      59  static inline int __attribute__ ((unused, always_inline))
      60  elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
      61  			   int lazy, int profile)
      62  {
      63    Elf32_Addr *got;
      64    extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden;
      65    extern void _dl_runtime_profile (Elf32_Word) attribute_hidden;
      66    extern void _dl_runtime_resolve_shstk (Elf32_Word) attribute_hidden;
      67    extern void _dl_runtime_profile_shstk (Elf32_Word) attribute_hidden;
      68    /* Check if SHSTK is enabled by kernel.  */
      69    bool shstk_enabled
      70      = (GL(dl_x86_feature_1) & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0;
      71  
      72    if (l->l_info[DT_JMPREL] && lazy)
      73      {
      74        /* The GOT entries for functions in the PLT have not yet been filled
      75  	 in.  Their initial contents will arrange when called to push an
      76  	 offset into the .rel.plt section, push _GLOBAL_OFFSET_TABLE_[1],
      77  	 and then jump to _GLOBAL_OFFSET_TABLE[2].  */
      78        got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
      79        /* If a library is prelinked but we have to relocate anyway,
      80  	 we have to be able to undo the prelinking of .got.plt.
      81  	 The prelinker saved us here address of .plt + 0x16.  */
      82        if (got[1])
      83  	{
      84  	  l->l_mach.plt = got[1] + l->l_addr;
      85  	  l->l_mach.gotplt = (Elf32_Addr) &got[3];
      86  	}
      87        got[1] = (Elf32_Addr) l;	/* Identify this shared object.  */
      88  
      89        /* The got[2] entry contains the address of a function which gets
      90  	 called to get the address of a so far unresolved function and
      91  	 jump to it.  The profiling extension of the dynamic linker allows
      92  	 to intercept the calls to collect information.  In this case we
      93  	 don't store the address in the GOT so that all future calls also
      94  	 end in this function.  */
      95        if (__glibc_unlikely (profile))
      96  	{
      97  	  got[2] = (shstk_enabled
      98  		    ? (Elf32_Addr) &_dl_runtime_profile_shstk
      99  		    : (Elf32_Addr) &_dl_runtime_profile);
     100  
     101  	  if (GLRO(dl_profile) != NULL
     102  	      && _dl_name_match_p (GLRO(dl_profile), l))
     103  	    /* This is the object we are looking for.  Say that we really
     104  	       want profiling and the timers are started.  */
     105  	    GL(dl_profile_map) = l;
     106  	}
     107        else
     108  	/* This function will get called to fix up the GOT entry indicated by
     109  	   the offset on the stack, and then jump to the resolved address.  */
     110  	got[2] = (shstk_enabled
     111  		  ? (Elf32_Addr) &_dl_runtime_resolve_shstk
     112  		  : (Elf32_Addr) &_dl_runtime_resolve);
     113      }
     114  
     115    return lazy;
     116  }
     117  
     118  /* Mask identifying addresses reserved for the user program,
     119     where the dynamic linker should not map anything.  */
     120  #define ELF_MACHINE_USER_ADDRESS_MASK	0xf8000000UL
     121  
     122  /* Initial entry point code for the dynamic linker.
     123     The C function `_dl_start' is the real entry point;
     124     its return value is the user program's entry point.  */
     125  
     126  #define RTLD_START asm ("\n\
     127  	.text\n\
     128  	.align 16\n\
     129  0:	movl (%esp), %ebx\n\
     130  	ret\n\
     131  	.align 16\n\
     132  .globl _start\n\
     133  .globl _dl_start_user\n\
     134  _start:\n\
     135  	movl %esp, %eax\n\
     136          subl $12, %esp\n\
     137          pushl %eax\n\
     138  	call _dl_start\n\
     139          addl $16, %esp\n\
     140  _dl_start_user:\n\
     141  	# Save the user entry point address in %edi.\n\
     142  	movl %eax, %edi\n\
     143  	# Point %ebx at the GOT.\n\
     144  	call 0b\n\
     145  	addl $_GLOBAL_OFFSET_TABLE_, %ebx\n\
     146  	# Read the original argument count.\n\
     147  	movl (%esp), %edx\n\
     148  	# The special initializer gets called with the stack just\n\
     149  	# as the application's entry point will see it; it can\n\
     150  	# switch stacks if it moves these contents over.\n\
     151  " RTLD_START_SPECIAL_INIT "\n\
     152  	# Load the parameters again.\n\
     153  	# (eax, edx, ecx, esi) = (_dl_loaded, argc, argv, envp)\n\
     154  	movl _rtld_local@GOTOFF(%ebx), %eax\n\
     155  	leal 8(%esp,%edx,4), %esi\n\
     156  	leal 4(%esp), %ecx\n\
     157  	movl %esp, %ebp\n\
     158  	# Make sure _dl_init is run with 16 byte aligned stack.\n\
     159  	andl $-16, %esp\n\
     160          subl $12, %esp\n\
     161  	pushl %ebp\n\
     162          # Arguments for _dl_init.\n\
     163  	pushl %esi\n\
     164  	pushl %ecx\n\
     165  	pushl %edx\n\
     166  	pushl %eax\n\
     167  	# Clear %ebp, so that even constructors have terminated backchain.\n\
     168  	xorl %ebp, %ebp\n\
     169  	# Call the function to run the initializers.\n\
     170  	call _dl_init\n\
     171  	# Pass our finalizer function to the user in %edx, as per ELF ABI.\n\
     172  	leal _dl_fini@GOTOFF(%ebx), %edx\n\
     173  	# Restore %esp _start expects.\n\
     174  	movl 16(%esp), %esp\n\
     175  	# Jump to the user's entry point.\n\
     176  	jmp *%edi\n\
     177  	.previous\n\
     178  ");
     179  
     180  #ifndef RTLD_START_SPECIAL_INIT
     181  # define RTLD_START_SPECIAL_INIT /* nothing */
     182  #endif
     183  
     184  /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
     185     TLS variable, so undefined references should not be allowed to
     186     define the value.
     187     ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve to one
     188     of the main executable's symbols, as for a COPY reloc.  */
     189  # define elf_machine_type_class(type) \
     190    ((((type) == R_386_JMP_SLOT || (type) == R_386_TLS_DTPMOD32		      \
     191       || (type) == R_386_TLS_DTPOFF32 || (type) == R_386_TLS_TPOFF32	      \
     192       || (type) == R_386_TLS_TPOFF || (type) == R_386_TLS_DESC)		      \
     193      * ELF_RTYPE_CLASS_PLT)						      \
     194     | (((type) == R_386_COPY) * ELF_RTYPE_CLASS_COPY))
     195  
     196  /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
     197  #define ELF_MACHINE_JMP_SLOT	R_386_JMP_SLOT
     198  
     199  /* We define an initialization functions.  This is called very early in
     200     _dl_sysdep_start.  */
     201  #define DL_PLATFORM_INIT dl_platform_init ()
     202  
     203  static inline void __attribute__ ((unused))
     204  dl_platform_init (void)
     205  {
     206  #if IS_IN (rtld)
     207    /* _dl_x86_init_cpu_features is a wrapper for init_cpu_features which
     208       has been called early from __libc_start_main in static executable.  */
     209    _dl_x86_init_cpu_features ();
     210  #else
     211    if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
     212      /* Avoid an empty string which would disturb us.  */
     213      GLRO(dl_platform) = NULL;
     214  #endif
     215  }
     216  
     217  static inline Elf32_Addr
     218  elf_machine_fixup_plt (struct link_map *map, lookup_t t,
     219  		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
     220  		       const Elf32_Rel *reloc,
     221  		       Elf32_Addr *reloc_addr, Elf32_Addr value)
     222  {
     223    return *reloc_addr = value;
     224  }
     225  
     226  /* Return the final value of a plt relocation.  */
     227  static inline Elf32_Addr
     228  elf_machine_plt_value (struct link_map *map, const Elf32_Rel *reloc,
     229  		       Elf32_Addr value)
     230  {
     231    return value;
     232  }
     233  
     234  
     235  /* Names of the architecture-specific auditing callback functions.  */
     236  #define ARCH_LA_PLTENTER i86_gnu_pltenter
     237  #define ARCH_LA_PLTEXIT i86_gnu_pltexit
     238  
     239  #endif /* !dl_machine_h */
     240  
     241  #ifdef RESOLVE_MAP
     242  
     243  /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
     244     MAP is the object containing the reloc.  */
     245  
     246  static inline void
     247  __attribute ((always_inline))
     248  elf_machine_rel (struct link_map *map, struct r_scope_elem *scope[],
     249  		 const Elf32_Rel *reloc,
     250  		 const Elf32_Sym *sym, const struct r_found_version *version,
     251  		 void *const reloc_addr_arg, int skip_ifunc)
     252  {
     253    Elf32_Addr *const reloc_addr = reloc_addr_arg;
     254    const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
     255  
     256  # if !defined RTLD_BOOTSTRAP
     257    if (__glibc_unlikely (r_type == R_386_RELATIVE))
     258      *reloc_addr += map->l_addr;
     259  #  ifndef RTLD_BOOTSTRAP
     260    else if (__glibc_unlikely (r_type == R_386_NONE))
     261      return;
     262  #  endif
     263    else
     264  # endif	/* !RTLD_BOOTSTRAP */
     265      {
     266  # ifndef RTLD_BOOTSTRAP
     267        const Elf32_Sym *const refsym = sym;
     268  # endif
     269        struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version,
     270  					      r_type);
     271        Elf32_Addr value = SYMBOL_ADDRESS (sym_map, sym, true);
     272  
     273        if (sym != NULL
     274  	  && __glibc_unlikely (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC)
     275  	  && __glibc_likely (sym->st_shndx != SHN_UNDEF)
     276  	  && __glibc_likely (!skip_ifunc))
     277  	{
     278  # ifndef RTLD_BOOTSTRAP
     279  	  if (sym_map != map
     280  	      && !sym_map->l_relocated)
     281  	    {
     282  	      const char *strtab
     283  		= (const char *) D_PTR (map, l_info[DT_STRTAB]);
     284  	      if (sym_map->l_type == lt_executable)
     285  		_dl_fatal_printf ("\
     286  %s: IFUNC symbol '%s' referenced in '%s' is defined in the executable \
     287  and creates an unsatisfiable circular dependency.\n",
     288  				  RTLD_PROGNAME, strtab + refsym->st_name,
     289  				  map->l_name);
     290  	      else
     291  		_dl_error_printf ("\
     292  %s: Relink `%s' with `%s' for IFUNC symbol `%s'\n",
     293  				  RTLD_PROGNAME, map->l_name,
     294  				  sym_map->l_name,
     295  				  strtab + refsym->st_name);
     296  	    }
     297  # endif
     298  	  value = ((Elf32_Addr (*) (void)) value) ();
     299  	}
     300  
     301        switch (r_type)
     302  	{
     303  # ifndef RTLD_BOOTSTRAP
     304  	case R_386_SIZE32:
     305  	  /* Set to symbol size plus addend.  */
     306  	  *reloc_addr += sym->st_size;
     307  	  break;
     308  # endif
     309  	case R_386_GLOB_DAT:
     310  	case R_386_JMP_SLOT:
     311  	  *reloc_addr = value;
     312  	  break;
     313  
     314  	case R_386_TLS_DTPMOD32:
     315  # ifdef RTLD_BOOTSTRAP
     316  	  /* During startup the dynamic linker is always the module
     317  	     with index 1.
     318  	     XXX If this relocation is necessary move before RESOLVE
     319  	     call.  */
     320  	  *reloc_addr = 1;
     321  # else
     322  	  /* Get the information from the link map returned by the
     323  	     resolv function.  */
     324  	  if (sym_map != NULL)
     325  	    *reloc_addr = sym_map->l_tls_modid;
     326  # endif
     327  	  break;
     328  	case R_386_TLS_DTPOFF32:
     329  # ifndef RTLD_BOOTSTRAP
     330  	  /* During relocation all TLS symbols are defined and used.
     331  	     Therefore the offset is already correct.  */
     332  	  if (sym != NULL)
     333  	    *reloc_addr = sym->st_value;
     334  # endif
     335  	  break;
     336  	case R_386_TLS_DESC:
     337  	  {
     338  	    struct tlsdesc volatile *td =
     339  	      (struct tlsdesc volatile *)reloc_addr;
     340  
     341  # ifndef RTLD_BOOTSTRAP
     342  	    if (! sym)
     343  	      td->entry = _dl_tlsdesc_undefweak;
     344  	    else
     345  # endif
     346  	      {
     347  # ifndef RTLD_BOOTSTRAP
     348  #  ifndef SHARED
     349  		CHECK_STATIC_TLS (map, sym_map);
     350  #  else
     351  		if (!TRY_STATIC_TLS (map, sym_map))
     352  		  {
     353  		    td->arg = _dl_make_tlsdesc_dynamic
     354  		      (sym_map, sym->st_value + (ElfW(Word))td->arg);
     355  		    td->entry = _dl_tlsdesc_dynamic;
     356  		  }
     357  		else
     358  #  endif
     359  # endif
     360  		  {
     361  		    td->arg = (void*)(sym->st_value - sym_map->l_tls_offset
     362  				      + (ElfW(Word))td->arg);
     363  		    td->entry = _dl_tlsdesc_return;
     364  		  }
     365  	      }
     366  	    break;
     367  	  }
     368  	case R_386_TLS_TPOFF32:
     369  	  /* The offset is positive, backward from the thread pointer.  */
     370  #  ifdef RTLD_BOOTSTRAP
     371  	  *reloc_addr += map->l_tls_offset - sym->st_value;
     372  #  else
     373  	  /* We know the offset of object the symbol is contained in.
     374  	     It is a positive value which will be subtracted from the
     375  	     thread pointer.  To get the variable position in the TLS
     376  	     block we subtract the offset from that of the TLS block.  */
     377  	  if (sym != NULL)
     378  	    {
     379  	      CHECK_STATIC_TLS (map, sym_map);
     380  	      *reloc_addr += sym_map->l_tls_offset - sym->st_value;
     381  	    }
     382  # endif
     383  	  break;
     384  	case R_386_TLS_TPOFF:
     385  	  /* The offset is negative, forward from the thread pointer.  */
     386  # ifdef RTLD_BOOTSTRAP
     387  	  *reloc_addr += sym->st_value - map->l_tls_offset;
     388  # else
     389  	  /* We know the offset of object the symbol is contained in.
     390  	     It is a negative value which will be added to the
     391  	     thread pointer.  */
     392  	  if (sym != NULL)
     393  	    {
     394  	      CHECK_STATIC_TLS (map, sym_map);
     395  	      *reloc_addr += sym->st_value - sym_map->l_tls_offset;
     396  	    }
     397  # endif
     398  	  break;
     399  
     400  # ifndef RTLD_BOOTSTRAP
     401  	case R_386_32:
     402  	  *reloc_addr += value;
     403  	  break;
     404  	case R_386_PC32:
     405  	  *reloc_addr += (value - (Elf32_Addr) reloc_addr);
     406  	  break;
     407  	case R_386_COPY:
     408  	  if (sym == NULL)
     409  	    /* This can happen in trace mode if an object could not be
     410  	       found.  */
     411  	    break;
     412  	  if (__glibc_unlikely (sym->st_size > refsym->st_size)
     413  	      || (__glibc_unlikely(sym->st_size < refsym->st_size)
     414  		  && GLRO(dl_verbose)))
     415  	    {
     416  	      const char *strtab;
     417  
     418  	      strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
     419  	      _dl_error_printf ("\
     420  %s: Symbol `%s' has different size in shared object, consider re-linking\n",
     421  				RTLD_PROGNAME, strtab + refsym->st_name);
     422  	    }
     423  	  memcpy (reloc_addr_arg, (void *) value,
     424  		  MIN (sym->st_size, refsym->st_size));
     425  	  break;
     426  	case R_386_IRELATIVE:
     427  	  value = map->l_addr + *reloc_addr;
     428  	  if (__glibc_likely (!skip_ifunc))
     429  	    value = ((Elf32_Addr (*) (void)) value) ();
     430  	  *reloc_addr = value;
     431  	  break;
     432  	default:
     433  	  _dl_reloc_bad_type (map, r_type, 0);
     434  	  break;
     435  # endif	/* !RTLD_BOOTSTRAP */
     436  	}
     437      }
     438  }
     439  
     440  
     441  static inline void
     442  __attribute ((always_inline))
     443  elf_machine_rel_relative (Elf32_Addr l_addr, const Elf32_Rel *reloc,
     444  			  void *const reloc_addr_arg)
     445  {
     446    Elf32_Addr *const reloc_addr = reloc_addr_arg;
     447    assert (ELF32_R_TYPE (reloc->r_info) == R_386_RELATIVE);
     448    *reloc_addr += l_addr;
     449  }
     450  
     451  # ifndef RTLD_BOOTSTRAP
     452  static inline void
     453  __attribute__ ((always_inline))
     454  elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
     455  			   void *const reloc_addr_arg)
     456  {
     457    Elf32_Addr *const reloc_addr = reloc_addr_arg;
     458    *reloc_addr = l_addr + reloc->r_addend;
     459  }
     460  # endif	/* !RTLD_BOOTSTRAP */
     461  
     462  static inline void
     463  __attribute__ ((always_inline))
     464  elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
     465  		      Elf32_Addr l_addr, const Elf32_Rel *reloc,
     466  		      int skip_ifunc)
     467  {
     468    Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
     469    const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
     470    /* Check for unexpected PLT reloc type.  */
     471    if (__glibc_likely (r_type == R_386_JMP_SLOT))
     472      {
     473        /* Prelink has been deprecated.  */
     474        if (__glibc_likely (map->l_mach.plt == 0))
     475  	*reloc_addr += l_addr;
     476        else
     477  	*reloc_addr = (map->l_mach.plt
     478  		       + (((Elf32_Addr) reloc_addr) - map->l_mach.gotplt) * 4);
     479      }
     480    else if (__glibc_likely (r_type == R_386_TLS_DESC))
     481      {
     482        const Elf32_Rel *const r = reloc;
     483        /* The code below was borrowed from elf_dynamic_do_rel().  */
     484        const ElfW(Sym) *const symtab =
     485  	(const void *) D_PTR (map, l_info[DT_SYMTAB]);
     486  
     487        /* Always initialize TLS descriptors completely at load time, in
     488  	 case static TLS is allocated for it that requires locking.  */
     489  # ifdef RTLD_BOOTSTRAP
     490        /* The dynamic linker always uses versioning.  */
     491        assert (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL);
     492  # else
     493        if (map->l_info[VERSYMIDX (DT_VERSYM)])
     494  # endif
     495  	{
     496  	  const ElfW(Half) *const version =
     497  	    (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
     498  	  ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
     499  	  elf_machine_rel (map, scope, r, &symtab[ELFW(R_SYM) (r->r_info)],
     500  			   &map->l_versions[ndx],
     501  			   (void *) (l_addr + r->r_offset), skip_ifunc);
     502  	}
     503  # ifndef RTLD_BOOTSTRAP
     504        else
     505  	elf_machine_rel (map, scope, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL,
     506  			 (void *) (l_addr + r->r_offset), skip_ifunc);
     507  # endif
     508      }
     509    else if (__glibc_unlikely (r_type == R_386_IRELATIVE))
     510      {
     511        Elf32_Addr value = map->l_addr + *reloc_addr;
     512        if (__glibc_likely (!skip_ifunc))
     513  	value = ((Elf32_Addr (*) (void)) value) ();
     514        *reloc_addr = value;
     515      }
     516    else
     517      _dl_reloc_bad_type (map, r_type, 1);
     518  }
     519  
     520  #endif /* RESOLVE_MAP */