(root)/
glibc-2.38/
elf/
dl-minimal.c
       1  /* Minimal replacements for basic facilities used in the dynamic linker.
       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  #include <assert.h>
      20  #include <ldsodefs.h>
      21  #include <dl-irel.h>
      22  #include <dl-hash.h>
      23  #include <dl-sym-post.h>
      24  #include <_itoa.h>
      25  #include <dl-minimal-malloc.h>
      26  #include <stdio.h>
      27  #include <unistd.h>
      28  #include <errno.h>
      29  
      30  /* The rtld startup code calls __rtld_malloc_init_stubs after the
      31    first self-relocation to adjust the pointers to the minimal
      32    implementation below.  Before the final relocation,
      33    __rtld_malloc_init_real is called to replace the pointers with the
      34    real implementation.  */
      35  __typeof (calloc) *__rtld_calloc attribute_relro;
      36  __typeof (free) *__rtld_free attribute_relro;
      37  __typeof (malloc) *__rtld_malloc attribute_relro;
      38  __typeof (realloc) *__rtld_realloc attribute_relro;
      39  
      40  void
      41  __rtld_malloc_init_stubs (void)
      42  {
      43    __rtld_calloc = &__minimal_calloc;
      44    __rtld_free = &__minimal_free;
      45    __rtld_malloc = &__minimal_malloc;
      46    __rtld_realloc = &__minimal_realloc;
      47  }
      48  
      49  bool
      50  __rtld_malloc_is_complete (void)
      51  {
      52    /* The caller assumes that there is an active malloc.  */
      53    assert (__rtld_malloc != NULL);
      54    return __rtld_malloc != &__minimal_malloc;
      55  }
      56  
      57  /* Lookup NAME at VERSION in the scope of MATCH.  */
      58  static void *
      59  lookup_malloc_symbol (struct link_map *main_map, const char *name,
      60  		      struct r_found_version *version)
      61  {
      62  
      63    const ElfW(Sym) *ref = NULL;
      64    lookup_t result = _dl_lookup_symbol_x (name, main_map, &ref,
      65  					 main_map->l_scope,
      66  					 version, 0, 0, NULL);
      67  
      68    assert (ELFW(ST_TYPE) (ref->st_info) != STT_TLS);
      69    void *value = DL_SYMBOL_ADDRESS (result, ref);
      70  
      71    return _dl_sym_post (result, ref, value, 0, main_map);
      72  }
      73  
      74  void
      75  __rtld_malloc_init_real (struct link_map *main_map)
      76  {
      77    /* We cannot use relocations and initializers for this because the
      78       changes made by __rtld_malloc_init_stubs break REL-style
      79       (non-RELA) relocations that depend on the previous pointer
      80       contents.  Also avoid direct relocation dependencies for the
      81       malloc symbols so this function can be called before the final
      82       rtld relocation (which enables RELRO, after which the pointer
      83       variables cannot be written to).  */
      84  
      85    struct r_found_version version;
      86    version.name = symbol_version_string (libc, GLIBC_2_0);
      87    version.hidden = 0;
      88    version.hash = _dl_elf_hash (version.name);
      89    version.filename = NULL;
      90  
      91    void *new_calloc = lookup_malloc_symbol (main_map, "calloc", &version);
      92    void *new_free = lookup_malloc_symbol (main_map, "free", &version);
      93    void *new_malloc = lookup_malloc_symbol (main_map, "malloc", &version);
      94    void *new_realloc = lookup_malloc_symbol (main_map, "realloc", &version);
      95  
      96    /* Update the pointers in one go, so that any internal allocations
      97       performed by lookup_malloc_symbol see a consistent
      98       implementation.  */
      99    __rtld_calloc = new_calloc;
     100    __rtld_free = new_free;
     101    __rtld_malloc = new_malloc;
     102    __rtld_realloc = new_realloc;
     103  }
     104  
     105  
     106  /* Avoid signal frobnication in setjmp/longjmp.  Keeps things smaller.  */
     107  
     108  #include <setjmp.h>
     109  
     110  int weak_function
     111  __sigjmp_save (sigjmp_buf env, int savemask __attribute__ ((unused)))
     112  {
     113    env[0].__mask_was_saved = 0;
     114    return 0;
     115  }
     116  
     117  /* Define our own version of the internal function used by strerror.  We
     118     only provide the messages for some common errors.  This avoids pulling
     119     in the whole error list.  */
     120  
     121  char * weak_function
     122  __strerror_r (int errnum, char *buf, size_t buflen)
     123  {
     124    char *msg;
     125  
     126    switch (errnum)
     127      {
     128      case ENOMEM:
     129        msg = (char *) "Cannot allocate memory";
     130        break;
     131      case EINVAL:
     132        msg = (char *) "Invalid argument";
     133        break;
     134      case ENOENT:
     135        msg = (char *) "No such file or directory";
     136        break;
     137      case EPERM:
     138        msg = (char *) "Operation not permitted";
     139        break;
     140      case EIO:
     141        msg = (char *) "Input/output error";
     142        break;
     143      case EACCES:
     144        msg = (char *) "Permission denied";
     145        break;
     146      default:
     147        /* No need to check buffer size, all calls in the dynamic linker
     148  	 provide enough space.  */
     149        buf[buflen - 1] = '\0';
     150        msg = _itoa (errnum, buf + buflen - 1, 10, 0);
     151        msg = memcpy (msg - (sizeof ("Error ") - 1), "Error ",
     152  		    sizeof ("Error ") - 1);
     153        break;
     154      }
     155  
     156    return msg;
     157  }
     158  
     159  void
     160  __libc_fatal (const char *message)
     161  {
     162    _dl_fatal_printf ("%s", message);
     163  }
     164  rtld_hidden_def (__libc_fatal)
     165  
     166  void
     167  __attribute__ ((noreturn))
     168  __chk_fail (void)
     169  {
     170    _exit (127);
     171  }
     172  rtld_hidden_def (__chk_fail)
     173  
     174  #ifndef NDEBUG
     175  /* Define (weakly) our own assert failure function which doesn't use stdio.
     176     If we are linked into the user program (-ldl), the normal __assert_fail
     177     defn can override this one.  */
     178  
     179  void weak_function
     180  __assert_fail (const char *assertion,
     181  	       const char *file, unsigned int line, const char *function)
     182  {
     183    _dl_fatal_printf ("\
     184  Inconsistency detected by ld.so: %s: %u: %s%sAssertion `%s' failed!\n",
     185  		    file, line, function ?: "", function ? ": " : "",
     186  		    assertion);
     187  
     188  }
     189  # ifndef NO_RTLD_HIDDEN
     190  rtld_hidden_weak (__assert_fail)
     191  # endif
     192  
     193  void weak_function
     194  __assert_perror_fail (int errnum,
     195  		      const char *file, unsigned int line,
     196  		      const char *function)
     197  {
     198    char errbuf[400];
     199    _dl_fatal_printf ("\
     200  Inconsistency detected by ld.so: %s: %u: %s%sUnexpected error: %s.\n",
     201  		    file, line, function ?: "", function ? ": " : "",
     202  		    __strerror_r (errnum, errbuf, sizeof errbuf));
     203  
     204  }
     205  # ifndef NO_RTLD_HIDDEN
     206  rtld_hidden_weak (__assert_perror_fail)
     207  # endif
     208  #endif
     209  
     210  #undef _itoa
     211  /* We always use _itoa instead of _itoa_word in ld.so since the former
     212     also has to be present and it is never about speed when these
     213     functions are used.  */
     214  char *
     215  _itoa (unsigned long long int value, char *buflim, unsigned int base,
     216         int upper_case)
     217  {
     218    assert (! upper_case);
     219  
     220    do
     221      *--buflim = _itoa_lower_digits[value % base];
     222    while ((value /= base) != 0);
     223  
     224    return buflim;
     225  }
     226  
     227  /* The '_itoa_lower_digits' variable in libc.so is able to handle bases
     228     up to 36.  We don't need this here.  */
     229  const char _itoa_lower_digits[16] = "0123456789abcdef";
     230  rtld_hidden_data_def (_itoa_lower_digits)
     231  
     232  /* The following is not a complete strsep implementation.  It cannot
     233     handle empty delimiter strings.  But this isn't necessary for the
     234     execution of ld.so.  */
     235  #undef strsep
     236  #undef __strsep
     237  char *
     238  __strsep (char **stringp, const char *delim)
     239  {
     240    char *begin;
     241  
     242    assert (delim[0] != '\0');
     243  
     244    begin = *stringp;
     245    if (begin != NULL)
     246      {
     247        char *end = begin;
     248  
     249        while (*end != '\0' || (end = NULL))
     250  	{
     251  	  const char *dp = delim;
     252  
     253  	  do
     254  	    if (*dp == *end)
     255  	      break;
     256  	  while (*++dp != '\0');
     257  
     258  	  if (*dp != '\0')
     259  	    {
     260  	      *end++ = '\0';
     261  	      break;
     262  	    }
     263  
     264  	  ++end;
     265  	}
     266  
     267        *stringp = end;
     268      }
     269  
     270    return begin;
     271  }
     272  weak_alias (__strsep, strsep)
     273  strong_alias (__strsep, __strsep_g)