Update.
[platform/upstream/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 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 <entry.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <sys/mman.h>
25 #include <fcntl.h>
26 #include <link.h>
27 #include <unistd.h>
28 #include <stdio-common/_itoa.h>
29
30 #include <dl-machine.h>
31
32 extern int _dl_argc;
33 extern char **_dl_argv;
34 extern char **_environ;
35 extern size_t _dl_pagesize;
36 extern const char *_dl_platform;
37 extern unsigned long _dl_hwcap;
38 extern size_t _dl_platformlen;
39 extern void _end;
40 extern void ENTRY_POINT (void);
41
42 ElfW(Addr) _dl_base_addr;
43 uid_t __libc_uid;
44 int __libc_enable_secure;
45 int __libc_multiple_libcs;      /* Defining this here avoids the inclusion
46                                    of init-first.  */
47 static ElfW(auxv_t) *_dl_auxv;
48
49
50 #ifndef DL_FIND_ARG_COMPONENTS
51 #define DL_FIND_ARG_COMPONENTS(cookie, argc, argv, envp, auxp)  \
52   do {                                                          \
53     void **_tmp;                                                \
54     (argc) = *(long *) cookie;                                  \
55     (argv) = (char **) cookie + 1;                              \
56     (envp) = (argv) + (argc) + 1;                               \
57     for (_tmp = (void **) (envp); *_tmp; ++_tmp)                \
58       continue;                                                 \
59     (auxp) = (void *) ++_tmp;                                   \
60   } while (0)
61 #endif
62
63
64 ElfW(Addr)
65 _dl_sysdep_start (void **start_argptr,
66                   void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phnum,
67                                    ElfW(Addr) *user_entry))
68 {
69   const ElfW(Phdr) *phdr = NULL;
70   ElfW(Word) phnum = 0;
71   ElfW(Addr) user_entry;
72   ElfW(auxv_t) *av;
73   uid_t uid = 0;
74   uid_t euid = 0;
75   gid_t gid = 0;
76   gid_t egid = 0;
77   unsigned int seen;
78
79   DL_FIND_ARG_COMPONENTS (start_argptr, _dl_argc, _dl_argv, _environ, _dl_auxv);
80
81   user_entry = (ElfW(Addr)) &ENTRY_POINT;
82   _dl_platform = NULL; /* Default to nothing known about the platform.  */
83
84   seen = 0;
85 #define M(type) (1 << (type))
86
87   for (av = _dl_auxv; av->a_type != AT_NULL; seen |= M ((++av)->a_type))
88     switch (av->a_type)
89       {
90       case AT_PHDR:
91         phdr = av->a_un.a_ptr;
92         break;
93       case AT_PHNUM:
94         phnum = av->a_un.a_val;
95         break;
96       case AT_PAGESZ:
97         _dl_pagesize = av->a_un.a_val;
98         break;
99       case AT_ENTRY:
100         user_entry = av->a_un.a_val;
101         break;
102       case AT_BASE:
103         _dl_base_addr = av->a_un.a_val;
104         break;
105       case AT_UID:
106         uid = av->a_un.a_val;
107         break;
108       case AT_GID:
109         gid = av->a_un.a_val;
110         break;
111       case AT_EUID:
112         euid = av->a_un.a_val;
113         break;
114       case AT_EGID:
115         egid = av->a_un.a_val;
116         break;
117       case AT_PLATFORM:
118         _dl_platform = av->a_un.a_ptr;
119         break;
120       case AT_HWCAP:
121         _dl_hwcap = av->a_un.a_val;
122         break;
123       }
124
125   /* Linux doesn't provide us with any of these values on the stack
126      when the dynamic linker is run directly as a program.  */
127
128 #define SEE(UID, uid) if ((seen & M (AT_##UID)) == 0) uid = __get##uid ()
129   SEE (UID, uid);
130   SEE (GID, gid);
131   SEE (EUID, euid);
132   SEE (EGID, egid);
133
134   __libc_uid = uid;
135   __libc_enable_secure = uid != euid || gid != egid;
136
137   if (_dl_pagesize == 0)
138     _dl_pagesize = __getpagesize ();
139
140 #ifdef DL_SYSDEP_INIT
141   DL_SYSDEP_INIT;
142 #endif
143
144 #ifdef DL_PLATFORM_INIT
145   DL_PLATFORM_INIT;
146 #endif
147
148   /* Determine the length of the platform name.  */
149   if (_dl_platform != NULL)
150     _dl_platformlen = strlen (_dl_platform);
151
152   if (__sbrk (0) == &_end)
153     /* The dynamic linker was run as a program, and so the initial break
154        starts just after our bss, at &_end.  The malloc in dl-minimal.c
155        will consume the rest of this page, so tell the kernel to move the
156        break up that far.  When the user program examines its break, it
157        will see this new value and not clobber our data.  */
158     __sbrk (_dl_pagesize - ((&_end - (void *) 0) & (_dl_pagesize - 1)));
159
160   (*dl_main) (phdr, phnum, &user_entry);
161   return user_entry;
162 }
163
164 void
165 _dl_sysdep_start_cleanup (void)
166 {
167 }
168
169 void
170 _dl_show_auxv (void)
171 {
172   char buf[64];
173   ElfW(auxv_t) *av;
174
175   /* Terminate string.  */
176   buf[63] = '\0';
177
178   for (av = _dl_auxv; av->a_type != AT_NULL; ++av)
179     switch (av->a_type)
180       {
181       case AT_PHDR:
182         _dl_sysdep_message ("AT_PHDR:     0x",
183                             _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
184                                         16, 0),
185                             "\n", NULL);
186         break;
187       case AT_PHNUM:
188         _dl_sysdep_message ("AT_PHNUM:    ",
189                             _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
190                                         10, 0),
191                             "\n", NULL);
192         break;
193       case AT_PAGESZ:
194         _dl_sysdep_message ("AT_PAGESZ:   ",
195                             _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
196                                         10, 0),
197                             "\n", NULL);
198         break;
199       case AT_ENTRY:
200         _dl_sysdep_message ("AT_ENTRY:    0x",
201                             _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
202                                         16, 0),
203                             "\n", NULL);
204         break;
205       case AT_BASE:
206         _dl_sysdep_message ("AT_BASE:    0x",
207                             _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
208                                         16, 0),
209                             "\n", NULL);
210         break;
211       case AT_UID:
212         _dl_sysdep_message ("AT_UID:      ",
213                             _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
214                                         10, 0),
215                             "\n", NULL);
216         break;
217       case AT_GID:
218         _dl_sysdep_message ("AT_GID:      ",
219                             _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
220                                         10, 0),
221                             "\n", NULL);
222         break;
223       case AT_EUID:
224         _dl_sysdep_message ("AT_EUID:     ",
225                             _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
226                                         10, 0),
227                             "\n", NULL);
228         break;
229       case AT_EGID:
230         _dl_sysdep_message ("AT_EGID:     ",
231                             _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
232                                         10, 0),
233                             "\n", NULL);
234         break;
235       case AT_PLATFORM:
236         _dl_sysdep_message ("AT_PLATFORM: ", av->a_un.a_ptr, NULL);
237         break;
238       case AT_HWCAP:
239         _dl_sysdep_message ("AT_HWCAP:    ",
240                             _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
241                                         16, 0),
242                             "\n", NULL);
243         break;
244       }
245 }