Update.
[glibc.git] / sysdeps / generic / dl-sysdep.c
blob8d182be9e93d408a3496103e81a7fda7877c9ee8
1 /* Operating system support for run-time dynamic linker. Generic Unix version.
2 Copyright (C) 1995,1996,1997,1998,2000,2001 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
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 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
20 #include <assert.h>
21 #include <elf.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <libintl.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/mman.h>
31 #include <ldsodefs.h>
32 #include <stdio-common/_itoa.h>
33 #include <fpu_control.h>
35 #include <entry.h>
36 #include <dl-machine.h>
37 #include <dl-procinfo.h>
38 #include <dl-osinfo.h>
39 #include <hp-timing.h>
41 extern int _dl_argc;
42 extern char **_dl_argv;
43 extern char **_environ;
44 extern size_t _dl_pagesize;
45 extern int _dl_clktck;
46 extern const char *_dl_platform;
47 extern unsigned long int _dl_hwcap;
48 extern size_t _dl_platformlen;
49 extern fpu_control_t _dl_fpu_control;
50 extern void _end;
52 /* Protect SUID program against misuse of file descriptors. */
53 extern void __libc_check_standard_fds (void);
55 #ifdef NEED_DL_BASE_ADDR
56 ElfW(Addr) _dl_base_addr;
57 #endif
58 int __libc_enable_secure;
59 int __libc_multiple_libcs = 0; /* Defining this here avoids the inclusion
60 of init-first. */
61 /* This variable contains the lowest stack address ever used. */
62 void *__libc_stack_end;
63 static ElfW(auxv_t) *_dl_auxv;
64 unsigned long int _dl_hwcap_mask = HWCAP_IMPORTANT;
65 #if HP_TIMING_AVAIL
66 hp_timing_t _dl_cpuclock_offset;
67 #endif
69 #ifndef DL_FIND_ARG_COMPONENTS
70 # define DL_FIND_ARG_COMPONENTS(cookie, argc, argv, envp, auxp) \
71 do { \
72 void **_tmp; \
73 (argc) = *(long int *) cookie; \
74 (argv) = (char **) ((long int *) cookie + 1); \
75 (envp) = (argv) + (argc) + 1; \
76 for (_tmp = (void **) (envp); *_tmp; ++_tmp) \
77 continue; \
78 (auxp) = (void *) ++_tmp; \
79 } while (0)
80 #endif
83 ElfW(Addr)
84 _dl_sysdep_start (void **start_argptr,
85 void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phnum,
86 ElfW(Addr) *user_entry))
88 const ElfW(Phdr) *phdr = NULL;
89 ElfW(Word) phnum = 0;
90 ElfW(Addr) user_entry;
91 ElfW(auxv_t) *av;
92 uid_t uid = 0;
93 uid_t euid = 0;
94 gid_t gid = 0;
95 gid_t egid = 0;
96 #ifdef HAVE_AUX_XID
97 # define set_seen(tag) (tag) /* Evaluate for the side effects. */
98 #else
99 unsigned int seen = 0;
100 # define M(type) (1 << (type))
101 # define set_seen(tag) seen |= M ((tag)->a_type)
102 #endif
104 #if HP_TIMING_AVAIL
105 HP_TIMING_NOW (_dl_cpuclock_offset);
106 #endif
108 DL_FIND_ARG_COMPONENTS (start_argptr, _dl_argc, _dl_argv, _environ,
109 _dl_auxv);
111 user_entry = (ElfW(Addr)) ENTRY_POINT;
112 _dl_platform = NULL; /* Default to nothing known about the platform. */
114 for (av = _dl_auxv; av->a_type != AT_NULL; set_seen (av++))
115 switch (av->a_type)
117 case AT_PHDR:
118 phdr = av->a_un.a_ptr;
119 break;
120 case AT_PHNUM:
121 phnum = av->a_un.a_val;
122 break;
123 case AT_PAGESZ:
124 _dl_pagesize = av->a_un.a_val;
125 break;
126 case AT_ENTRY:
127 user_entry = av->a_un.a_val;
128 break;
129 #ifdef NEED_DL_BASE_ADDR
130 case AT_BASE:
131 _dl_base_addr = av->a_un.a_val;
132 break;
133 #endif
134 case AT_UID:
135 uid = av->a_un.a_val;
136 break;
137 case AT_GID:
138 gid = av->a_un.a_val;
139 break;
140 case AT_EUID:
141 euid = av->a_un.a_val;
142 break;
143 case AT_EGID:
144 egid = av->a_un.a_val;
145 break;
146 case AT_PLATFORM:
147 _dl_platform = av->a_un.a_ptr;
148 break;
149 case AT_HWCAP:
150 _dl_hwcap = av->a_un.a_val;
151 break;
152 case AT_CLKTCK:
153 _dl_clktck = av->a_un.a_val;
154 break;
155 case AT_FPUCW:
156 _dl_fpu_control = av->a_un.a_val;
157 break;
160 #ifdef DL_SYSDEP_OSCHECK
161 DL_SYSDEP_OSCHECK (dl_fatal);
162 #endif
164 /* Linux doesn't provide us with any of these values on the stack
165 when the dynamic linker is run directly as a program. */
167 #ifndef HAVE_AUX_XID
168 # define SEE(UID, uid) if ((seen & M (AT_##UID)) == 0) uid = __get##uid ()
169 SEE (UID, uid);
170 SEE (GID, gid);
171 SEE (EUID, euid);
172 SEE (EGID, egid);
173 #endif
175 __libc_enable_secure = uid != euid || gid != egid;
177 #ifndef HAVE_AUX_PAGESIZE
178 if (_dl_pagesize == 0)
179 _dl_pagesize = __getpagesize ();
180 #endif
182 #ifdef DL_SYSDEP_INIT
183 DL_SYSDEP_INIT;
184 #endif
186 #ifdef DL_PLATFORM_INIT
187 DL_PLATFORM_INIT;
188 #endif
190 /* Determine the length of the platform name. */
191 if (_dl_platform != NULL)
192 _dl_platformlen = strlen (_dl_platform);
194 if (__sbrk (0) == &_end)
195 /* The dynamic linker was run as a program, and so the initial break
196 starts just after our bss, at &_end. The malloc in dl-minimal.c
197 will consume the rest of this page, so tell the kernel to move the
198 break up that far. When the user program examines its break, it
199 will see this new value and not clobber our data. */
200 __sbrk (_dl_pagesize - ((&_end - (void *) 0) & (_dl_pagesize - 1)));
202 /* If this is a SUID program we make sure that FDs 0, 1, and 2 are
203 allocated. If necessary we are doing it ourself. If it is not
204 possible we stop the program. */
205 if (__builtin_expect (__libc_enable_secure, 0))
206 __libc_check_standard_fds ();
208 (*dl_main) (phdr, phnum, &user_entry);
209 return user_entry;
212 void
213 internal_function
214 _dl_sysdep_start_cleanup (void)
218 void
219 internal_function
220 _dl_show_auxv (void)
222 char buf[64];
223 ElfW(auxv_t) *av;
225 /* Terminate string. */
226 buf[63] = '\0';
228 /* The following code assumes that the AT_* values are encoded
229 starting from 0 with AT_NULL, 1 for AT_IGNORE, and all other values
230 close by (otherwise the array will be too large). In case we have
231 to support a platform where these requirements are not fulfilled
232 some alternative implementation has to be used. */
233 for (av = _dl_auxv; av->a_type != AT_NULL; ++av)
235 static const struct
237 const char label[20];
238 enum { dec, hex, str } form;
239 } auxvars[] =
241 [AT_EXECFD - 2] = { "AT_EXECFD: ", dec },
242 [AT_PHDR - 2] = { "AT_PHDR: 0x", hex },
243 [AT_PHENT - 2] = { "AT_PHENT: ", dec },
244 [AT_PHNUM - 2] = { "AT_PHNUM: ", dec },
245 [AT_PAGESZ - 2] = { "AT_PAGESZ: ", dec },
246 [AT_BASE - 2] = { "AT_BASE: 0x", hex },
247 [AT_FLAGS - 2] = { "AT_FLAGS: 0x", hex },
248 [AT_ENTRY - 2] = { "AT_ENTRY: 0x", hex },
249 [AT_NOTELF - 2] = { "AT_NOTELF: ", hex },
250 [AT_UID - 2] = { "AT_UID: ", dec },
251 [AT_EUID - 2] = { "AT_EUID: ", dec },
252 [AT_GID - 2] = { "AT_GID: ", dec },
253 [AT_EGID - 2] = { "AT_EGID: ", dec },
254 [AT_PLATFORM - 2] = { "AT_PLATFORM: ", str },
255 [AT_HWCAP - 2] = { "AT_HWCAP: ", hex },
256 [AT_CLKTCK - 2] = { "AT_CLKTCK: ", dec },
257 [AT_FPUCW - 2] = { "AT_FPUCW: ", hex },
258 [AT_DCACHEBSIZE - 2] = { "AT_DCACHEBSIZE: 0x", hex },
259 [AT_ICACHEBSIZE - 2] = { "AT_ICACHEBSIZE: 0x", hex },
260 [AT_UCACHEBSIZE - 2] = { "AT_UCACHEBSIZE: 0x", hex }
262 unsigned int idx = (unsigned int) (av->a_type - 2);
264 assert (AT_NULL == 0);
265 assert (AT_IGNORE == 1);
266 if (idx < sizeof (auxvars) / sizeof (auxvars[0]))
268 if (av->a_type != AT_HWCAP || _dl_procinfo (av->a_un.a_val) < 0)
270 const char *val = av->a_un.a_ptr;
272 if (__builtin_expect (auxvars[idx].form, dec) == dec)
273 val = _itoa_word (av->a_un.a_val, buf + sizeof buf - 1, 10, 0);
274 else if (__builtin_expect (auxvars[idx].form, hex) == hex)
275 val = _itoa_word (av->a_un.a_val, buf + sizeof buf - 1, 16, 0);
277 _dl_printf ("%s%s\n", auxvars[idx].label, val);
284 /* Return an array of useful/necessary hardware capability names. */
285 const struct r_strlenpair *
286 internal_function
287 _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
288 size_t *max_capstrlen)
290 /* Determine how many important bits are set. */
291 unsigned long int masked = _dl_hwcap & _dl_hwcap_mask;
292 size_t cnt = platform != NULL;
293 size_t n, m;
294 size_t total;
295 struct r_strlenpair *temp;
296 struct r_strlenpair *result;
297 struct r_strlenpair *rp;
298 char *cp;
300 /* Count the number of bits set in the masked value. */
301 for (n = 0; (~((1UL << n) - 1) & masked) != 0; ++n)
302 if ((masked & (1UL << n)) != 0)
303 ++cnt;
305 if (cnt == 0)
307 /* If we have platform name and no important capability we only have
308 the base directory to search. */
309 result = (struct r_strlenpair *) malloc (sizeof (*result));
310 if (result == NULL)
312 no_memory:
313 _dl_signal_error (ENOMEM, NULL, NULL,
314 N_("cannot create capability list"));
317 result[0].str = (char *) result; /* Does not really matter. */
318 result[0].len = 0;
320 *sz = 1;
321 return result;
324 /* Create temporary data structure to generate result table. */
325 temp = (struct r_strlenpair *) alloca (cnt * sizeof (*temp));
326 m = 0;
327 for (n = 0; masked != 0; ++n)
328 if ((masked & (1UL << n)) != 0)
330 temp[m].str = _dl_hwcap_string (n);
331 temp[m].len = strlen (temp[m].str);
332 masked ^= 1UL << n;
333 ++m;
335 if (platform != NULL)
337 temp[m].str = platform;
338 temp[m].len = platform_len;
339 ++m;
342 /* Determine the total size of all strings together. */
343 if (cnt == 1)
344 total = temp[0].len;
345 else
347 total = (1 << (cnt - 2)) * (temp[0].len + temp[cnt - 1].len + 2);
348 for (n = 1; n + 1 < cnt; ++n)
349 total += (1 << (cnt - 3)) * (temp[n].len + 1);
352 /* The result structure: we use a very compressed way to store the
353 various combinations of capability names. */
354 *sz = 1 << cnt;
355 result = (struct r_strlenpair *) malloc (*sz * sizeof (*result) + total);
356 if (result == NULL)
357 goto no_memory;
359 if (cnt == 1)
361 result[0].str = (char *) (result + *sz);
362 result[0].len = temp[0].len + 1;
363 result[1].str = (char *) (result + *sz);
364 result[1].len = 0;
365 cp = __mempcpy ((char *) (result + *sz), temp[0].str, temp[0].len);
366 *cp = '/';
367 *sz = 2;
368 *max_capstrlen = result[0].len;
370 return result;
373 /* Fill in the information. This follows the following scheme
374 (indeces from TEMP for four strings):
375 entry #0: 0, 1, 2, 3 binary: 1111
376 #1: 0, 1, 3 1101
377 #2: 0, 2, 3 1011
378 #3: 0, 3 1001
379 This allows the representation of all possible combinations of
380 capability names in the string. First generate the strings. */
381 result[1].str = result[0].str = cp = (char *) (result + *sz);
382 #define add(idx) \
383 cp = __mempcpy (__mempcpy (cp, temp[idx].str, temp[idx].len), "/", 1);
384 if (cnt == 2)
386 add (1);
387 add (0);
389 else
391 n = 1 << cnt;
394 n -= 2;
396 /* We always add the last string. */
397 add (cnt - 1);
399 /* Add the strings which have the bit set in N. */
400 for (m = cnt - 2; m > 0; --m)
401 if ((n & (1 << m)) != 0)
402 add (m);
404 /* Always add the first string. */
405 add (0);
407 while (n != 0);
409 #undef add
411 /* Now we are ready to install the string pointers and length. */
412 for (n = 0; n < (1UL << cnt); ++n)
413 result[n].len = 0;
414 n = cnt;
417 size_t mask = 1 << --n;
419 rp = result;
420 for (m = 1 << cnt; m > 0; ++rp)
421 if ((--m & mask) != 0)
422 rp->len += temp[n].len + 1;
424 while (n != 0);
426 /* The first half of the strings all include the first string. */
427 n = (1 << cnt) - 2;
428 rp = &result[2];
429 while (n != (1UL << (cnt - 1)))
431 if ((n & 1) != 0)
432 rp[0].str = rp[-2].str + rp[-2].len;
433 else
434 rp[0].str = rp[-1].str;
435 ++rp;
436 --n;
439 /* The second have starts right after the first part of the string of
440 corresponding entry in the first half. */
443 rp[0].str = rp[-(1 << (cnt - 1))].str + temp[cnt - 1].len + 1;
444 ++rp;
446 while (--n != 0);
448 /* The maximum string length. */
449 *max_capstrlen = result[0].len;
451 return result;