Back to index

glibc  2.9
dl-minimal.c
Go to the documentation of this file.
00001 /* Minimal replacements for basic facilities used in the dynamic linker.
00002    Copyright (C) 1995-1998,2000-2002,2004-2006,2007
00003    Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <errno.h>
00022 #include <limits.h>
00023 #include <string.h>
00024 #include <tls.h>
00025 #include <unistd.h>
00026 #include <sys/mman.h>
00027 #include <sys/param.h>
00028 #include <sys/types.h>
00029 #include <ldsodefs.h>
00030 #include <stdio-common/_itoa.h>
00031 
00032 #include <assert.h>
00033 
00034 /* Minimal `malloc' allocator for use while loading shared libraries.
00035    No block is ever freed.  */
00036 
00037 static void *alloc_ptr, *alloc_end, *alloc_last_block;
00038 
00039 /* Declarations of global functions.  */
00040 extern void weak_function free (void *ptr);
00041 extern void * weak_function realloc (void *ptr, size_t n);
00042 extern unsigned long int weak_function __strtoul_internal (const char *nptr,
00043                                                     char **endptr,
00044                                                     int base,
00045                                                     int group);
00046 extern unsigned long int weak_function strtoul (const char *nptr,
00047                                           char **endptr, int base);
00048 
00049 
00050 /* Allocate an aligned memory block.  */
00051 void * weak_function
00052 __libc_memalign (size_t align, size_t n)
00053 {
00054 #ifdef MAP_ANON
00055 #define       _dl_zerofd (-1)
00056 #else
00057   extern int _dl_zerofd;
00058 
00059   if (_dl_zerofd == -1)
00060     _dl_zerofd = _dl_sysdep_open_zero_fill ();
00061 #define MAP_ANON 0
00062 #endif
00063 
00064   if (alloc_end == 0)
00065     {
00066       /* Consume any unused space in the last page of our data segment.  */
00067       extern int _end attribute_hidden;
00068       alloc_ptr = &_end;
00069       alloc_end = (void *) 0 + (((alloc_ptr - (void *) 0)
00070                              + GLRO(dl_pagesize) - 1)
00071                             & ~(GLRO(dl_pagesize) - 1));
00072     }
00073 
00074   /* Make sure the allocation pointer is ideally aligned.  */
00075   alloc_ptr = (void *) 0 + (((alloc_ptr - (void *) 0) + align - 1)
00076                          & ~(align - 1));
00077 
00078   if (alloc_ptr + n >= alloc_end || n >= -(uintptr_t) alloc_ptr)
00079     {
00080       /* Insufficient space left; allocate another page.  */
00081       caddr_t page;
00082       size_t nup = (n + GLRO(dl_pagesize) - 1) & ~(GLRO(dl_pagesize) - 1);
00083       if (__builtin_expect (nup == 0, 0))
00084        {
00085          if (n)
00086            return NULL;
00087          nup = GLRO(dl_pagesize);
00088        }
00089       page = __mmap (0, nup, PROT_READ|PROT_WRITE,
00090                    MAP_ANON|MAP_PRIVATE, _dl_zerofd, 0);
00091       if (page == MAP_FAILED)
00092        return NULL;
00093       if (page != alloc_end)
00094        alloc_ptr = page;
00095       alloc_end = page + nup;
00096     }
00097 
00098   alloc_last_block = (void *) alloc_ptr;
00099   alloc_ptr += n;
00100   return alloc_last_block;
00101 }
00102 
00103 void * weak_function
00104 malloc (size_t n)
00105 {
00106   return __libc_memalign (sizeof (double), n);
00107 }
00108 
00109 /* We use this function occasionally since the real implementation may
00110    be optimized when it can assume the memory it returns already is
00111    set to NUL.  */
00112 void * weak_function
00113 calloc (size_t nmemb, size_t size)
00114 {
00115   /* New memory from the trivial malloc above is always already cleared.
00116      (We make sure that's true in the rare occasion it might not be,
00117      by clearing memory in free, below.)  */
00118   size_t bytes = nmemb * size;
00119 
00120 #define HALF_SIZE_T (((size_t) 1) << (8 * sizeof (size_t) / 2))
00121   if (__builtin_expect ((nmemb | size) >= HALF_SIZE_T, 0)
00122       && size != 0 && bytes / size != nmemb)
00123     return NULL;
00124 
00125   return malloc (bytes);
00126 }
00127 
00128 /* This will rarely be called.  */
00129 void weak_function
00130 free (void *ptr)
00131 {
00132   /* We can free only the last block allocated.  */
00133   if (ptr == alloc_last_block)
00134     {
00135       /* Since this is rare, we clear the freed block here
00136         so that calloc can presume malloc returns cleared memory.  */
00137       memset (alloc_last_block, '\0', alloc_ptr - alloc_last_block);
00138       alloc_ptr = alloc_last_block;
00139     }
00140 }
00141 
00142 /* This is only called with the most recent block returned by malloc.  */
00143 void * weak_function
00144 realloc (void *ptr, size_t n)
00145 {
00146   if (ptr == NULL)
00147     return malloc (n);
00148   assert (ptr == alloc_last_block);
00149   size_t old_size = alloc_ptr - alloc_last_block;
00150   alloc_ptr = alloc_last_block;
00151   void *new = malloc (n);
00152   return new != ptr ? memcpy (new, ptr, old_size) : new;
00153 }
00154 
00155 /* Avoid signal frobnication in setjmp/longjmp.  Keeps things smaller.  */
00156 
00157 #include <setjmp.h>
00158 
00159 int weak_function
00160 __sigjmp_save (sigjmp_buf env, int savemask __attribute__ ((unused)))
00161 {
00162   env[0].__mask_was_saved = 0;
00163   return 0;
00164 }
00165 
00166 /* Define our own version of the internal function used by strerror.  We
00167    only provide the messages for some common errors.  This avoids pulling
00168    in the whole error list.  */
00169 
00170 char * weak_function
00171 __strerror_r (int errnum, char *buf, size_t buflen)
00172 {
00173   char *msg;
00174 
00175   switch (errnum)
00176     {
00177     case ENOMEM:
00178       msg = (char *) "Cannot allocate memory";
00179       break;
00180     case EINVAL:
00181       msg = (char *) "Invalid argument";
00182       break;
00183     case ENOENT:
00184       msg = (char *) "No such file or directory";
00185       break;
00186     case EPERM:
00187       msg = (char *) "Operation not permitted";
00188       break;
00189     case EIO:
00190       msg = (char *) "Input/output error";
00191       break;
00192     case EACCES:
00193       msg = (char *) "Permission denied";
00194       break;
00195     default:
00196       /* No need to check buffer size, all calls in the dynamic linker
00197         provide enough space.  */
00198       buf[buflen - 1] = '\0';
00199       msg = _itoa (errnum, buf + buflen - 1, 10, 0);
00200       msg = memcpy (msg - (sizeof ("Error ") - 1), "Error ",
00201                   sizeof ("Error ") - 1);
00202       break;
00203     }
00204 
00205   return msg;
00206 }
00207 
00208 #ifndef NDEBUG
00209 
00210 /* Define (weakly) our own assert failure function which doesn't use stdio.
00211    If we are linked into the user program (-ldl), the normal __assert_fail
00212    defn can override this one.  */
00213 
00214 void weak_function
00215 __assert_fail (const char *assertion,
00216               const char *file, unsigned int line, const char *function)
00217 {
00218   _dl_fatal_printf ("\
00219 Inconsistency detected by ld.so: %s: %u: %s%sAssertion `%s' failed!\n",
00220                   file, line, function ?: "", function ? ": " : "",
00221                   assertion);
00222 
00223 }
00224 rtld_hidden_weak(__assert_fail)
00225 
00226 void weak_function
00227 __assert_perror_fail (int errnum,
00228                     const char *file, unsigned int line,
00229                     const char *function)
00230 {
00231   char errbuf[400];
00232   _dl_fatal_printf ("\
00233 Inconsistency detected by ld.so: %s: %u: %s%sUnexpected error: %s.\n",
00234                   file, line, function ?: "", function ? ": " : "",
00235                   __strerror_r (errnum, errbuf, sizeof errbuf));
00236 
00237 }
00238 rtld_hidden_weak (__assert_perror_fail)
00239 #endif
00240 
00241 unsigned long int weak_function
00242 __strtoul_internal (const char *nptr, char **endptr, int base, int group)
00243 {
00244   unsigned long int result = 0;
00245   long int sign = 1;
00246 
00247   while (*nptr == ' ' || *nptr == '\t')
00248     ++nptr;
00249 
00250   if (*nptr == '-')
00251     {
00252       sign = -1;
00253       ++nptr;
00254     }
00255   else if (*nptr == '+')
00256     ++nptr;
00257 
00258   if (*nptr < '0' || *nptr > '9')
00259     {
00260       if (endptr != NULL)
00261        *endptr = (char *) nptr;
00262       return 0UL;
00263     }
00264 
00265   assert (base == 0);
00266   base = 10;
00267   if (*nptr == '0')
00268     {
00269       if (nptr[1] == 'x' || nptr[1] == 'X')
00270        {
00271          base = 16;
00272          nptr += 2;
00273        }
00274       else
00275        base = 8;
00276     }
00277 
00278   while (*nptr >= '0' && *nptr <= '9')
00279     {
00280       unsigned long int digval = *nptr - '0';
00281       if (result > ULONG_MAX / 10
00282          || (result == ULONG_MAX / 10 && digval > ULONG_MAX % 10))
00283        {
00284          errno = ERANGE;
00285          if (endptr != NULL)
00286            *endptr = (char *) nptr;
00287          return ULONG_MAX;
00288        }
00289       result *= base;
00290       result += digval;
00291       ++nptr;
00292     }
00293 
00294   if (endptr != NULL)
00295     *endptr = (char *) nptr;
00296   return result * sign;
00297 }
00298 
00299 
00300 #undef _itoa
00301 /* We always use _itoa instead of _itoa_word in ld.so since the former
00302    also has to be present and it is never about speed when these
00303    functions are used.  */
00304 char *
00305 _itoa (value, buflim, base, upper_case)
00306      unsigned long long int value;
00307      char *buflim;
00308      unsigned int base;
00309      int upper_case;
00310 {
00311   extern const char INTUSE(_itoa_lower_digits)[] attribute_hidden;
00312 
00313   assert (! upper_case);
00314 
00315   do
00316     *--buflim = INTUSE(_itoa_lower_digits)[value % base];
00317   while ((value /= base) != 0);
00318 
00319   return buflim;
00320 }
00321 
00322 
00323 /* The following is not a complete strsep implementation.  It cannot
00324    handle empty delimiter strings.  But this isn't necessary for the
00325    execution of ld.so.  */
00326 #undef strsep
00327 #undef __strsep
00328 char *
00329 __strsep (char **stringp, const char *delim)
00330 {
00331   char *begin;
00332 
00333   assert (delim[0] != '\0');
00334 
00335   begin = *stringp;
00336   if (begin != NULL)
00337     {
00338       char *end = begin;
00339 
00340       while (*end != '\0' || (end = NULL))
00341        {
00342          const char *dp = delim;
00343 
00344          do
00345            if (*dp == *end)
00346              break;
00347          while (*++dp != '\0');
00348 
00349          if (*dp != '\0')
00350            {
00351              *end++ = '\0';
00352              break;
00353            }
00354 
00355          ++end;
00356        }
00357 
00358       *stringp = end;
00359     }
00360 
00361   return begin;
00362 }
00363 weak_alias (__strsep, strsep)
00364 strong_alias (__strsep, __strsep_g)
00365 
00366 void
00367 __attribute__ ((noreturn))
00368 __chk_fail (void)
00369 {
00370   _exit (127);
00371 }
00372 rtld_hidden_def (__chk_fail)
00373 
00374 /* The '_itoa_lower_digits' variable in libc.so is able to handle bases
00375    up to 36.  We don't need this here.  */
00376 const char INTUSE(_itoa_lower_digits)[16] attribute_hidden
00377   = "0123456789abcdef";