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