Blame elf/dl-minimal.c

Packit Service 82fcde
/* Minimal replacements for basic facilities used in the dynamic linker.
Packit Service 82fcde
   Copyright (C) 1995-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <limits.h>
Packit Service 82fcde
#include <stdio.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
#include <tls.h>
Packit Service 82fcde
#include <unistd.h>
Packit Service 82fcde
#include <sys/mman.h>
Packit Service 82fcde
#include <sys/param.h>
Packit Service 82fcde
#include <sys/types.h>
Packit Service 82fcde
#include <ldsodefs.h>
Packit Service 82fcde
#include <_itoa.h>
Packit Service 82fcde
#include <malloc/malloc-internal.h>
Packit Service 82fcde
Packit Service 82fcde
#include <assert.h>
Packit Service 82fcde
Packit Service 82fcde
/* Minimal malloc allocator for used during initial link.  After the
Packit Service 82fcde
   initial link, a full malloc implementation is interposed, either
Packit Service 82fcde
   the one in libc, or a different one supplied by the user through
Packit Service 82fcde
   interposition.  */
Packit Service 82fcde
Packit Service 82fcde
static void *alloc_ptr, *alloc_end, *alloc_last_block;
Packit Service 82fcde
Packit Service 82fcde
/* Declarations of global functions.  */
Packit Service 82fcde
extern void weak_function free (void *ptr);
Packit Service 82fcde
extern void * weak_function realloc (void *ptr, size_t n);
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Allocate an aligned memory block.  */
Packit Service 82fcde
void * weak_function
Packit Service 82fcde
malloc (size_t n)
Packit Service 82fcde
{
Packit Service 82fcde
  if (alloc_end == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Consume any unused space in the last page of our data segment.  */
Packit Service 82fcde
      extern int _end attribute_hidden;
Packit Service 82fcde
      alloc_ptr = &_end;
Packit Service 82fcde
      alloc_end = (void *) 0 + (((alloc_ptr - (void *) 0)
Packit Service 82fcde
				 + GLRO(dl_pagesize) - 1)
Packit Service 82fcde
				& ~(GLRO(dl_pagesize) - 1));
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Make sure the allocation pointer is ideally aligned.  */
Packit Service 82fcde
  alloc_ptr = (void *) 0 + (((alloc_ptr - (void *) 0) + MALLOC_ALIGNMENT - 1)
Packit Service 82fcde
			    & ~(MALLOC_ALIGNMENT - 1));
Packit Service 82fcde
Packit Service 82fcde
  if (alloc_ptr + n >= alloc_end || n >= -(uintptr_t) alloc_ptr)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Insufficient space left; allocate another page plus one extra
Packit Service 82fcde
	 page to reduce number of mmap calls.  */
Packit Service 82fcde
      caddr_t page;
Packit Service 82fcde
      size_t nup = (n + GLRO(dl_pagesize) - 1) & ~(GLRO(dl_pagesize) - 1);
Packit Service 82fcde
      if (__glibc_unlikely (nup == 0 && n != 0))
Packit Service 82fcde
	return NULL;
Packit Service 82fcde
      nup += GLRO(dl_pagesize);
Packit Service 82fcde
      page = __mmap (0, nup, PROT_READ|PROT_WRITE,
Packit Service 82fcde
		     MAP_ANON|MAP_PRIVATE, -1, 0);
Packit Service 82fcde
      if (page == MAP_FAILED)
Packit Service 82fcde
	return NULL;
Packit Service 82fcde
      if (page != alloc_end)
Packit Service 82fcde
	alloc_ptr = page;
Packit Service 82fcde
      alloc_end = page + nup;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  alloc_last_block = (void *) alloc_ptr;
Packit Service 82fcde
  alloc_ptr += n;
Packit Service 82fcde
  return alloc_last_block;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* We use this function occasionally since the real implementation may
Packit Service 82fcde
   be optimized when it can assume the memory it returns already is
Packit Service 82fcde
   set to NUL.  */
Packit Service 82fcde
void * weak_function
Packit Service 82fcde
calloc (size_t nmemb, size_t size)
Packit Service 82fcde
{
Packit Service 82fcde
  /* New memory from the trivial malloc above is always already cleared.
Packit Service 82fcde
     (We make sure that's true in the rare occasion it might not be,
Packit Service 82fcde
     by clearing memory in free, below.)  */
Packit Service 82fcde
  size_t bytes = nmemb * size;
Packit Service 82fcde
Packit Service 82fcde
#define HALF_SIZE_T (((size_t) 1) << (8 * sizeof (size_t) / 2))
Packit Service 82fcde
  if (__builtin_expect ((nmemb | size) >= HALF_SIZE_T, 0)
Packit Service 82fcde
      && size != 0 && bytes / size != nmemb)
Packit Service 82fcde
    return NULL;
Packit Service 82fcde
Packit Service 82fcde
  return malloc (bytes);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* This will rarely be called.  */
Packit Service 82fcde
void weak_function
Packit Service 82fcde
free (void *ptr)
Packit Service 82fcde
{
Packit Service 82fcde
  /* We can free only the last block allocated.  */
Packit Service 82fcde
  if (ptr == alloc_last_block)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Since this is rare, we clear the freed block here
Packit Service 82fcde
	 so that calloc can presume malloc returns cleared memory.  */
Packit Service 82fcde
      memset (alloc_last_block, '\0', alloc_ptr - alloc_last_block);
Packit Service 82fcde
      alloc_ptr = alloc_last_block;
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* This is only called with the most recent block returned by malloc.  */
Packit Service 82fcde
void * weak_function
Packit Service 82fcde
realloc (void *ptr, size_t n)
Packit Service 82fcde
{
Packit Service 82fcde
  if (ptr == NULL)
Packit Service 82fcde
    return malloc (n);
Packit Service 82fcde
  assert (ptr == alloc_last_block);
Packit Service 82fcde
  size_t old_size = alloc_ptr - alloc_last_block;
Packit Service 82fcde
  alloc_ptr = alloc_last_block;
Packit Service 82fcde
  void *new = malloc (n);
Packit Service 82fcde
  return new != ptr ? memcpy (new, ptr, old_size) : new;
Packit Service 82fcde
}
Packit Service 82fcde

Packit Service 82fcde
/* Avoid signal frobnication in setjmp/longjmp.  Keeps things smaller.  */
Packit Service 82fcde
Packit Service 82fcde
#include <setjmp.h>
Packit Service 82fcde
Packit Service 82fcde
int weak_function
Packit Service 82fcde
__sigjmp_save (sigjmp_buf env, int savemask __attribute__ ((unused)))
Packit Service 82fcde
{
Packit Service 82fcde
  env[0].__mask_was_saved = 0;
Packit Service 82fcde
  return 0;
Packit Service 82fcde
}
Packit Service 82fcde

Packit Service 82fcde
/* Define our own version of the internal function used by strerror.  We
Packit Service 82fcde
   only provide the messages for some common errors.  This avoids pulling
Packit Service 82fcde
   in the whole error list.  */
Packit Service 82fcde
Packit Service 82fcde
char * weak_function
Packit Service 82fcde
__strerror_r (int errnum, char *buf, size_t buflen)
Packit Service 82fcde
{
Packit Service 82fcde
  char *msg;
Packit Service 82fcde
Packit Service 82fcde
  switch (errnum)
Packit Service 82fcde
    {
Packit Service 82fcde
    case ENOMEM:
Packit Service 82fcde
      msg = (char *) "Cannot allocate memory";
Packit Service 82fcde
      break;
Packit Service 82fcde
    case EINVAL:
Packit Service 82fcde
      msg = (char *) "Invalid argument";
Packit Service 82fcde
      break;
Packit Service 82fcde
    case ENOENT:
Packit Service 82fcde
      msg = (char *) "No such file or directory";
Packit Service 82fcde
      break;
Packit Service 82fcde
    case EPERM:
Packit Service 82fcde
      msg = (char *) "Operation not permitted";
Packit Service 82fcde
      break;
Packit Service 82fcde
    case EIO:
Packit Service 82fcde
      msg = (char *) "Input/output error";
Packit Service 82fcde
      break;
Packit Service 82fcde
    case EACCES:
Packit Service 82fcde
      msg = (char *) "Permission denied";
Packit Service 82fcde
      break;
Packit Service 82fcde
    default:
Packit Service 82fcde
      /* No need to check buffer size, all calls in the dynamic linker
Packit Service 82fcde
	 provide enough space.  */
Packit Service 82fcde
      buf[buflen - 1] = '\0';
Packit Service 82fcde
      msg = _itoa (errnum, buf + buflen - 1, 10, 0);
Packit Service 82fcde
      msg = memcpy (msg - (sizeof ("Error ") - 1), "Error ",
Packit Service 82fcde
		    sizeof ("Error ") - 1);
Packit Service 82fcde
      break;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return msg;
Packit Service 82fcde
}
Packit Service 82fcde

Packit Service 82fcde
void
Packit Service 82fcde
__libc_fatal (const char *message)
Packit Service 82fcde
{
Packit Service 82fcde
  _dl_fatal_printf ("%s", message);
Packit Service 82fcde
}
Packit Service 82fcde
rtld_hidden_def (__libc_fatal)
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
__attribute__ ((noreturn))
Packit Service 82fcde
__chk_fail (void)
Packit Service 82fcde
{
Packit Service 82fcde
  _exit (127);
Packit Service 82fcde
}
Packit Service 82fcde
rtld_hidden_def (__chk_fail)
Packit Service 82fcde
Packit Service 82fcde
#ifndef NDEBUG
Packit Service 82fcde
/* Define (weakly) our own assert failure function which doesn't use stdio.
Packit Service 82fcde
   If we are linked into the user program (-ldl), the normal __assert_fail
Packit Service 82fcde
   defn can override this one.  */
Packit Service 82fcde
Packit Service 82fcde
void weak_function
Packit Service 82fcde
__assert_fail (const char *assertion,
Packit Service 82fcde
	       const char *file, unsigned int line, const char *function)
Packit Service 82fcde
{
Packit Service 82fcde
  _dl_fatal_printf ("\
Packit Service 82fcde
Inconsistency detected by ld.so: %s: %u: %s%sAssertion `%s' failed!\n",
Packit Service 82fcde
		    file, line, function ?: "", function ? ": " : "",
Packit Service 82fcde
		    assertion);
Packit Service 82fcde
Packit Service 82fcde
}
Packit Service 82fcde
rtld_hidden_weak (__assert_fail)
Packit Service 82fcde
Packit Service 82fcde
void weak_function
Packit Service 82fcde
__assert_perror_fail (int errnum,
Packit Service 82fcde
		      const char *file, unsigned int line,
Packit Service 82fcde
		      const char *function)
Packit Service 82fcde
{
Packit Service 82fcde
  char errbuf[400];
Packit Service 82fcde
  _dl_fatal_printf ("\
Packit Service 82fcde
Inconsistency detected by ld.so: %s: %u: %s%sUnexpected error: %s.\n",
Packit Service 82fcde
		    file, line, function ?: "", function ? ": " : "",
Packit Service 82fcde
		    __strerror_r (errnum, errbuf, sizeof errbuf));
Packit Service 82fcde
Packit Service 82fcde
}
Packit Service 82fcde
rtld_hidden_weak (__assert_perror_fail)
Packit Service 82fcde
#endif
Packit Service 82fcde

Packit Service 82fcde
#undef _itoa
Packit Service 82fcde
/* We always use _itoa instead of _itoa_word in ld.so since the former
Packit Service 82fcde
   also has to be present and it is never about speed when these
Packit Service 82fcde
   functions are used.  */
Packit Service 82fcde
char *
Packit Service 82fcde
_itoa (unsigned long long int value, char *buflim, unsigned int base,
Packit Service 82fcde
       int upper_case)
Packit Service 82fcde
{
Packit Service 82fcde
  assert (! upper_case);
Packit Service 82fcde
Packit Service 82fcde
  do
Packit Service 82fcde
    *--buflim = _itoa_lower_digits[value % base];
Packit Service 82fcde
  while ((value /= base) != 0);
Packit Service 82fcde
Packit Service 82fcde
  return buflim;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* The '_itoa_lower_digits' variable in libc.so is able to handle bases
Packit Service 82fcde
   up to 36.  We don't need this here.  */
Packit Service 82fcde
const char _itoa_lower_digits[16] = "0123456789abcdef";
Packit Service 82fcde
rtld_hidden_data_def (_itoa_lower_digits)
Packit Service 82fcde

Packit Service 82fcde
/* The following is not a complete strsep implementation.  It cannot
Packit Service 82fcde
   handle empty delimiter strings.  But this isn't necessary for the
Packit Service 82fcde
   execution of ld.so.  */
Packit Service 82fcde
#undef strsep
Packit Service 82fcde
#undef __strsep
Packit Service 82fcde
char *
Packit Service 82fcde
__strsep (char **stringp, const char *delim)
Packit Service 82fcde
{
Packit Service 82fcde
  char *begin;
Packit Service 82fcde
Packit Service 82fcde
  assert (delim[0] != '\0');
Packit Service 82fcde
Packit Service 82fcde
  begin = *stringp;
Packit Service 82fcde
  if (begin != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      char *end = begin;
Packit Service 82fcde
Packit Service 82fcde
      while (*end != '\0' || (end = NULL))
Packit Service 82fcde
	{
Packit Service 82fcde
	  const char *dp = delim;
Packit Service 82fcde
Packit Service 82fcde
	  do
Packit Service 82fcde
	    if (*dp == *end)
Packit Service 82fcde
	      break;
Packit Service 82fcde
	  while (*++dp != '\0');
Packit Service 82fcde
Packit Service 82fcde
	  if (*dp != '\0')
Packit Service 82fcde
	    {
Packit Service 82fcde
	      *end++ = '\0';
Packit Service 82fcde
	      break;
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  ++end;
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      *stringp = end;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return begin;
Packit Service 82fcde
}
Packit Service 82fcde
weak_alias (__strsep, strsep)
Packit Service 82fcde
strong_alias (__strsep, __strsep_g)