Update.
[platform/upstream/glibc.git] / elf / dl-minimal.c
1 /* Minimal replacements for basic facilities used in the dynamic linker.
2    Copyright (C) 1995, 1996, 1997, 1998 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 Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    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    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #include <errno.h>
21 #include <limits.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <sys/mman.h>
26 #include <elf/ldsodefs.h>
27 #include <stdio-common/_itoa.h>
28
29 #include <assert.h>
30
31 /* Minimal `malloc' allocator for use while loading shared libraries.
32    No block is ever freed.  */
33
34 static void *alloc_ptr, *alloc_end, *alloc_last_block;
35
36 void * weak_function
37 malloc (size_t n)
38 {
39 #ifdef MAP_ANON
40 #define _dl_zerofd (-1)
41 #else
42   extern int _dl_zerofd;
43
44   if (_dl_zerofd == -1)
45     _dl_zerofd = _dl_sysdep_open_zero_fill ();
46 #define MAP_ANON 0
47 #endif
48
49   if (alloc_end == 0)
50     {
51       /* Consume any unused space in the last page of our data segment.  */
52       extern int _end;
53       alloc_ptr = &_end;
54       alloc_end = (void *) 0 + (((alloc_ptr - (void *) 0) + _dl_pagesize - 1)
55                                 & ~(_dl_pagesize - 1));
56     }
57
58   /* Make sure the allocation pointer is ideally aligned.  */
59   alloc_ptr = (void *) 0 + (((alloc_ptr - (void *) 0) + sizeof (double) - 1)
60                             & ~(sizeof (double) - 1));
61
62   if (alloc_ptr + n >= alloc_end)
63     {
64       /* Insufficient space left; allocate another page.  */
65       caddr_t page;
66       size_t nup = (n + _dl_pagesize - 1) & ~(_dl_pagesize - 1);
67       page = __mmap (0, nup, PROT_READ|PROT_WRITE,
68                      MAP_ANON|MAP_PRIVATE, _dl_zerofd, 0);
69       assert (page != MAP_FAILED);
70       if (page != alloc_end)
71         alloc_ptr = page;
72       alloc_end = page + nup;
73     }
74
75   alloc_last_block = (void *) alloc_ptr;
76   alloc_ptr += n;
77   return alloc_last_block;
78 }
79
80 /* We use this function occasionally since the real implementation may
81    be optimized when it can assume the memory it returns already is
82    set to NUL.  */
83 void * weak_function
84 calloc (size_t nmemb, size_t size)
85 {
86   size_t total = nmemb * size;
87   void *result = malloc (total);
88   return memset (result, '\0', total);
89 }
90
91 /* This will rarely be called.  */
92 void weak_function
93 free (void *ptr)
94 {
95   /* We can free only the last block allocated.  */
96   if (ptr == alloc_last_block)
97     alloc_ptr = alloc_last_block;
98 }
99
100 /* This is only called with the most recent block returned by malloc.  */
101 void * weak_function
102 realloc (void *ptr, size_t n)
103 {
104   void *new;
105   assert (ptr == alloc_last_block);
106   alloc_ptr = alloc_last_block;
107   new = malloc (n);
108   assert (new == ptr);
109   return new;
110 }
111 \f
112 /* Avoid signal frobnication in setjmp/longjmp.  Keeps things smaller.  */
113
114 #include <setjmp.h>
115
116 int weak_function
117 __sigjmp_save (sigjmp_buf env, int savemask)
118 {
119   env[0].__mask_was_saved = savemask;
120   return 0;
121 }
122
123 void weak_function
124 longjmp (jmp_buf env, int val)
125 {
126   __longjmp (env[0].__jmpbuf, val);
127 }
128 \f
129 /* Define our own version of the internal function used by strerror.  We
130    only provide the messages for some common errors.  This avoids pulling
131    in the whole error list.  */
132
133 char * weak_function
134 __strerror_r (int errnum, char *buf, size_t buflen)
135 {
136   char *msg;
137
138   switch (errnum)
139     {
140     case ENOMEM:
141       msg = (char *) "Cannot allocate memory";
142       break;
143     case EINVAL:
144       msg = (char *) "Invalid argument";
145       break;
146     case ENOENT:
147       msg = (char *) "No such file or directory";
148       break;
149     case EPERM:
150       msg = (char *) "Operation not permitted";
151       break;
152     case EIO:
153       msg = (char *) "Input/output error";
154       break;
155     case EACCES:
156       msg = (char *) "Permission denied";
157       break;
158     default:
159       /* No need to check buffer size, all calls in the dynamic linker
160          provide enough space.  */
161       buf[buflen - 1] = '\0';
162       msg = _itoa_word (errnum, buf + buflen - 1, 10, 0);
163       msg = memcpy (msg - (sizeof ("Error ") - 1), "Error ",
164                     sizeof ("Error ") - 1);
165       break;
166     }
167
168   return msg;
169 }
170 \f
171 #ifndef NDEBUG
172
173 /* Define (weakly) our own assert failure function which doesn't use stdio.
174    If we are linked into the user program (-ldl), the normal __assert_fail
175    defn can override this one.  */
176
177 void weak_function
178 __assert_fail (const char *assertion,
179                const char *file, unsigned int line, const char *function)
180 {
181   char buf[64];
182   buf[sizeof buf - 1] = '\0';
183   _dl_sysdep_fatal ("BUG IN DYNAMIC LINKER ld.so: ",
184                     file, ": ", _itoa_word (line, buf + sizeof buf - 1, 10, 0),
185                     ": ", function ?: "", function ? ": " : "",
186                     "Assertion `", assertion, "' failed!\n",
187                     NULL);
188
189 }
190
191 void weak_function
192 __assert_perror_fail (int errnum,
193                       const char *file, unsigned int line,
194                       const char *function)
195 {
196   char errbuf[64];
197   char buf[64];
198   buf[sizeof buf - 1] = '\0';
199   _dl_sysdep_fatal ("BUG IN DYNAMIC LINKER ld.so: ",
200                     file, ": ", _itoa_word (line, buf + sizeof buf - 1, 10, 0),
201                     ": ", function ?: "", function ? ": " : "",
202                     "Unexpected error: ",
203                     __strerror_r (errnum, errbuf, sizeof (errbuf)), "\n",
204                     NULL);
205
206 }
207
208 #endif
209
210 /* This function is only used in eval.c.  */
211 long int weak_function
212 __strtol_internal (const char *nptr, char **endptr, int base, int group)
213 {
214   unsigned long int result = 0;
215   long int sign = 1;
216
217   while (*nptr == ' ' || *nptr == '\t')
218     ++nptr;
219
220   if (*nptr == '-')
221     {
222       sign = -1;
223       ++nptr;
224     }
225   else if (*nptr == '+')
226     ++nptr;
227
228   if (*nptr < '0' || *nptr > '9')
229     {
230       if (endptr != NULL)
231         *endptr = (char *) nptr;
232       return 0L;
233     }
234
235   assert (base == 0);
236   base = 10;
237   if (*nptr == '0')
238     {
239       if (nptr[1] == 'x' || nptr[1] == 'X')
240         {
241           base = 16;
242           nptr += 2;
243         }
244       else
245         base = 8;
246     }
247
248   while (*nptr >= '0' && *nptr <= '9')
249     {
250       unsigned long int digval = *nptr - '0';
251       if (result > LONG_MAX / 10
252           || (sign > 0 ? result == LONG_MAX / 10 && digval > LONG_MAX % 10
253               : (result == ((unsigned long int) LONG_MAX + 1) / 10
254                  && digval > ((unsigned long int) LONG_MAX + 1) % 10)))
255         {
256           errno = ERANGE;
257           return sign > 0 ? LONG_MAX : LONG_MIN;
258         }
259       result *= base;
260       result += digval;
261       ++nptr;
262     }
263
264   return (long int) result * sign;
265 }
266
267 long int weak_function
268 strtol (const char *nptr, char **endptr, int base)
269 {
270   return __strtol_internal (nptr, endptr, base, 0);
271 }
272
273 unsigned long int weak_function
274 __strtoul_internal (const char *nptr, char **endptr, int base, int group)
275 {
276   unsigned long int result = 0;
277   long int sign = 1;
278
279   while (*nptr == ' ' || *nptr == '\t')
280     ++nptr;
281
282   if (*nptr == '-')
283     {
284       sign = -1;
285       ++nptr;
286     }
287   else if (*nptr == '+')
288     ++nptr;
289
290   if (*nptr < '0' || *nptr > '9')
291     {
292       if (endptr != NULL)
293         *endptr = (char *) nptr;
294       return 0UL;
295     }
296
297   assert (base == 0);
298   base = 10;
299   if (*nptr == '0')
300     {
301       if (nptr[1] == 'x' || nptr[1] == 'X')
302         {
303           base = 16;
304           nptr += 2;
305         }
306       else
307         base = 8;
308     }
309
310   while (*nptr >= '0' && *nptr <= '9')
311     {
312       unsigned long int digval = *nptr - '0';
313       if (result > LONG_MAX / 10
314           || (result == ULONG_MAX / 10 && digval > ULONG_MAX % 10))
315         {
316           errno = ERANGE;
317           return ULONG_MAX;
318         }
319       result *= base;
320       result += digval;
321       ++nptr;
322     }
323
324   return result * sign;
325 }
326
327 unsigned long int weak_function
328 strtoul (const char *nptr, char **endptr, int base)
329 {
330   return (unsigned long int) __strtoul_internal (nptr, endptr, base, 0);
331 }