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 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.
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.
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. */
27 #include <sys/types.h>
31 #include <stdio-common/_itoa.h>
32 #include <fpu_control.h>
35 #include <dl-machine.h>
36 #include <dl-procinfo.h>
37 #include <dl-osinfo.h>
38 #include <hp-timing.h>
41 extern char **_dl_argv
;
42 extern char **_environ
;
43 extern size_t _dl_pagesize
;
44 extern int _dl_clktck
;
45 extern const char *_dl_platform
;
46 extern unsigned long int _dl_hwcap
;
47 extern size_t _dl_platformlen
;
48 extern fpu_control_t _dl_fpu_control
;
51 /* Protect SUID program against misuse of file descriptors. */
52 extern void __libc_check_standard_fds (void);
54 #ifdef NEED_DL_BASE_ADDR
55 ElfW(Addr
) _dl_base_addr
;
57 int __libc_enable_secure
;
58 int __libc_multiple_libcs
= 0; /* Defining this here avoids the inclusion
60 /* This variable contains the lowest stack address ever used. */
61 void *__libc_stack_end
;
62 static ElfW(auxv_t
) *_dl_auxv
;
63 unsigned long int _dl_hwcap_mask
= HWCAP_IMPORTANT
;
65 hp_timing_t _dl_cpuclock_offset
= 0;
68 #ifndef DL_FIND_ARG_COMPONENTS
69 # define DL_FIND_ARG_COMPONENTS(cookie, argc, argv, envp, auxp) \
72 (argc) = *(long int *) cookie; \
73 (argv) = (char **) ((long int *) cookie + 1); \
74 (envp) = (argv) + (argc) + 1; \
75 for (_tmp = (void **) (envp); *_tmp; ++_tmp) \
77 (auxp) = (void *) ++_tmp; \
83 _dl_sysdep_start (void **start_argptr
,
84 void (*dl_main
) (const ElfW(Phdr
) *phdr
, ElfW(Word
) phnum
,
85 ElfW(Addr
) *user_entry
))
87 const ElfW(Phdr
) *phdr
= NULL
;
89 ElfW(Addr
) user_entry
;
96 # define set_seen(tag) (tag) /* Evaluate for the side effects. */
98 unsigned int seen
= 0;
99 # define M(type) (1 << (type))
100 # define set_seen(tag) seen |= M ((tag)->a_type)
104 HP_TIMING_NOW (_dl_cpuclock_offset
);
107 DL_FIND_ARG_COMPONENTS (start_argptr
, _dl_argc
, _dl_argv
, _environ
,
110 user_entry
= (ElfW(Addr
)) ENTRY_POINT
;
111 _dl_platform
= NULL
; /* Default to nothing known about the platform. */
113 for (av
= _dl_auxv
; av
->a_type
!= AT_NULL
; set_seen (av
++))
117 phdr
= av
->a_un
.a_ptr
;
120 phnum
= av
->a_un
.a_val
;
123 _dl_pagesize
= av
->a_un
.a_val
;
126 user_entry
= av
->a_un
.a_val
;
128 #ifdef NEED_DL_BASE_ADDR
130 _dl_base_addr
= av
->a_un
.a_val
;
134 uid
= av
->a_un
.a_val
;
137 gid
= av
->a_un
.a_val
;
140 euid
= av
->a_un
.a_val
;
143 egid
= av
->a_un
.a_val
;
146 _dl_platform
= av
->a_un
.a_ptr
;
149 _dl_hwcap
= av
->a_un
.a_val
;
152 _dl_clktck
= av
->a_un
.a_val
;
155 _dl_fpu_control
= av
->a_un
.a_val
;
159 #ifdef DL_SYSDEP_OSCHECK
160 DL_SYSDEP_OSCHECK (dl_fatal
);
163 /* Linux doesn't provide us with any of these values on the stack
164 when the dynamic linker is run directly as a program. */
167 # define SEE(UID, uid) if ((seen & M (AT_##UID)) == 0) uid = __get##uid ()
174 __libc_enable_secure
= uid
!= euid
|| gid
!= egid
;
176 #ifndef HAVE_AUX_PAGESIZE
177 if (_dl_pagesize
== 0)
178 _dl_pagesize
= __getpagesize ();
181 #ifdef DL_SYSDEP_INIT
185 #ifdef DL_PLATFORM_INIT
189 /* Determine the length of the platform name. */
190 if (_dl_platform
!= NULL
)
191 _dl_platformlen
= strlen (_dl_platform
);
193 if (__sbrk (0) == &_end
)
194 /* The dynamic linker was run as a program, and so the initial break
195 starts just after our bss, at &_end. The malloc in dl-minimal.c
196 will consume the rest of this page, so tell the kernel to move the
197 break up that far. When the user program examines its break, it
198 will see this new value and not clobber our data. */
199 __sbrk (_dl_pagesize
- ((&_end
- (void *) 0) & (_dl_pagesize
- 1)));
201 /* If this is a SUID program we make sure that FDs 0, 1, and 2 are
202 allocated. If necessary we are doing it ourself. If it is not
203 possible we stop the program. */
204 if (__builtin_expect (__libc_enable_secure
, 0))
205 __libc_check_standard_fds ();
207 (*dl_main
) (phdr
, phnum
, &user_entry
);
213 _dl_sysdep_start_cleanup (void)
224 /* Terminate string. */
227 /* The following code assumes that the AT_* values are encoded
228 starting from 0 with AT_NULL, 1 for AT_IGNORE, and all other values
229 close by (otherwise the array will be too large). In case we have
230 to support a platform where these requirements are not fulfilled
231 some alternative implementation has to be used. */
232 for (av
= _dl_auxv
; av
->a_type
!= AT_NULL
; ++av
)
236 const char label
[20];
237 enum { dec
, hex
, str
} form
;
240 [AT_EXECFD
- 2] = { "AT_EXECFD: ", dec
},
241 [AT_PHDR
- 2] = { "AT_PHDR: 0x", hex
},
242 [AT_PHENT
- 2] = { "AT_PHENT: ", dec
},
243 [AT_PHNUM
- 2] = { "AT_PHNUM: ", dec
},
244 [AT_PAGESZ
- 2] = { "AT_PAGESZ: ", dec
},
245 [AT_BASE
- 2] = { "AT_BASE: 0x", hex
},
246 [AT_FLAGS
- 2] = { "AT_FLAGS: 0x", hex
},
247 [AT_ENTRY
- 2] = { "AT_ENTRY: 0x", hex
},
248 [AT_NOTELF
- 2] = { "AT_NOTELF: ", hex
},
249 [AT_UID
- 2] = { "AT_UID: ", dec
},
250 [AT_EUID
- 2] = { "AT_EUID: ", dec
},
251 [AT_GID
- 2] = { "AT_GID: ", dec
},
252 [AT_EGID
- 2] = { "AT_EGID: ", dec
},
253 [AT_PLATFORM
- 2] = { "AT_PLATFORM: ", str
},
254 [AT_HWCAP
- 2] = { "AT_HWCAP: ", hex
},
255 [AT_CLKTCK
- 2] = { "AT_CLKTCK: ", dec
},
256 [AT_FPUCW
- 2] = { "AT_FPUCW: ", hex
},
257 [AT_DCACHEBSIZE
- 2] = { "AT_DCACHEBSIZE: 0x", hex
},
258 [AT_ICACHEBSIZE
- 2] = { "AT_ICACHEBSIZE: 0x", hex
},
259 [AT_UCACHEBSIZE
- 2] = { "AT_UCACHEBSIZE: 0x", hex
}
261 unsigned int idx
= (unsigned int) (av
->a_type
- 2);
263 assert (AT_NULL
== 0);
264 assert (AT_IGNORE
== 1);
265 if (idx
< sizeof (auxvars
) / sizeof (auxvars
[0]))
267 if (av
->a_type
!= AT_HWCAP
|| _dl_procinfo (av
->a_un
.a_val
) < 0)
269 const char *val
= av
->a_un
.a_ptr
;
271 if (__builtin_expect (auxvars
[idx
].form
, dec
) == dec
)
272 val
= _itoa_word (av
->a_un
.a_val
, buf
+ sizeof buf
- 1, 10, 0);
273 else if (__builtin_expect (auxvars
[idx
].form
, hex
) == hex
)
274 val
= _itoa_word (av
->a_un
.a_val
, buf
+ sizeof buf
- 1, 16, 0);
276 _dl_printf ("%s%s\n", auxvars
[idx
].label
, val
);
283 /* Return an array of useful/necessary hardware capability names. */
284 const struct r_strlenpair
*
286 _dl_important_hwcaps (const char *platform
, size_t platform_len
, size_t *sz
,
287 size_t *max_capstrlen
)
289 /* Determine how many important bits are set. */
290 unsigned long int masked
= _dl_hwcap
& _dl_hwcap_mask
;
291 size_t cnt
= platform
!= NULL
;
294 struct r_strlenpair
*temp
;
295 struct r_strlenpair
*result
;
296 struct r_strlenpair
*rp
;
299 /* Count the number of bits set in the masked value. */
300 for (n
= 0; (~((1UL << n
) - 1) & masked
) != 0; ++n
)
301 if ((masked
& (1UL << n
)) != 0)
306 /* If we have platform name and no important capability we only have
307 the base directory to search. */
308 result
= (struct r_strlenpair
*) malloc (sizeof (*result
));
312 _dl_signal_error (ENOMEM
, NULL
, "cannot create capability list");
315 result
[0].str
= (char *) result
; /* Does not really matter. */
322 /* Create temporary data structure to generate result table. */
323 temp
= (struct r_strlenpair
*) alloca (cnt
* sizeof (*temp
));
325 for (n
= 0; masked
!= 0; ++n
)
326 if ((masked
& (1UL << n
)) != 0)
328 temp
[m
].str
= _dl_hwcap_string (n
);
329 temp
[m
].len
= strlen (temp
[m
].str
);
333 if (platform
!= NULL
)
335 temp
[m
].str
= platform
;
336 temp
[m
].len
= platform_len
;
340 /* Determine the total size of all strings together. */
345 total
= (1 << (cnt
- 2)) * (temp
[0].len
+ temp
[cnt
- 1].len
+ 2);
346 for (n
= 1; n
+ 1 < cnt
; ++n
)
347 total
+= (1 << (cnt
- 3)) * (temp
[n
].len
+ 1);
350 /* The result structure: we use a very compressed way to store the
351 various combinations of capability names. */
353 result
= (struct r_strlenpair
*) malloc (*sz
* sizeof (*result
) + total
);
359 result
[0].str
= (char *) (result
+ *sz
);
360 result
[0].len
= temp
[0].len
+ 1;
361 result
[1].str
= (char *) (result
+ *sz
);
363 cp
= __mempcpy ((char *) (result
+ *sz
), temp
[0].str
, temp
[0].len
);
366 *max_capstrlen
= result
[0].len
;
371 /* Fill in the information. This follows the following scheme
372 (indeces from TEMP for four strings):
373 entry #0: 0, 1, 2, 3 binary: 1111
377 This allows the representation of all possible combinations of
378 capability names in the string. First generate the strings. */
379 result
[1].str
= result
[0].str
= cp
= (char *) (result
+ *sz
);
381 cp = __mempcpy (__mempcpy (cp, temp[idx].str, temp[idx].len), "/", 1);
394 /* We always add the last string. */
397 /* Add the strings which have the bit set in N. */
398 for (m
= cnt
- 2; m
> 0; --m
)
399 if ((n
& (1 << m
)) != 0)
402 /* Always add the first string. */
409 /* Now we are ready to install the string pointers and length. */
410 for (n
= 0; n
< (1UL << cnt
); ++n
)
415 size_t mask
= 1 << --n
;
418 for (m
= 1 << cnt
; m
> 0; ++rp
)
419 if ((--m
& mask
) != 0)
420 rp
->len
+= temp
[n
].len
+ 1;
424 /* The first half of the strings all include the first string. */
427 while (n
!= (1UL << (cnt
- 1)))
430 rp
[0].str
= rp
[-2].str
+ rp
[-2].len
;
432 rp
[0].str
= rp
[-1].str
;
437 /* The second have starts right after the first part of the string of
438 corresponding entry in the first half. */
441 rp
[0].str
= rp
[-(1 << (cnt
- 1))].str
+ temp
[cnt
- 1].len
+ 1;
446 /* The maximum string length. */
447 *max_capstrlen
= result
[0].len
;