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