Update.
[glibc.git] / sysdeps / generic / dl-sysdep.c
blob64cfd47bef8f2bf5e2810c13a21db537e7244e31
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;
42 extern void _end;
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;
51 int __libc_multiple_libcs = 0; /* Defining this here avoids the inclusion
52 of init-first. */
53 /* This variable contains the lowest stack address ever used. */
54 void *__libc_stack_end;
55 static ElfW(auxv_t) *_dl_auxv;
57 #ifndef DL_FIND_ARG_COMPONENTS
58 # define DL_FIND_ARG_COMPONENTS(cookie, argc, argv, envp, auxp) \
59 do { \
60 void **_tmp; \
61 (argc) = *(long int *) cookie; \
62 (argv) = (char **) ((long int *) cookie + 1); \
63 (envp) = (argv) + (argc) + 1; \
64 for (_tmp = (void **) (envp); *_tmp; ++_tmp) \
65 continue; \
66 (auxp) = (void *) ++_tmp; \
67 } while (0)
68 #endif
71 ElfW(Addr)
72 _dl_sysdep_start (void **start_argptr,
73 void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phnum,
74 ElfW(Addr) *user_entry))
76 const ElfW(Phdr) *phdr = NULL;
77 ElfW(Word) phnum = 0;
78 ElfW(Addr) user_entry;
79 ElfW(auxv_t) *av;
80 uid_t uid = 0;
81 uid_t euid = 0;
82 gid_t gid = 0;
83 gid_t egid = 0;
84 #ifdef HAVE_AUX_XID
85 # define set_seen(tag) (tag) /* Evaluate for the side effects. */
86 #else
87 unsigned int seen = 0;
88 # define M(type) (1 << (type))
89 # define set_seen(tag) seen |= M ((tag)->a_type)
90 #endif
92 DL_FIND_ARG_COMPONENTS (start_argptr, _dl_argc, _dl_argv, _environ,
93 _dl_auxv);
95 user_entry = (ElfW(Addr)) ENTRY_POINT;
96 GL(dl_platform) = NULL; /* Default to nothing known about the platform. */
98 for (av = _dl_auxv; av->a_type != AT_NULL; set_seen (av++))
99 switch (av->a_type)
101 case AT_PHDR:
102 phdr = av->a_un.a_ptr;
103 break;
104 case AT_PHNUM:
105 phnum = av->a_un.a_val;
106 break;
107 case AT_PAGESZ:
108 GL(dl_pagesize) = av->a_un.a_val;
109 break;
110 case AT_ENTRY:
111 user_entry = av->a_un.a_val;
112 break;
113 #ifdef NEED_DL_BASE_ADDR
114 case AT_BASE:
115 _dl_base_addr = av->a_un.a_val;
116 break;
117 #endif
118 case AT_UID:
119 uid = av->a_un.a_val;
120 break;
121 case AT_GID:
122 gid = av->a_un.a_val;
123 break;
124 case AT_EUID:
125 euid = av->a_un.a_val;
126 break;
127 case AT_EGID:
128 egid = av->a_un.a_val;
129 break;
130 case AT_PLATFORM:
131 GL(dl_platform) = av->a_un.a_ptr;
132 break;
133 case AT_HWCAP:
134 GL(dl_hwcap) = av->a_un.a_val;
135 break;
136 case AT_CLKTCK:
137 GL(dl_clktck) = av->a_un.a_val;
138 break;
139 case AT_FPUCW:
140 GL(dl_fpu_control) = av->a_un.a_val;
141 break;
144 #ifdef DL_SYSDEP_OSCHECK
145 DL_SYSDEP_OSCHECK (dl_fatal);
146 #endif
148 /* Linux doesn't provide us with any of these values on the stack
149 when the dynamic linker is run directly as a program. */
151 #ifndef HAVE_AUX_XID
152 # define SEE(UID, uid) if ((seen & M (AT_##UID)) == 0) uid = __get##uid ()
153 SEE (UID, uid);
154 SEE (GID, gid);
155 SEE (EUID, euid);
156 SEE (EGID, egid);
157 #endif
159 __libc_enable_secure = uid != euid || gid != egid;
161 #ifndef HAVE_AUX_PAGESIZE
162 if (GL(dl_pagesize) == 0)
163 GL(dl_pagesize) = __getpagesize ();
164 #endif
166 #ifdef DL_SYSDEP_INIT
167 DL_SYSDEP_INIT;
168 #endif
170 #ifdef DL_PLATFORM_INIT
171 DL_PLATFORM_INIT;
172 #endif
174 /* Determine the length of the platform name. */
175 if (GL(dl_platform) != NULL)
176 GL(dl_platformlen) = strlen (GL(dl_platform));
178 if (__sbrk (0) == &_end)
179 /* The dynamic linker was run as a program, and so the initial break
180 starts just after our bss, at &_end. The malloc in dl-minimal.c
181 will consume the rest of this page, so tell the kernel to move the
182 break up that far. When the user program examines its break, it
183 will see this new value and not clobber our data. */
184 __sbrk (GL(dl_pagesize) - ((&_end - (void *) 0) & (GL(dl_pagesize) - 1)));
186 /* If this is a SUID program we make sure that FDs 0, 1, and 2 are
187 allocated. If necessary we are doing it ourself. If it is not
188 possible we stop the program. */
189 if (__builtin_expect (__libc_enable_secure, 0))
190 __libc_check_standard_fds ();
192 (*dl_main) (phdr, phnum, &user_entry);
193 return user_entry;
196 void
197 internal_function
198 _dl_sysdep_start_cleanup (void)
202 void
203 internal_function
204 _dl_show_auxv (void)
206 char buf[64];
207 ElfW(auxv_t) *av;
209 /* Terminate string. */
210 buf[63] = '\0';
212 /* The following code assumes that the AT_* values are encoded
213 starting from 0 with AT_NULL, 1 for AT_IGNORE, and all other values
214 close by (otherwise the array will be too large). In case we have
215 to support a platform where these requirements are not fulfilled
216 some alternative implementation has to be used. */
217 for (av = _dl_auxv; av->a_type != AT_NULL; ++av)
219 static const struct
221 const char label[20];
222 enum { dec, hex, str } form;
223 } auxvars[] =
225 [AT_EXECFD - 2] = { "AT_EXECFD: ", dec },
226 [AT_PHDR - 2] = { "AT_PHDR: 0x", hex },
227 [AT_PHENT - 2] = { "AT_PHENT: ", dec },
228 [AT_PHNUM - 2] = { "AT_PHNUM: ", dec },
229 [AT_PAGESZ - 2] = { "AT_PAGESZ: ", dec },
230 [AT_BASE - 2] = { "AT_BASE: 0x", hex },
231 [AT_FLAGS - 2] = { "AT_FLAGS: 0x", hex },
232 [AT_ENTRY - 2] = { "AT_ENTRY: 0x", hex },
233 [AT_NOTELF - 2] = { "AT_NOTELF: ", hex },
234 [AT_UID - 2] = { "AT_UID: ", dec },
235 [AT_EUID - 2] = { "AT_EUID: ", dec },
236 [AT_GID - 2] = { "AT_GID: ", dec },
237 [AT_EGID - 2] = { "AT_EGID: ", dec },
238 [AT_PLATFORM - 2] = { "AT_PLATFORM: ", str },
239 [AT_HWCAP - 2] = { "AT_HWCAP: ", hex },
240 [AT_CLKTCK - 2] = { "AT_CLKTCK: ", dec },
241 [AT_FPUCW - 2] = { "AT_FPUCW: ", hex },
242 [AT_DCACHEBSIZE - 2] = { "AT_DCACHEBSIZE: 0x", hex },
243 [AT_ICACHEBSIZE - 2] = { "AT_ICACHEBSIZE: 0x", hex },
244 [AT_UCACHEBSIZE - 2] = { "AT_UCACHEBSIZE: 0x", hex }
246 unsigned int idx = (unsigned int) (av->a_type - 2);
248 assert (AT_NULL == 0);
249 assert (AT_IGNORE == 1);
250 if (idx < sizeof (auxvars) / sizeof (auxvars[0]))
252 if (av->a_type != AT_HWCAP || _dl_procinfo (av->a_un.a_val) < 0)
254 const char *val = av->a_un.a_ptr;
256 if (__builtin_expect (auxvars[idx].form, dec) == dec)
257 val = _itoa ((unsigned long int) av->a_un.a_val,
258 buf + sizeof buf - 1, 10, 0);
259 else if (__builtin_expect (auxvars[idx].form, hex) == hex)
260 val = _itoa ((unsigned long int) av->a_un.a_val,
261 buf + sizeof buf - 1, 16, 0);
263 _dl_printf ("%s%s\n", auxvars[idx].label, val);
270 /* Return an array of useful/necessary hardware capability names. */
271 const struct r_strlenpair *
272 internal_function
273 _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
274 size_t *max_capstrlen)
276 /* Determine how many important bits are set. */
277 unsigned long int masked = GL(dl_hwcap) & GL(dl_hwcap_mask);
278 size_t cnt = platform != NULL;
279 size_t n, m;
280 size_t total;
281 struct r_strlenpair *temp;
282 struct r_strlenpair *result;
283 struct r_strlenpair *rp;
284 char *cp;
286 /* Count the number of bits set in the masked value. */
287 for (n = 0; (~((1UL << n) - 1) & masked) != 0; ++n)
288 if ((masked & (1UL << n)) != 0)
289 ++cnt;
291 if (cnt == 0)
293 /* If we have platform name and no important capability we only have
294 the base directory to search. */
295 result = (struct r_strlenpair *) malloc (sizeof (*result));
296 if (result == NULL)
298 no_memory:
299 INT(_dl_signal_error) (ENOMEM, NULL, NULL,
300 N_("cannot create capability list"));
303 result[0].str = (char *) result; /* Does not really matter. */
304 result[0].len = 0;
306 *sz = 1;
307 return result;
310 /* Create temporary data structure to generate result table. */
311 temp = (struct r_strlenpair *) alloca (cnt * sizeof (*temp));
312 m = 0;
313 for (n = 0; masked != 0; ++n)
314 if ((masked & (1UL << n)) != 0)
316 temp[m].str = _dl_hwcap_string (n);
317 temp[m].len = strlen (temp[m].str);
318 masked ^= 1UL << n;
319 ++m;
321 if (platform != NULL)
323 temp[m].str = platform;
324 temp[m].len = platform_len;
325 ++m;
328 /* Determine the total size of all strings together. */
329 if (cnt == 1)
330 total = temp[0].len;
331 else
333 total = (1 << (cnt - 2)) * (temp[0].len + temp[cnt - 1].len + 2);
334 for (n = 1; n + 1 < cnt; ++n)
335 total += (1 << (cnt - 3)) * (temp[n].len + 1);
338 /* The result structure: we use a very compressed way to store the
339 various combinations of capability names. */
340 *sz = 1 << cnt;
341 result = (struct r_strlenpair *) malloc (*sz * sizeof (*result) + total);
342 if (result == NULL)
343 goto no_memory;
345 if (cnt == 1)
347 result[0].str = (char *) (result + *sz);
348 result[0].len = temp[0].len + 1;
349 result[1].str = (char *) (result + *sz);
350 result[1].len = 0;
351 cp = __mempcpy ((char *) (result + *sz), temp[0].str, temp[0].len);
352 *cp = '/';
353 *sz = 2;
354 *max_capstrlen = result[0].len;
356 return result;
359 /* Fill in the information. This follows the following scheme
360 (indeces from TEMP for four strings):
361 entry #0: 0, 1, 2, 3 binary: 1111
362 #1: 0, 1, 3 1101
363 #2: 0, 2, 3 1011
364 #3: 0, 3 1001
365 This allows the representation of all possible combinations of
366 capability names in the string. First generate the strings. */
367 result[1].str = result[0].str = cp = (char *) (result + *sz);
368 #define add(idx) \
369 cp = __mempcpy (__mempcpy (cp, temp[idx].str, temp[idx].len), "/", 1);
370 if (cnt == 2)
372 add (1);
373 add (0);
375 else
377 n = 1 << cnt;
380 n -= 2;
382 /* We always add the last string. */
383 add (cnt - 1);
385 /* Add the strings which have the bit set in N. */
386 for (m = cnt - 2; m > 0; --m)
387 if ((n & (1 << m)) != 0)
388 add (m);
390 /* Always add the first string. */
391 add (0);
393 while (n != 0);
395 #undef add
397 /* Now we are ready to install the string pointers and length. */
398 for (n = 0; n < (1UL << cnt); ++n)
399 result[n].len = 0;
400 n = cnt;
403 size_t mask = 1 << --n;
405 rp = result;
406 for (m = 1 << cnt; m > 0; ++rp)
407 if ((--m & mask) != 0)
408 rp->len += temp[n].len + 1;
410 while (n != 0);
412 /* The first half of the strings all include the first string. */
413 n = (1 << cnt) - 2;
414 rp = &result[2];
415 while (n != (1UL << (cnt - 1)))
417 if ((n & 1) != 0)
418 rp[0].str = rp[-2].str + rp[-2].len;
419 else
420 rp[0].str = rp[-1].str;
421 ++rp;
422 --n;
425 /* The second have starts right after the first part of the string of
426 corresponding entry in the first half. */
429 rp[0].str = rp[-(1 << (cnt - 1))].str + temp[cnt - 1].len + 1;
430 ++rp;
432 while (--n != 0);
434 /* The maximum string length. */
435 *max_capstrlen = result[0].len;
437 return result;