]> git.ipfire.org Git - thirdparty/glibc.git/blob - elf/dl-minimal.c
Update.
[thirdparty/glibc.git] / elf / dl-minimal.c
1 /* Minimal replacements for basic facilities used in the dynamic linker.
2 Copyright (C) 1995,96,97,98,2000 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 <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 /* Declarations of global functions. */
37 extern void weak_function free (void *ptr);
38 extern void * weak_function realloc (void *ptr, size_t n);
39 extern long int weak_function __strtol_internal (const char *nptr,
40 char **endptr,
41 int base, int group);
42 extern long int weak_function strtol (const char *nptr, char **endptr,
43 int base);
44 extern unsigned long int weak_function __strtoul_internal
45 (const char *nptr, char **endptr, int base, int group);
46 extern unsigned long int weak_function strtoul (const char *nptr,
47 char **endptr, int base);
48
49
50 void * weak_function
51 malloc (size_t n)
52 {
53 #ifdef MAP_ANON
54 #define _dl_zerofd (-1)
55 #else
56 extern int _dl_zerofd;
57
58 if (_dl_zerofd == -1)
59 _dl_zerofd = _dl_sysdep_open_zero_fill ();
60 #define MAP_ANON 0
61 #endif
62
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;
68 alloc_end = (void *) 0 + (((alloc_ptr - (void *) 0) + _dl_pagesize - 1)
69 & ~(_dl_pagesize - 1));
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;
80 size_t nup = (n + _dl_pagesize - 1) & ~(_dl_pagesize - 1);
81 page = __mmap (0, nup, PROT_READ|PROT_WRITE,
82 MAP_ANON|MAP_PRIVATE, _dl_zerofd, 0);
83 assert (page != MAP_FAILED);
84 if (page != alloc_end)
85 alloc_ptr = page;
86 alloc_end = page + nup;
87 }
88
89 alloc_last_block = (void *) alloc_ptr;
90 alloc_ptr += n;
91 return alloc_last_block;
92 }
93
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. */
97 void * weak_function
98 calloc (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
105 /* This will rarely be called. */
106 void weak_function
107 free (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 }
113
114 /* This is only called with the most recent block returned by malloc. */
115 void * weak_function
116 realloc (void *ptr, size_t n)
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 }
125 \f
126 /* Avoid signal frobnication in setjmp/longjmp. Keeps things smaller. */
127
128 #include <setjmp.h>
129
130 int weak_function
131 __sigjmp_save (sigjmp_buf env, int savemask)
132 {
133 env[0].__mask_was_saved = savemask;
134 return 0;
135 }
136
137 void weak_function
138 longjmp (jmp_buf env, int val)
139 {
140 __longjmp (env[0].__jmpbuf, val);
141 }
142 \f
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. */
146
147 char * weak_function
148 __strerror_r (int errnum, char *buf, size_t buflen)
149 {
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;
183 }
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
191 void weak_function
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: ",
198 file, ": ", _itoa_word (line, buf + sizeof buf - 1, 10, 0),
199 ": ", function ?: "", function ? ": " : "",
200 "Assertion `", assertion, "' failed!\n",
201 NULL);
202
203 }
204
205 void weak_function
206 __assert_perror_fail (int errnum,
207 const char *file, unsigned int line,
208 const char *function)
209 {
210 char errbuf[64];
211 char buf[64];
212 buf[sizeof buf - 1] = '\0';
213 _dl_sysdep_fatal ("BUG IN DYNAMIC LINKER ld.so: ",
214 file, ": ", _itoa_word (line, buf + sizeof buf - 1, 10, 0),
215 ": ", function ?: "", function ? ": " : "",
216 "Unexpected error: ",
217 __strerror_r (errnum, errbuf, sizeof (errbuf)), "\n",
218 NULL);
219
220 }
221
222 #endif
223
224 /* This function is only used in eval.c. */
225 long int weak_function
226 __strtol_internal (const char *nptr, char **endptr, int base, int group)
227 {
228 unsigned long int result = 0;
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);
250 base = 10;
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 }
261
262 while (*nptr >= '0' && *nptr <= '9')
263 {
264 unsigned long int digval = *nptr - '0';
265 if (result > LONG_MAX / 10
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)))
269 {
270 errno = ERANGE;
271 return sign > 0 ? LONG_MAX : LONG_MIN;
272 }
273 result *= base;
274 result += digval;
275 ++nptr;
276 }
277
278 return (long int) result * sign;
279 }
280
281 long int weak_function
282 strtol (const char *nptr, char **endptr, int base)
283 {
284 return __strtol_internal (nptr, endptr, base, 0);
285 }
286
287 unsigned long int weak_function
288 __strtoul_internal (const char *nptr, char **endptr, int base, int group)
289 {
290 unsigned long int result = 0;
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);
312 base = 10;
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 }
323
324 while (*nptr >= '0' && *nptr <= '9')
325 {
326 unsigned long int digval = *nptr - '0';
327 if (result > LONG_MAX / 10
328 || (result == ULONG_MAX / 10 && digval > ULONG_MAX % 10))
329 {
330 errno = ERANGE;
331 return ULONG_MAX;
332 }
333 result *= base;
334 result += digval;
335 ++nptr;
336 }
337
338 return result * sign;
339 }
340
341 unsigned long int weak_function
342 strtoul (const char *nptr, char **endptr, int base)
343 {
344 return (unsigned long int) __strtoul_internal (nptr, endptr, base, 0);
345 }