Update.
[glibc.git] / sysdeps / generic / dl-sysdep.c
blob17e8f4dcf2776121fab8f1918597585663a164d8
1 /* Operating system support for run-time dynamic linker. Generic Unix version.
2 Copyright (C) 1995-1998, 2000, 2001, 2002 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 char **_environ attribute_hidden;
42 extern void _end attribute_hidden;
44 /* Protect SUID program against misuse of file descriptors. */
45 extern void __libc_check_standard_fds (void);
47 #ifdef NEED_DL_BASE_ADDR
48 ElfW(Addr) _dl_base_addr;
49 #endif
50 int __libc_enable_secure = 0;
51 INTVARDEF(__libc_enable_secure)
52 int __libc_multiple_libcs = 0; /* Defining this here avoids the inclusion
53 of init-first. */
54 /* This variable contains the lowest stack address ever used. */
55 void *__libc_stack_end;
56 static ElfW(auxv_t) *_dl_auxv;
58 #ifndef DL_FIND_ARG_COMPONENTS
59 # define DL_FIND_ARG_COMPONENTS(cookie, argc, argv, envp, auxp) \
60 do { \
61 void **_tmp; \
62 (argc) = *(long int *) cookie; \
63 (argv) = (char **) ((long int *) cookie + 1); \
64 (envp) = (argv) + (argc) + 1; \
65 for (_tmp = (void **) (envp); *_tmp; ++_tmp) \
66 continue; \
67 (auxp) = (void *) ++_tmp; \
68 } while (0)
69 #endif
72 ElfW(Addr)
73 _dl_sysdep_start (void **start_argptr,
74 void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phnum,
75 ElfW(Addr) *user_entry))
77 const ElfW(Phdr) *phdr = NULL;
78 ElfW(Word) phnum = 0;
79 ElfW(Addr) user_entry;
80 ElfW(auxv_t) *av;
81 uid_t uid = 0;
82 gid_t gid = 0;
83 #ifdef HAVE_AUX_XID
84 # define set_seen(tag) (tag) /* Evaluate for the side effects. */
85 #else
86 unsigned int seen = 0;
87 # define M(type) (1 << (type))
88 # define set_seen(tag) seen |= M ((tag)->a_type)
89 #endif
91 DL_FIND_ARG_COMPONENTS (start_argptr, _dl_argc, INTUSE(_dl_argv), _environ,
92 _dl_auxv);
94 user_entry = (ElfW(Addr)) ENTRY_POINT;
95 GL(dl_platform) = NULL; /* Default to nothing known about the platform. */
97 for (av = _dl_auxv; av->a_type != AT_NULL; set_seen (av++))
98 switch (av->a_type)
100 case AT_PHDR:
101 phdr = av->a_un.a_ptr;
102 break;
103 case AT_PHNUM:
104 phnum = av->a_un.a_val;
105 break;
106 case AT_PAGESZ:
107 GL(dl_pagesize) = av->a_un.a_val;
108 break;
109 case AT_ENTRY:
110 user_entry = av->a_un.a_val;
111 break;
112 #ifdef NEED_DL_BASE_ADDR
113 case AT_BASE:
114 _dl_base_addr = av->a_un.a_val;
115 break;
116 #endif
117 case AT_UID:
118 case AT_EUID:
119 uid ^= av->a_un.a_val;
120 break;
121 case AT_GID:
122 case AT_EGID:
123 gid ^= av->a_un.a_val;
124 break;
125 case AT_PLATFORM:
126 GL(dl_platform) = av->a_un.a_ptr;
127 break;
128 case AT_HWCAP:
129 GL(dl_hwcap) = av->a_un.a_val;
130 break;
131 case AT_CLKTCK:
132 GL(dl_clktck) = av->a_un.a_val;
133 break;
134 case AT_FPUCW:
135 GL(dl_fpu_control) = av->a_un.a_val;
136 break;
139 #ifdef DL_SYSDEP_OSCHECK
140 DL_SYSDEP_OSCHECK (dl_fatal);
141 #endif
143 /* Fill in the values we have not gotten from the kernel through the
144 auxiliary vector. */
145 #ifndef HAVE_AUX_XID
146 # define SEE(UID, var, uid) \
147 if ((seen & M (AT_##UID)) == 0) var ^= __get##uid ()
148 SEE (UID, uid, uid);
149 SEE (EUID, uid, euid);
150 SEE (GID, gid, gid);
151 SEE (EGID, gid, egid);
152 #endif
154 /* If one of the two pairs of IDs does not mattch this is a setuid
155 or setgid run. */
156 INTUSE(__libc_enable_secure) = uid | gid;
158 #ifndef HAVE_AUX_PAGESIZE
159 if (GL(dl_pagesize) == 0)
160 GL(dl_pagesize) = __getpagesize ();
161 #endif
163 #ifdef DL_SYSDEP_INIT
164 DL_SYSDEP_INIT;
165 #endif
167 #ifdef DL_PLATFORM_INIT
168 DL_PLATFORM_INIT;
169 #endif
171 /* Determine the length of the platform name. */
172 if (GL(dl_platform) != NULL)
173 GL(dl_platformlen) = strlen (GL(dl_platform));
175 if (__sbrk (0) == &_end)
176 /* The dynamic linker was run as a program, and so the initial break
177 starts just after our bss, at &_end. The malloc in dl-minimal.c
178 will consume the rest of this page, so tell the kernel to move the
179 break up that far. When the user program examines its break, it
180 will see this new value and not clobber our data. */
181 __sbrk (GL(dl_pagesize) - ((&_end - (void *) 0) & (GL(dl_pagesize) - 1)));
183 /* If this is a SUID program we make sure that FDs 0, 1, and 2 are
184 allocated. If necessary we are doing it ourself. If it is not
185 possible we stop the program. */
186 if (__builtin_expect (INTUSE(__libc_enable_secure), 0))
187 __libc_check_standard_fds ();
189 (*dl_main) (phdr, phnum, &user_entry);
190 return user_entry;
193 void
194 internal_function
195 _dl_sysdep_start_cleanup (void)
199 void
200 internal_function
201 _dl_show_auxv (void)
203 char buf[64];
204 ElfW(auxv_t) *av;
206 /* Terminate string. */
207 buf[63] = '\0';
209 /* The following code assumes that the AT_* values are encoded
210 starting from 0 with AT_NULL, 1 for AT_IGNORE, and all other values
211 close by (otherwise the array will be too large). In case we have
212 to support a platform where these requirements are not fulfilled
213 some alternative implementation has to be used. */
214 for (av = _dl_auxv; av->a_type != AT_NULL; ++av)
216 static const struct
218 const char label[20];
219 enum { dec, hex, str } form;
220 } auxvars[] =
222 [AT_EXECFD - 2] = { "AT_EXECFD: ", dec },
223 [AT_PHDR - 2] = { "AT_PHDR: 0x", hex },
224 [AT_PHENT - 2] = { "AT_PHENT: ", dec },
225 [AT_PHNUM - 2] = { "AT_PHNUM: ", dec },
226 [AT_PAGESZ - 2] = { "AT_PAGESZ: ", dec },
227 [AT_BASE - 2] = { "AT_BASE: 0x", hex },
228 [AT_FLAGS - 2] = { "AT_FLAGS: 0x", hex },
229 [AT_ENTRY - 2] = { "AT_ENTRY: 0x", hex },
230 [AT_NOTELF - 2] = { "AT_NOTELF: ", hex },
231 [AT_UID - 2] = { "AT_UID: ", dec },
232 [AT_EUID - 2] = { "AT_EUID: ", dec },
233 [AT_GID - 2] = { "AT_GID: ", dec },
234 [AT_EGID - 2] = { "AT_EGID: ", dec },
235 [AT_PLATFORM - 2] = { "AT_PLATFORM: ", str },
236 [AT_HWCAP - 2] = { "AT_HWCAP: ", hex },
237 [AT_CLKTCK - 2] = { "AT_CLKTCK: ", dec },
238 [AT_FPUCW - 2] = { "AT_FPUCW: ", hex },
239 [AT_DCACHEBSIZE - 2] = { "AT_DCACHEBSIZE: 0x", hex },
240 [AT_ICACHEBSIZE - 2] = { "AT_ICACHEBSIZE: 0x", hex },
241 [AT_UCACHEBSIZE - 2] = { "AT_UCACHEBSIZE: 0x", hex }
243 unsigned int idx = (unsigned int) (av->a_type - 2);
245 assert (AT_NULL == 0);
246 assert (AT_IGNORE == 1);
247 if (idx < sizeof (auxvars) / sizeof (auxvars[0]))
249 if (av->a_type != AT_HWCAP || _dl_procinfo (av->a_un.a_val) < 0)
251 const char *val = av->a_un.a_ptr;
253 if (__builtin_expect (auxvars[idx].form, dec) == dec)
254 val = _itoa ((unsigned long int) av->a_un.a_val,
255 buf + sizeof buf - 1, 10, 0);
256 else if (__builtin_expect (auxvars[idx].form, hex) == hex)
257 val = _itoa ((unsigned long int) av->a_un.a_val,
258 buf + sizeof buf - 1, 16, 0);
260 _dl_printf ("%s%s\n", auxvars[idx].label, val);
267 /* Return an array of useful/necessary hardware capability names. */
268 const struct r_strlenpair *
269 internal_function
270 _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
271 size_t *max_capstrlen)
273 /* Determine how many important bits are set. */
274 unsigned long int masked = GL(dl_hwcap) & GL(dl_hwcap_mask);
275 size_t cnt = platform != NULL;
276 size_t n, m;
277 size_t total;
278 struct r_strlenpair *temp;
279 struct r_strlenpair *result;
280 struct r_strlenpair *rp;
281 char *cp;
283 /* Count the number of bits set in the masked value. */
284 for (n = 0; (~((1UL << n) - 1) & masked) != 0; ++n)
285 if ((masked & (1UL << n)) != 0)
286 ++cnt;
288 if (cnt == 0)
290 /* If we have platform name and no important capability we only have
291 the base directory to search. */
292 result = (struct r_strlenpair *) malloc (sizeof (*result));
293 if (result == NULL)
295 no_memory:
296 INTUSE(_dl_signal_error) (ENOMEM, NULL, NULL,
297 N_("cannot create capability list"));
300 result[0].str = (char *) result; /* Does not really matter. */
301 result[0].len = 0;
303 *sz = 1;
304 return result;
307 /* Create temporary data structure to generate result table. */
308 temp = (struct r_strlenpair *) alloca (cnt * sizeof (*temp));
309 m = 0;
310 for (n = 0; masked != 0; ++n)
311 if ((masked & (1UL << n)) != 0)
313 temp[m].str = _dl_hwcap_string (n);
314 temp[m].len = strlen (temp[m].str);
315 masked ^= 1UL << n;
316 ++m;
318 if (platform != NULL)
320 temp[m].str = platform;
321 temp[m].len = platform_len;
322 ++m;
324 assert (m == cnt);
326 /* Determine the total size of all strings together. */
327 if (cnt == 1)
328 total = temp[0].len;
329 else
331 total = (1UL << (cnt - 2)) * (temp[0].len + temp[cnt - 1].len + 2);
332 for (n = 1; n + 1 < cnt; ++n)
333 total += (1UL << (cnt - 3)) * (temp[n].len + 1);
336 /* The result structure: we use a very compressed way to store the
337 various combinations of capability names. */
338 *sz = 1 << cnt;
339 result = (struct r_strlenpair *) malloc (*sz * sizeof (*result) + total);
340 if (result == NULL)
341 goto no_memory;
343 if (cnt == 1)
345 result[0].str = (char *) (result + *sz);
346 result[0].len = temp[0].len + 1;
347 result[1].str = (char *) (result + *sz);
348 result[1].len = 0;
349 cp = __mempcpy ((char *) (result + *sz), temp[0].str, temp[0].len);
350 *cp = '/';
351 *sz = 2;
352 *max_capstrlen = result[0].len;
354 return result;
357 /* Fill in the information. This follows the following scheme
358 (indeces from TEMP for four strings):
359 entry #0: 0, 1, 2, 3 binary: 1111
360 #1: 0, 1, 3 1101
361 #2: 0, 2, 3 1011
362 #3: 0, 3 1001
363 This allows the representation of all possible combinations of
364 capability names in the string. First generate the strings. */
365 result[1].str = result[0].str = cp = (char *) (result + *sz);
366 #define add(idx) \
367 cp = __mempcpy (__mempcpy (cp, temp[idx].str, temp[idx].len), "/", 1);
368 if (cnt == 2)
370 add (1);
371 add (0);
373 else
375 n = 1 << cnt;
378 n -= 2;
380 /* We always add the last string. */
381 add (cnt - 1);
383 /* Add the strings which have the bit set in N. */
384 for (m = cnt - 2; m > 0; --m)
385 if ((n & (1 << m)) != 0)
386 add (m);
388 /* Always add the first string. */
389 add (0);
391 while (n != 0);
393 #undef add
395 /* Now we are ready to install the string pointers and length. */
396 for (n = 0; n < (1UL << cnt); ++n)
397 result[n].len = 0;
398 n = cnt;
401 size_t mask = 1 << --n;
403 rp = result;
404 for (m = 1 << cnt; m > 0; ++rp)
405 if ((--m & mask) != 0)
406 rp->len += temp[n].len + 1;
408 while (n != 0);
410 /* The first half of the strings all include the first string. */
411 n = (1 << cnt) - 2;
412 rp = &result[2];
413 while (n != (1UL << (cnt - 1)))
415 if ((--n & 1) != 0)
416 rp[0].str = rp[-2].str + rp[-2].len;
417 else
418 rp[0].str = rp[-1].str;
419 ++rp;
422 /* The second have starts right after the first part of the string of
423 corresponding entry in the first half. */
426 rp[0].str = rp[-(1 << (cnt - 1))].str + temp[cnt - 1].len + 1;
427 ++rp;
429 while (--n != 0);
431 /* The maximum string length. */
432 *max_capstrlen = result[0].len;
434 return result;