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
28 #include <sys/types.h>
32 #include <stdio-common/_itoa.h>
33 #include <fpu_control.h>
36 #include <dl-machine.h>
37 #include <dl-procinfo.h>
38 #include <dl-osinfo.h>
39 #include <hp-timing.h>
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
;
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
;
58 int __libc_enable_secure
;
59 int __libc_multiple_libcs
= 0; /* Defining this here avoids the inclusion
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
;
66 hp_timing_t _dl_cpuclock_offset
;
69 #ifndef DL_FIND_ARG_COMPONENTS
70 # define DL_FIND_ARG_COMPONENTS(cookie, argc, argv, envp, auxp) \
73 (argc) = *(long int *) cookie; \
74 (argv) = (char **) ((long int *) cookie + 1); \
75 (envp) = (argv) + (argc) + 1; \
76 for (_tmp = (void **) (envp); *_tmp; ++_tmp) \
78 (auxp) = (void *) ++_tmp; \
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
;
90 ElfW(Addr
) user_entry
;
97 # define set_seen(tag) (tag) /* Evaluate for the side effects. */
99 unsigned int seen
= 0;
100 # define M(type) (1 << (type))
101 # define set_seen(tag) seen |= M ((tag)->a_type)
105 HP_TIMING_NOW (_dl_cpuclock_offset
);
108 DL_FIND_ARG_COMPONENTS (start_argptr
, _dl_argc
, _dl_argv
, _environ
,
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
++))
118 phdr
= av
->a_un
.a_ptr
;
121 phnum
= av
->a_un
.a_val
;
124 _dl_pagesize
= av
->a_un
.a_val
;
127 user_entry
= av
->a_un
.a_val
;
129 #ifdef NEED_DL_BASE_ADDR
131 _dl_base_addr
= av
->a_un
.a_val
;
135 uid
= av
->a_un
.a_val
;
138 gid
= av
->a_un
.a_val
;
141 euid
= av
->a_un
.a_val
;
144 egid
= av
->a_un
.a_val
;
147 _dl_platform
= av
->a_un
.a_ptr
;
150 _dl_hwcap
= av
->a_un
.a_val
;
153 _dl_clktck
= av
->a_un
.a_val
;
156 _dl_fpu_control
= av
->a_un
.a_val
;
160 #ifdef DL_SYSDEP_OSCHECK
161 DL_SYSDEP_OSCHECK (dl_fatal
);
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. */
168 # define SEE(UID, uid) if ((seen & M (AT_##UID)) == 0) uid = __get##uid ()
175 __libc_enable_secure
= uid
!= euid
|| gid
!= egid
;
177 #ifndef HAVE_AUX_PAGESIZE
178 if (_dl_pagesize
== 0)
179 _dl_pagesize
= __getpagesize ();
182 #ifdef DL_SYSDEP_INIT
186 #ifdef DL_PLATFORM_INIT
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
);
214 _dl_sysdep_start_cleanup (void)
225 /* Terminate string. */
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
)
237 const char label
[20];
238 enum { dec
, hex
, str
} form
;
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
*
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
;
295 struct r_strlenpair
*temp
;
296 struct r_strlenpair
*result
;
297 struct r_strlenpair
*rp
;
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)
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
));
313 _dl_signal_error (ENOMEM
, NULL
, NULL
,
314 N_("cannot create capability list"));
317 result
[0].str
= (char *) result
; /* Does not really matter. */
324 /* Create temporary data structure to generate result table. */
325 temp
= (struct r_strlenpair
*) alloca (cnt
* sizeof (*temp
));
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
);
335 if (platform
!= NULL
)
337 temp
[m
].str
= platform
;
338 temp
[m
].len
= platform_len
;
342 /* Determine the total size of all strings together. */
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. */
355 result
= (struct r_strlenpair
*) malloc (*sz
* sizeof (*result
) + total
);
361 result
[0].str
= (char *) (result
+ *sz
);
362 result
[0].len
= temp
[0].len
+ 1;
363 result
[1].str
= (char *) (result
+ *sz
);
365 cp
= __mempcpy ((char *) (result
+ *sz
), temp
[0].str
, temp
[0].len
);
368 *max_capstrlen
= result
[0].len
;
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
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
);
383 cp = __mempcpy (__mempcpy (cp, temp[idx].str, temp[idx].len), "/", 1);
396 /* We always add the last string. */
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)
404 /* Always add the first string. */
411 /* Now we are ready to install the string pointers and length. */
412 for (n
= 0; n
< (1UL << cnt
); ++n
)
417 size_t mask
= 1 << --n
;
420 for (m
= 1 << cnt
; m
> 0; ++rp
)
421 if ((--m
& mask
) != 0)
422 rp
->len
+= temp
[n
].len
+ 1;
426 /* The first half of the strings all include the first string. */
429 while (n
!= (1UL << (cnt
- 1)))
432 rp
[0].str
= rp
[-2].str
+ rp
[-2].len
;
434 rp
[0].str
= rp
[-1].str
;
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;
448 /* The maximum string length. */
449 *max_capstrlen
= result
[0].len
;