Update.
[jlayton/glibc.git] / sysdeps / generic / dl-sysdep.c
1 /* Operating system support for run-time dynamic linker.  Generic Unix version.
2    Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
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.
9
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.
14
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.  */
19
20 #include <elf.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <sys/mman.h>
29 #include <elf/ldsodefs.h>
30 #include <stdio-common/_itoa.h>
31 #include <fpu_control.h>
32
33 #include <entry.h>
34 #include <dl-machine.h>
35 #include <dl-procinfo.h>
36
37 extern int _dl_argc;
38 extern char **_dl_argv;
39 extern char **_environ;
40 extern size_t _dl_pagesize;
41 extern const char *_dl_platform;
42 extern unsigned long int _dl_hwcap;
43 extern size_t _dl_platformlen;
44 extern fpu_control_t _dl_fpu_control;
45 extern void _end;
46 extern void ENTRY_POINT (void);
47
48 ElfW(Addr) _dl_base_addr;
49 int __libc_enable_secure;
50 int __libc_multiple_libcs = 0;  /* Defining this here avoids the inclusion
51                                    of init-first.  */
52 /* This variable contains the lowest stack address ever used.  */
53 void *__libc_stack_end;
54 static ElfW(auxv_t) *_dl_auxv;
55 unsigned long int _dl_hwcap_mask = HWCAP_IMPORTANT;
56
57
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 *) cookie;                                  \
63     (argv) = (char **) 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
70
71
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))
76 {
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   uid_t euid = 0;
83   gid_t gid = 0;
84   gid_t egid = 0;
85   unsigned int seen;
86
87   DL_FIND_ARG_COMPONENTS (start_argptr, _dl_argc, _dl_argv, _environ, _dl_auxv);
88
89   user_entry = (ElfW(Addr)) &ENTRY_POINT;
90   _dl_platform = NULL; /* Default to nothing known about the platform.  */
91
92   seen = 0;
93 #define M(type) (1 << (type))
94
95   for (av = _dl_auxv; av->a_type != AT_NULL; seen |= M ((++av)->a_type))
96     switch (av->a_type)
97       {
98       case AT_PHDR:
99         phdr = av->a_un.a_ptr;
100         break;
101       case AT_PHNUM:
102         phnum = av->a_un.a_val;
103         break;
104       case AT_PAGESZ:
105         _dl_pagesize = av->a_un.a_val;
106         break;
107       case AT_ENTRY:
108         user_entry = av->a_un.a_val;
109         break;
110       case AT_BASE:
111         _dl_base_addr = av->a_un.a_val;
112         break;
113       case AT_UID:
114         uid = av->a_un.a_val;
115         break;
116       case AT_GID:
117         gid = av->a_un.a_val;
118         break;
119       case AT_EUID:
120         euid = av->a_un.a_val;
121         break;
122       case AT_EGID:
123         egid = av->a_un.a_val;
124         break;
125       case AT_PLATFORM:
126         _dl_platform = av->a_un.a_ptr;
127         break;
128       case AT_HWCAP:
129         _dl_hwcap = av->a_un.a_val;
130         break;
131       case AT_FPUCW:
132         _dl_fpu_control = av->a_un.a_val;
133         break;
134       }
135
136   /* Linux doesn't provide us with any of these values on the stack
137      when the dynamic linker is run directly as a program.  */
138
139 #define SEE(UID, uid) if ((seen & M (AT_##UID)) == 0) uid = __get##uid ()
140   SEE (UID, uid);
141   SEE (GID, gid);
142   SEE (EUID, euid);
143   SEE (EGID, egid);
144
145   __libc_enable_secure = uid != euid || gid != egid;
146
147   if (_dl_pagesize == 0)
148     _dl_pagesize = __getpagesize ();
149
150 #ifdef DL_SYSDEP_INIT
151   DL_SYSDEP_INIT;
152 #endif
153
154 #ifdef DL_PLATFORM_INIT
155   DL_PLATFORM_INIT;
156 #endif
157
158   /* Determine the length of the platform name.  */
159   if (_dl_platform != NULL)
160     _dl_platformlen = strlen (_dl_platform);
161
162   if (__sbrk (0) == &_end)
163     /* The dynamic linker was run as a program, and so the initial break
164        starts just after our bss, at &_end.  The malloc in dl-minimal.c
165        will consume the rest of this page, so tell the kernel to move the
166        break up that far.  When the user program examines its break, it
167        will see this new value and not clobber our data.  */
168     __sbrk (_dl_pagesize - ((&_end - (void *) 0) & (_dl_pagesize - 1)));
169
170   (*dl_main) (phdr, phnum, &user_entry);
171   return user_entry;
172 }
173
174 void
175 _dl_sysdep_start_cleanup (void)
176 {
177 }
178
179 void
180 internal_function
181 _dl_show_auxv (void)
182 {
183   char buf[64];
184   ElfW(auxv_t) *av;
185
186   /* Terminate string.  */
187   buf[63] = '\0';
188
189   for (av = _dl_auxv; av->a_type != AT_NULL; ++av)
190     switch (av->a_type)
191       {
192       case AT_PHDR:
193         _dl_sysdep_message ("AT_PHDR:     0x",
194                             _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
195                                         16, 0),
196                             "\n", NULL);
197         break;
198       case AT_PHNUM:
199         _dl_sysdep_message ("AT_PHNUM:    ",
200                             _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
201                                         10, 0),
202                             "\n", NULL);
203         break;
204       case AT_PAGESZ:
205         _dl_sysdep_message ("AT_PAGESZ:   ",
206                             _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
207                                         10, 0),
208                             "\n", NULL);
209         break;
210       case AT_ENTRY:
211         _dl_sysdep_message ("AT_ENTRY:    0x",
212                             _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
213                                         16, 0),
214                             "\n", NULL);
215         break;
216       case AT_BASE:
217         _dl_sysdep_message ("AT_BASE:     0x",
218                             _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
219                                         16, 0),
220                             "\n", NULL);
221         break;
222       case AT_UID:
223         _dl_sysdep_message ("AT_UID:      ",
224                             _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
225                                         10, 0),
226                             "\n", NULL);
227         break;
228       case AT_GID:
229         _dl_sysdep_message ("AT_GID:      ",
230                             _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
231                                         10, 0),
232                             "\n", NULL);
233         break;
234       case AT_EUID:
235         _dl_sysdep_message ("AT_EUID:     ",
236                             _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
237                                         10, 0),
238                             "\n", NULL);
239         break;
240       case AT_EGID:
241         _dl_sysdep_message ("AT_EGID:     ",
242                             _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
243                                         10, 0),
244                             "\n", NULL);
245         break;
246       case AT_PLATFORM:
247         _dl_sysdep_message ("AT_PLATFORM: ", av->a_un.a_ptr, "\n", NULL);
248         break;
249       case AT_HWCAP:
250         _dl_hwcap = av->a_un.a_val;
251         if (_dl_procinfo (_dl_hwcap) < 0)
252           _dl_sysdep_message ("AT_HWCAP:    ",
253                               _itoa_word (_dl_hwcap, buf + sizeof buf - 1,
254                                           16, 0),
255                               "\n", NULL);
256         break;
257       case AT_FPUCW:
258         _dl_sysdep_message ("AT_FPUCW:     ",
259                             _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
260                                         10, 0),
261                             "\n", NULL);
262         break;
263       }
264 }
265
266
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)
272 {
273   /* Determine how many important bits are set.  */
274   unsigned long int masked = _dl_hwcap & _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;
282
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;
287
288   if (cnt == 0)
289     {
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)
294         {
295         no_memory:
296           _dl_signal_error (ENOMEM, NULL, "cannot create capability list");
297         }
298
299       result[0].str = (char *) result;  /* Does not really matter.  */
300       result[0].len = 0;
301
302       *sz = 1;
303       return result;
304     }
305
306   /* Create temporary data structure to generate result table.  */
307   temp = (struct r_strlenpair *) alloca (cnt * sizeof (*temp));
308   m = 0;
309   for (n = 0; masked != 0; ++n)
310     if ((masked & (1UL << n)) != 0)
311       {
312         temp[m].str = _dl_hwcap_string (n);
313         temp[m].len = strlen (temp[m].str);
314         masked ^= 1UL << n;
315         ++m;
316       }
317   if (platform != NULL)
318     {
319       temp[m].str = platform;
320       temp[m].len = platform_len;
321       ++m;
322     }
323
324   /* Determine the total size of all strings together.  */
325   if (cnt == 1)
326     total = temp[0].len;
327   else
328     {
329       total = (1 << (cnt - 2)) * (temp[0].len + temp[cnt - 1].len + 2);
330       for (n = 1; n + 1 < cnt; ++n)
331         total += (1 << (cnt - 3)) * (temp[n].len + 1);
332     }
333
334   /* The result structure: we use a very compressed way to store the
335      various combinations of capability names.  */
336   *sz = 1 << cnt;
337   result = (struct r_strlenpair *) malloc (*sz * sizeof (*result) + total);
338   if (result == NULL)
339     goto no_memory;
340
341   if (cnt == 1)
342     {
343       result[0].str = (char *) (result + *sz);
344       result[0].len = temp[0].len + 1;
345       result[1].str = (char *) (result + *sz);
346       result[1].len = 0;
347       cp = __mempcpy ((char *) (result + *sz), temp[0].str, temp[0].len);
348       *cp = '/';
349       *sz = 2;
350       *max_capstrlen = result[0].len;
351
352       return result;
353     }
354
355   /* Fill in the information.  This follows the following scheme
356      (indeces from TEMP for four strings):
357         entry #0: 0, 1, 2, 3    binary: 1111
358               #1: 0, 1, 3               1101
359               #2: 0, 2, 3               1011
360               #3: 0, 3                  1001
361      This allows to represent all possible combinations of capability
362      names in the string.  First generate the strings.  */
363   result[1].str = result[0].str = cp = (char *) (result + *sz);
364 #define add(idx) \
365       cp = __mempcpy (__mempcpy (cp, temp[idx].str, temp[idx].len), "/", 1);
366   if (cnt == 2)
367     {
368       add (1);
369       add (0);
370     }
371   else
372     {
373       n = 1 << cnt;
374       do
375         {
376           n -= 2;
377
378           /* We always add the last string.  */
379           add (cnt - 1);
380
381           /* Add the strings which have the bit set in N.  */
382           for (m = cnt - 2; m > 0; --m)
383             if ((n & (1 << m)) != 0)
384               add (m);
385
386           /* Always add the first string.  */
387           add (0);
388         }
389       while (n != 0);
390     }
391 #undef add
392
393   /* Now we are ready to install the string pointers and length.  */
394   for (n = 0; n < (1 << cnt); ++n)
395     result[n].len = 0;
396   n = cnt;
397   do
398     {
399       size_t mask = 1 << --n;
400
401       rp = result;
402       for (m = 1 << cnt; m > 0; ++rp)
403         if ((--m & mask) != 0)
404           rp->len += temp[n].len + 1;
405     }
406   while (n != 0);
407
408   /* The first half of the strings all include the first string.  */
409   n = (1 << cnt) - 2;
410   rp = &result[2];
411   while (n != (1 << (cnt - 1)))
412     {
413       if ((n & 1) != 0)
414         rp[0].str = rp[-2].str + rp[-2].len;
415       else
416         rp[0].str = rp[-1].str;
417       ++rp;
418       --n;
419     }
420
421   /* The second have starts right after the first part of the string of
422      corresponding entry in the first half.  */
423   do
424     {
425       rp[0].str = rp[-(1 << (cnt - 1))].str + temp[cnt - 1].len + 1;
426       ++rp;
427     }
428   while (--n != 0);
429
430   /* The maximum string length.  */
431   *max_capstrlen = result[0].len;
432
433   return result;
434 }