]> sourceware.org Git - glibc.git/blame - sysdeps/mach/hurd/dl-sysdep.c
Tue May 30 15:52:32 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
[glibc.git] / sysdeps / mach / hurd / dl-sysdep.c
CommitLineData
99b306dc
RM
1/* Operating system support for run-time dynamic linker. Hurd version.
2Copyright (C) 1995 Free Software Foundation, Inc.
3This file is part of the GNU C Library.
4
5The GNU C Library is free software; you can redistribute it and/or
6modify it under the terms of the GNU Library General Public License as
7published by the Free Software Foundation; either version 2 of the
8License, or (at your option) any later version.
9
10The GNU C Library is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13Library General Public License for more details.
14
15You should have received a copy of the GNU Library General Public
16License along with the GNU C Library; see the file COPYING.LIB. If
17not, write to the Free Software Foundation, Inc., 675 Mass Ave,
18Cambridge, MA 02139, USA. */
19
20#include <hurd.h>
21#include <link.h>
22#include <unistd.h>
23#include <fcntl.h>
24#include <stdlib.h>
25#include <sys/mman.h>
26#include <sys/wait.h>
27#include <assert.h>
28#include <sysdep.h>
29#include <mach/mig_support.h>
30#include "hurdstartup.h"
31#include <mach/host_info.h>
32#include "../stdio/_itoa.h"
33#include <hurd/auth.h>
34#include <hurd/term.h>
35#include <stdarg.h>
36
37#include "dl-machine.h"
38
a1a9d215
RM
39extern void __mach_init (void);
40
99b306dc
RM
41extern int _dl_argc;
42extern char **_dl_argv;
43extern char **_environ;
44
45struct hurd_startup_data *_dl_hurd_data;
46
47Elf32_Addr
48_dl_sysdep_start (void **start_argptr,
49 void (*dl_main) (const Elf32_Phdr *phdr, Elf32_Word phent,
50 Elf32_Addr *user_entry))
51{
52 void go (int *argdata)
53 {
54 char **p;
55
56 /* Cache the information in various global variables. */
a1a9d215
RM
57 _dl_argc = *argdata;
58 _dl_argv = (void *) &argdata[1];
99b306dc
RM
59 _environ = &_dl_argv[_dl_argc + 1];
60 for (p = _environ; *p; ++p);
61 _dl_hurd_data = (void *) ++p;
62
63 _dl_secure = _dl_hurd_data->flags & EXEC_SECURE;
64
65 /* Call elf/rtld.c's main program. It will set everything
66 up and leave us to transfer control to USER_ENTRY. */
67 (*dl_main) ((const Elf32_Phdr *) _dl_hurd_data->phdr,
68 _dl_hurd_data->phdrsz / sizeof (Elf32_Phdr),
69 &_dl_hurd_data->user_entry);
70
a1a9d215
RM
71 /* Deallocate the reply port and task port rights acquired by
72 __mach_init. We are done with them now, and the user will
73 reacquire them for himself when he wants them. */
74 __mig_dealloc_reply_port (MACH_PORT_NULL);
75 __mach_port_deallocate (__mach_task_self (), __mach_task_self_);
76
99b306dc
RM
77 {
78 extern void _dl_start_user (void);
79 /* Unwind the stack to ARGDATA and simulate a return from _dl_start
80 to the RTLD_START code which will run the user's entry point. */
81 RETURN_TO (argdata, &_dl_start_user, _dl_hurd_data->user_entry);
82 }
83 }
84
a1a9d215
RM
85 /* Set up so we can do RPCs. */
86 __mach_init ();
87
99b306dc
RM
88 /* See hurd/hurdstartup.c; this deals with getting information
89 from the exec server and slicing up the arguments.
90 Then it will call `go', above. */
91 _hurd_startup (start_argptr, &go);
92
93 LOSE;
94}
95
96/* This is called when all other dynamic linking is finished, before the
97 dynamic linker re-relocates itself when ld.so itself appears in a
98 DT_NEEDED entry. It is called whether of not ld.so is being linked in.
99
100 We take this opportunity to deallocate the reply port and task-self send
101 right user reference we have acquired, since they will not be used again
102 before the library and user code runs. The C library will acquire its
103 own ports in its initialization. */
104
105void
106_dl_sysdep_prepare_for_ld_reloc (void)
107{
108 __mig_dealloc_reply_port (__mig_get_reply_port ());
109 __mach_port_deallocate (__mach_task_self (), __mach_task_self ());
110}
111\f
112int
113_dl_sysdep_open_zero_fill (void)
114{
115 return (int) MACH_PORT_NULL;
116}
117
118
119void
120_dl_sysdep_fatal (const char *msg, ...)
121{
122 extern __typeof (__io_write) __hurd_intr_rpc_io_write;
123 va_list ap;
124
125 va_start (ap, msg);
126 do
127 {
128 size_t len = strlen (msg);
129 mach_msg_type_number_t nwrote;
130 do
131 {
132 if (__hurd_intr_rpc_io_write (_hurd_init_dtable[2],
133 msg, len, -1, &nwrote))
134 break;
135 len -= nwrote;
136 msg += nwrote;
137 } while (nwrote > 0);
138 msg = va_arg (ap, const char *);
139 } while (msg);
140 va_end (ap);
141
142 _exit (127);
143}
144
145
146/* Minimal open/close/mmap implementation sufficient for initial loading of
147 shared libraries. These are weak definitions so that when the
148 dynamic linker re-relocates itself to be user-visible (for -ldl),
149 it will get the user's definition (i.e. usually libc's). */
150
151int
152open (const char *file_name, int mode, ...)
153{
154 extern __typeof (__dir_lookup) __hurd_intr_rpc_dir_lookup;
155 extern __typeof (__io_reauthenticate) __hurd_intr_rpc_io_reauthenticate;
156 enum retry_type doretry;
157 char retryname[1024]; /* XXX string_t LOSES! */
158 file_t startdir, newpt, fileport;
159 int dealloc_dir;
160 int nloops;
161
162
163 assert (mode == O_RDONLY);
164
165
166 startdir = _dl_hurd_data->portarray[file_name[0] == '/' ?
167 INIT_PORT_CRDIR : INIT_PORT_CWDIR];
168
169 while (file_name[0] == '/')
170 file_name++;
171
172 if (errno = __hurd_intr_rpc_dir_lookup (startdir, file_name, mode, 0,
173 &doretry, retryname, &fileport))
174 return -1;
175
176 dealloc_dir = 0;
177 nloops = 0;
178 errno = 0;
179
180 while (1)
181 {
182 if (dealloc_dir)
183 __mach_port_deallocate (__mach_task_self (), startdir);
184 if (errno)
185 return -1;
186
187 switch (doretry)
188 {
189 case FS_RETRY_REAUTH:
190 {
191 mach_port_t ref = __mach_reply_port ();
192 errno = __hurd_intr_rpc_io_reauthenticate
193 (fileport, ref, MACH_MSG_TYPE_MAKE_SEND);
194 if (! errno)
195 errno = __auth_user_authenticate
196 (_dl_hurd_data->portarray[INIT_PORT_AUTH],
197 fileport,
198 ref, MACH_MSG_TYPE_MAKE_SEND,
199 &newpt);
200 __mach_port_destroy (__mach_task_self (), ref);
201 }
202 __mach_port_deallocate (__mach_task_self (), fileport);
203 if (errno)
204 return -1;
205 fileport = newpt;
206 /* Fall through. */
207
208 case FS_RETRY_NORMAL:
209#ifdef SYMLOOP_MAX
210 if (nloops++ >= SYMLOOP_MAX)
211 {
212 errno = ELOOP;
213 return -1;
214 }
215#endif
216
217 /* An empty RETRYNAME indicates we have the final port. */
218 if (retryname[0] == '\0')
219 {
220 mach_port_t memobj_rd, memobj_wr;
221 extern __typeof (__io_map) __hurd_intr_rpc_io_map;
222
223 dealloc_dir = 1;
224
225 opened:
226 /* We have the file open. Now map it. */
227 errno = __hurd_intr_rpc_io_map (fileport,
228 &memobj_rd, &memobj_wr);
229 if (dealloc_dir)
230 __mach_port_deallocate (__mach_task_self (), fileport);
231 if (errno)
232 return -1;
233 if (memobj_wr != MACH_PORT_NULL)
234 __mach_port_deallocate (__mach_task_self (), memobj_wr);
235
236 return (int) memobj_rd;
237 }
238
239 startdir = fileport;
240 dealloc_dir = 1;
241 file_name = retryname;
242 break;
243
244 case FS_RETRY_MAGICAL:
245 switch (retryname[0])
246 {
247 case '/':
248 startdir = _dl_hurd_data->portarray[INIT_PORT_CRDIR];
249 dealloc_dir = 0;
250 if (fileport != MACH_PORT_NULL)
251 __mach_port_deallocate (__mach_task_self (), fileport);
252 file_name = &retryname[1];
253 break;
254
255 case 'f':
256 if (retryname[1] == 'd' && retryname[2] == '/')
257 {
258 int fd;
259 char *end;
260 errno = 0;
261 fd = (int) strtol (retryname, &end, 10);
262 if (end == NULL || errno || /* Malformed number. */
263 /* Check for excess text after the number. A slash
264 is valid; it ends the component. Anything else
265 does not name a numeric file descriptor. */
266 (*end != '/' && *end != '\0'))
267 {
268 errno = ENOENT;
269 return -1;
270 }
271 if (fd < 0 || fd >= _dl_hurd_data->dtablesize ||
272 _dl_hurd_data->dtable[fd] == MACH_PORT_NULL)
273 {
274 /* If the name was a proper number, but the file
275 descriptor does not exist, we return EBADF instead
276 of ENOENT. */
277 errno = EBADF;
278 return -1;
279 }
280 fileport = _dl_hurd_data->dtable[fd];
281 if (*end == '\0')
282 {
283 /* This descriptor is the file port we want. */
284 dealloc_dir = 0;
285 goto opened;
286 }
287 else
288 {
289 /* Do a normal retry on the remaining components. */
290 startdir = fileport;
291 dealloc_dir = 1;
292 file_name = end + 1; /* Skip the slash. */
293 break;
294 }
295 }
296 else
297 goto bad_magic;
298 break;
299
300 case 'm':
301 if (retryname[1] == 'a' && retryname[2] == 'c' &&
302 retryname[3] == 'h' && retryname[4] == 't' &&
303 retryname[5] == 'y' && retryname[6] == 'p' &&
304 retryname[7] == 'e')
305 {
306 error_t err;
307 struct host_basic_info hostinfo;
308 mach_msg_type_number_t hostinfocnt = HOST_BASIC_INFO_COUNT;
309 char *p;
310 if (err = __host_info (__mach_host_self (), HOST_BASIC_INFO,
311 (natural_t *) &hostinfo,
312 &hostinfocnt))
313 return err;
314 if (hostinfocnt != HOST_BASIC_INFO_COUNT)
315 return EGRATUITOUS;
316 p = _itoa (hostinfo.cpu_subtype, &retryname[8], 10, 0);
317 *--p = '/';
318 p = _itoa (hostinfo.cpu_type, &retryname[8], 10, 0);
319 if (p < retryname)
320 abort (); /* XXX write this right if this ever happens */
321 if (p > retryname)
322 strcpy (retryname, p);
323 startdir = fileport;
324 dealloc_dir = 1;
325 }
326 else
327 goto bad_magic;
328 break;
329
330 case 't':
331 if (retryname[1] == 't' && retryname[2] == 'y')
332 switch (retryname[3])
333 {
334 error_t opentty (file_t *result)
335 {
336 error_t err;
337 file_t unauth;
338 err = __termctty_open_terminal
339 (_dl_hurd_data->portarray[INIT_PORT_CTTYID],
340 mode, &unauth);
341 if (! err)
342 {
343 mach_port_t ref = __mach_reply_port ();
344 err = __hurd_intr_rpc_io_reauthenticate
345 (unauth, ref, MACH_MSG_TYPE_MAKE_SEND);
346 if (! err)
347 err = __auth_user_authenticate
348 (_dl_hurd_data->portarray[INIT_PORT_AUTH],
349 unauth,
350 ref, MACH_MSG_TYPE_MAKE_SEND,
351 result);
352 __mach_port_deallocate (__mach_task_self (),
353 unauth);
354 __mach_port_destroy (__mach_task_self (), ref);
355 }
356 return err;
357 }
358
359 case '\0':
360 if (errno = opentty (&fileport))
361 return -1;
362 dealloc_dir = 1;
363 goto opened;
364 case '/':
365 if (errno = opentty (&startdir))
366 return -1;
367 dealloc_dir = 1;
368 strcpy (retryname, &retryname[4]);
369 break;
370 default:
371 goto bad_magic;
372 }
373 else
374 goto bad_magic;
375 break;
376
377 default:
378 bad_magic:
379 errno = EGRATUITOUS;
380 return -1;
381 }
382 break;
383
384 default:
385 errno = EGRATUITOUS;
386 return -1;
387 }
388
389 errno = __hurd_intr_rpc_dir_lookup (startdir, file_name, mode, 0,
390 &doretry, retryname, &fileport);
391 }
392}
393
394int
395close (int fd)
396{
397 if (fd != (int) MACH_PORT_NULL)
398 __mach_port_deallocate (__mach_task_self (), (mach_port_t) fd);
399 return 0;
400}
401
402caddr_t
403mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
404{
405 vm_prot_t vmprot;
406 vm_address_t mapaddr;
407
408 vmprot = VM_PROT_NONE;
409 if (prot & PROT_READ)
410 vmprot |= VM_PROT_READ;
411 if (prot & PROT_WRITE)
412 vmprot |= VM_PROT_WRITE;
413 if (prot & PROT_EXEC)
414 vmprot |= VM_PROT_EXECUTE;
415
416 mapaddr = (vm_address_t) addr;
417 errno = __vm_map (__mach_task_self (),
418 &mapaddr, (vm_size_t) len, (vm_address_t) 0,
419 !(flags & MAP_FIXED),
420 (mach_port_t) fd, (vm_offset_t) offset,
421 flags & (MAP_COPY|MAP_PRIVATE),
422 vmprot, VM_PROT_ALL,
423 (flags & MAP_INHERIT) ? VM_INHERIT_COPY : VM_INHERIT_NONE);
424 return errno ? (caddr_t) -1 : (caddr_t) mapaddr;
425}
426
427void
428_exit (int status)
429{
430 extern __typeof (__proc_mark_exit) __hurd_intr_rpc_proc_mark_exit;
431 __hurd_intr_rpc_proc_mark_exit (_dl_hurd_data->portarray[INIT_PORT_PROC],
432 W_EXITCODE (status, 0));
433 while (__task_terminate (__mach_task_self ()))
434 __mach_task_self_ = (__mach_task_self) ();
435}
436
437weak_symbol (_exit)
438weak_symbol (open)
439weak_symbol (close)
440weak_symbol (mmap)
441\f
442/* Minimal `malloc' allocator for use while loading shared libraries.
443 Only small blocks are allocated, and none are ever freed. */
444
445void *
446malloc (size_t n)
447{
448 static vm_address_t ptr, end;
449 void *block;
450
451 if (end == 0)
452 {
453 /* Consume any unused space in the last page of our data segment. */
454 extern char _end;
455 ptr = (vm_address_t) &_end;
456 end = round_page (ptr);
457 }
458
459 /* Make sure the allocation pointer is ideally aligned. */
460 ptr += sizeof (double) - 1;
461 ptr &= ~(sizeof (double) - 1);
462
463 if (ptr + n >= end)
464 {
465 /* Insufficient space left; allocate another page. */
466 vm_address_t page;
467 assert (n <= __vm_page_size);
468 __vm_allocate (__mach_task_self (), &page, __vm_page_size, 1);
469 if (page != end)
470 ptr = page;
471 end = page + __vm_page_size;
472 }
473
474 block = (void *) ptr;
475 ptr += n;
476 return block;
477}
478
479weak_symbol (malloc)
480
481/* These should never be called. */
482void *realloc (void *ptr, size_t n) { ptr += n; abort (); }
483void free (void *ptr) { ptr = ptr; abort (); }
484weak_symbol (realloc)
485weak_symbol (free)
486\f
487/* Avoid signal frobnication in setjmp/longjmp. */
488
489int __sigjmp_save (sigjmp_buf env, int savemask)
490{ env[0].__mask_was_saved = savemask; return 0; }
491weak_symbol (__sigjmp_save)
492
493void
494longjmp (jmp_buf env, int val) { __longjmp (env[0].__jmpbuf, val); }
495weak_symbol (longjmp)
496
497
498/* Stub out this function that is called by interruptible RPC stubs. It
499 should never get called during initial dynamic linking, because we use
500 only the raw MiG stub functions __hurd_intr_rpc_*. Since this defn is
501 weak, the real defn in libc.so will override it if we are linked into
502 the user program (-ldl). */
503struct hurd_sigstate *
504_hurd_thread_sigstate (thread_t thread) { thread = thread; abort (); }
505weak_symbol (_hurd_thread_sigstate)
This page took 0.07411 seconds and 5 git commands to generate.