1 /* Operating system support for run-time dynamic linker. Hurd version.
2 Copyright (C) 1995, 96, 97, 98, 99 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 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.
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.
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. */
26 #include <elf/ldsodefs.h>
30 #include <mach/mig_support.h>
31 #include "hurdstartup.h"
32 #include <mach/host_info.h>
33 #include <stdio-common/_itoa.h>
34 #include <hurd/auth.h>
35 #include <hurd/term.h>
41 #include <dl-machine.h>
42 #include <dl-procinfo.h>
44 extern void __mach_init (void);
47 extern char **_dl_argv
;
48 extern char **_environ
;
49 extern void ENTRY_POINT (void);
51 int __libc_enable_secure
;
52 int __libc_multiple_libcs
; /* Defining this here avoids the inclusion
54 /* This variable containts the lowest stack address ever used. */
55 void *__libc_stack_end
;
56 unsigned long int _dl_hwcap_mask
= HWCAP_IMPORTANT
;
59 struct hurd_startup_data
*_dl_hurd_data
;
61 /* Defining these variables here avoids the inclusion of hurdsig.c. */
62 unsigned long int __hurd_sigthread_stack_base
;
63 unsigned long int __hurd_sigthread_stack_end
;
64 unsigned long int *__hurd_sigthread_variables
;
66 /* Defining these variables here avoids the inclusion of init-first.c.
67 We need to provide temporary storage for the per-thread variables
68 of the main user thread here, since it is used for storing the
69 `errno' variable. Note that this information is lost once we
70 relocate the dynamic linker. */
71 static unsigned long int threadvars
[_HURD_THREADVAR_MAX
];
72 unsigned long int __hurd_threadvar_stack_offset
73 = (unsigned long int) &threadvars
;
74 unsigned long int __hurd_threadvar_stack_mask
;
76 /* XXX loser kludge for vm_map kernel bug */
77 static vm_address_t fmha
;
78 static vm_size_t fmhs
;
79 static void unfmh(void){
80 __vm_deallocate(__mach_task_self(),fmha
,fmhs
);}
81 static void fmh(void) {
82 error_t err
;int x
;mach_port_t p
;
83 vm_address_t a
=0x08000000U
,max
=VM_MAX_ADDRESS
;
84 while (!(err
=__vm_region(__mach_task_self(),&a
,&fmhs
,&x
,&x
,&x
,&x
,&p
,&x
))){
85 __mach_port_deallocate(__mach_task_self(),p
);
86 if (a
+fmhs
>=0x80000000U
){
89 if (err
) assert(err
==KERN_NO_SPACE
);
90 if (!fmha
)fmhs
=0;else{
92 err
= __vm_map (__mach_task_self (),
93 &fmha
, fmhs
, 0, 0, MACH_PORT_NULL
, 0, 1,
94 VM_PROT_NONE
, VM_PROT_NONE
, VM_INHERIT_COPY
);
97 /* XXX loser kludge for vm_map kernel bug */
102 _dl_sysdep_start (void **start_argptr
,
103 void (*dl_main
) (const Elf32_Phdr
*phdr
, Elf32_Word phent
,
104 Elf32_Addr
*user_entry
))
106 void go (int *argdata
)
108 extern unsigned int _dl_skip_args
; /* rtld.c */
111 /* Cache the information in various global variables. */
113 _dl_argv
= 1 + (char **) argdata
;
114 _environ
= &_dl_argv
[_dl_argc
+ 1];
115 for (p
= _environ
; *p
++;); /* Skip environ pointers and terminator. */
117 if ((void *) p
== _dl_argv
[0])
119 static struct hurd_startup_data nodata
;
120 _dl_hurd_data
= &nodata
;
121 nodata
.user_entry
= (vm_address_t
) &ENTRY_POINT
;
124 _dl_hurd_data
= (void *) p
;
126 __libc_enable_secure
= _dl_hurd_data
->flags
& EXEC_SECURE
;
128 if (_dl_hurd_data
->flags
& EXEC_STACK_ARGS
&&
129 _dl_hurd_data
->user_entry
== 0)
130 _dl_hurd_data
->user_entry
= (vm_address_t
) &ENTRY_POINT
;
134 #if 0 /* XXX make this work for real someday... */
135 if (_dl_hurd_data
->user_entry
== (vm_address_t
) &ENTRY_POINT
)
136 /* We were invoked as a command, not as the program interpreter.
137 The generic ld.so code supports this: it will parse the args
138 as "ld.so PROGRAM [ARGS...]". For booting the Hurd, we
139 support an additional special syntax:
140 ld.so [-LIBS...] PROGRAM [ARGS...]
141 Each LIBS word consists of "FILENAME=MEMOBJ";
142 for example "-/lib/libc.so=123" says that the contents of
143 /lib/libc.so are found in a memory object whose port name
144 in our task is 123. */
145 while (_dl_argc
> 2 && _dl_argv
[1][0] == '-' && _dl_argv
[1][1] != '-')
147 char *lastslash
, *memobjname
, *p
;
154 p
= _dl_argv
++[1] + 1;
156 memobjname
= strchr (p
, '=');
158 _dl_sysdep_fatal ("Bogus library spec: ", p
, "\n", NULL
);
159 *memobjname
++ = '\0';
161 while (*memobjname
!= '\0')
162 memobj
= (memobj
* 10) + (*memobjname
++ - '0');
164 /* Add a user reference on the memory object port, so we will
165 still have one after _dl_map_object_from_fd calls our
167 err
= __mach_port_mod_refs (__mach_task_self (), memobj
,
168 MACH_PORT_RIGHT_SEND
, +1);
171 lastslash
= strrchr (p
, '/');
172 l
= _dl_map_object_from_fd (lastslash
? lastslash
+ 1 : p
,
175 /* Squirrel away the memory object port where it
176 can be retrieved by the program later. */
177 l
->l_info
[DT_NULL
] = (void *) memobj
;
181 /* Call elf/rtld.c's main program. It will set everything
182 up and leave us to transfer control to USER_ENTRY. */
183 (*dl_main
) ((const Elf32_Phdr
*) _dl_hurd_data
->phdr
,
184 _dl_hurd_data
->phdrsz
/ sizeof (Elf32_Phdr
),
185 &_dl_hurd_data
->user_entry
);
187 if (_dl_skip_args
&& _dl_argv
[-_dl_skip_args
] == (char *) p
)
189 /* We are ignoring the first few arguments, but we have no Hurd
190 startup data. It is magical convention that ARGV[0] == P in
191 this case. The startup code in init-first.c will get confused
192 if this is not the case, so we must rearrange things to make
193 it so. Overwrite the original ARGV[0] at P with
194 ARGV[_dl_skip_args]. */
195 assert ((char *) p
< _dl_argv
[0]);
196 _dl_argv
[0] = strcpy ((char *) p
, _dl_argv
[0]);
200 extern void _dl_start_user (void);
201 /* Unwind the stack to ARGDATA and simulate a return from _dl_start
202 to the RTLD_START code which will run the user's entry point. */
203 RETURN_TO (argdata
, &_dl_start_user
, _dl_hurd_data
->user_entry
);
207 /* Set up so we can do RPCs. */
210 /* Initialize frequently used global variable. */
211 _dl_pagesize
= __getpagesize ();
215 /* See hurd/hurdstartup.c; this deals with getting information
216 from the exec server and slicing up the arguments.
217 Then it will call `go', above. */
218 _hurd_startup (start_argptr
, &go
);
225 _dl_sysdep_start_cleanup (void)
227 /* Deallocate the reply port and task port rights acquired by
228 __mach_init. We are done with them now, and the user will
229 reacquire them for himself when he wants them. */
230 __mig_dealloc_reply_port (MACH_PORT_NULL
);
231 __mach_port_deallocate (__mach_task_self (), __mach_task_self_
);
234 /* Minimal open/close/mmap implementation sufficient for initial loading of
235 shared libraries. These are weak definitions so that when the
236 dynamic linker re-relocates itself to be user-visible (for -ldl),
237 it will get the user's definition (i.e. usually libc's). */
239 /* Open FILE_NAME and return a Hurd I/O for it in *PORT, or
240 return an error. If STAT is non-zero, stat the file into that stat buffer. */
242 open_file (const char *file_name
, int mode
,
243 mach_port_t
*port
, struct stat
*stat
)
245 enum retry_type doretry
;
246 char retryname
[1024]; /* XXX string_t LOSES! */
247 file_t startdir
, newpt
, fileport
;
252 assert (!(mode
& ~O_READ
));
254 startdir
= _dl_hurd_data
->portarray
[file_name
[0] == '/' ?
255 INIT_PORT_CRDIR
: INIT_PORT_CWDIR
];
257 while (file_name
[0] == '/')
260 if (err
= __dir_lookup (startdir
, (char *)file_name
, mode
, 0,
261 &doretry
, retryname
, &fileport
))
270 __mach_port_deallocate (__mach_task_self (), startdir
);
276 case FS_RETRY_REAUTH
:
278 mach_port_t ref
= __mach_reply_port ();
279 err
= __io_reauthenticate (fileport
, ref
, MACH_MSG_TYPE_MAKE_SEND
);
281 err
= __auth_user_authenticate
282 (_dl_hurd_data
->portarray
[INIT_PORT_AUTH
],
283 ref
, MACH_MSG_TYPE_MAKE_SEND
,
285 __mach_port_destroy (__mach_task_self (), ref
);
287 __mach_port_deallocate (__mach_task_self (), fileport
);
293 case FS_RETRY_NORMAL
:
295 if (nloops
++ >= SYMLOOP_MAX
)
299 /* An empty RETRYNAME indicates we have the final port. */
300 if (retryname
[0] == '\0')
304 /* We have the file open. Now map it. */
306 err
= __io_stat (fileport
, stat
);
311 __mach_port_deallocate (__mach_task_self (), fileport
);
316 __mach_port_mod_refs (__mach_task_self (), fileport
,
317 MACH_PORT_RIGHT_SEND
, 1);
326 file_name
= retryname
;
329 case FS_RETRY_MAGICAL
:
330 switch (retryname
[0])
333 startdir
= _dl_hurd_data
->portarray
[INIT_PORT_CRDIR
];
335 if (fileport
!= MACH_PORT_NULL
)
336 __mach_port_deallocate (__mach_task_self (), fileport
);
337 file_name
= &retryname
[1];
341 if (retryname
[1] == 'd' && retryname
[2] == '/' &&
342 isdigit (retryname
[3]))
344 /* We can't use strtol for the decoding here
345 because it brings in hairy locale bloat. */
348 for (p
= &retryname
[3]; isdigit (*p
); ++p
)
349 fd
= (fd
* 10) + (*p
- '0');
350 /* Check for excess text after the number. A slash is
351 valid; it ends the component. Anything else does not
352 name a numeric file descriptor. */
353 if (*p
!= '/' && *p
!= '\0')
355 if (fd
< 0 || fd
>= _dl_hurd_data
->dtablesize
||
356 _dl_hurd_data
->dtable
[fd
] == MACH_PORT_NULL
)
357 /* If the name was a proper number, but the file
358 descriptor does not exist, we return EBADF instead
361 fileport
= _dl_hurd_data
->dtable
[fd
];
364 /* This descriptor is the file port we want. */
370 /* Do a normal retry on the remaining components. */
373 file_name
= p
+ 1; /* Skip the slash. */
382 if (retryname
[1] == 'a' && retryname
[2] == 'c' &&
383 retryname
[3] == 'h' && retryname
[4] == 't' &&
384 retryname
[5] == 'y' && retryname
[6] == 'p' &&
388 struct host_basic_info hostinfo
;
389 mach_msg_type_number_t hostinfocnt
= HOST_BASIC_INFO_COUNT
;
391 if (err
= __host_info (__mach_host_self (), HOST_BASIC_INFO
,
392 (natural_t
*) &hostinfo
,
395 if (hostinfocnt
!= HOST_BASIC_INFO_COUNT
)
397 p
= _itoa (hostinfo
.cpu_subtype
, &retryname
[8], 10, 0);
399 p
= _itoa (hostinfo
.cpu_type
, &retryname
[8], 10, 0);
401 abort (); /* XXX write this right if this ever happens */
403 strcpy (retryname
, p
);
412 if (retryname
[1] == 't' && retryname
[2] == 'y')
413 switch (retryname
[3])
415 error_t
opentty (file_t
*result
)
419 err
= __termctty_open_terminal
420 (_dl_hurd_data
->portarray
[INIT_PORT_CTTYID
],
424 mach_port_t ref
= __mach_reply_port ();
425 err
= __io_reauthenticate
426 (unauth
, ref
, MACH_MSG_TYPE_MAKE_SEND
);
428 err
= __auth_user_authenticate
429 (_dl_hurd_data
->portarray
[INIT_PORT_AUTH
],
430 ref
, MACH_MSG_TYPE_MAKE_SEND
,
432 __mach_port_deallocate (__mach_task_self (),
434 __mach_port_destroy (__mach_task_self (), ref
);
440 if (err
= opentty (&fileport
))
445 if (err
= opentty (&startdir
))
448 strcpy (retryname
, &retryname
[4]);
467 err
= __dir_lookup (startdir
, (char *)file_name
, mode
, 0,
468 &doretry
, retryname
, &fileport
);
473 __open (const char *file_name
, int mode
, ...)
476 error_t err
= open_file (file_name
, mode
, &port
, 0);
478 return __hurd_fail (err
);
486 if (fd
!= (int) MACH_PORT_NULL
)
487 __mach_port_deallocate (__mach_task_self (), (mach_port_t
) fd
);
491 __ssize_t weak_function
492 __libc_read (int fd
, void *buf
, size_t nbytes
)
496 mach_msg_type_number_t nread
;
499 err
= __io_read ((mach_port_t
) fd
, &data
, &nread
, -1, nbytes
);
501 return __hurd_fail (err
);
505 memcpy (buf
, data
, nread
);
506 __vm_deallocate (__mach_task_self (), (vm_address_t
) data
, nread
);
512 __ssize_t weak_function
513 __libc_write (int fd
, const void *buf
, size_t nbytes
)
516 mach_msg_type_number_t nwrote
;
518 assert (fd
< _hurd_init_dtablesize
);
520 err
= __io_write (_hurd_init_dtable
[fd
], buf
, nbytes
, -1, &nwrote
);
522 return __hurd_fail (err
);
528 __lseek (int fd
, off_t offset
, int whence
)
532 err
= __io_seek ((mach_port_t
) fd
, offset
, whence
, &offset
);
534 return __hurd_fail (err
);
539 __ptr_t weak_function
540 __mmap (__ptr_t addr
, size_t len
, int prot
, int flags
, int fd
, off_t offset
)
544 vm_address_t mapaddr
;
545 mach_port_t memobj_rd
, memobj_wr
;
547 vmprot
= VM_PROT_NONE
;
548 if (prot
& PROT_READ
)
549 vmprot
|= VM_PROT_READ
;
550 if (prot
& PROT_WRITE
)
551 vmprot
|= VM_PROT_WRITE
;
552 if (prot
& PROT_EXEC
)
553 vmprot
|= VM_PROT_EXECUTE
;
555 if (flags
& MAP_ANON
)
556 memobj_rd
= MACH_PORT_NULL
;
559 assert (!(flags
& MAP_SHARED
));
560 err
= __io_map ((mach_port_t
) fd
, &memobj_rd
, &memobj_wr
);
562 return (__ptr_t
) __hurd_fail (err
);
563 __mach_port_deallocate (__mach_task_self (), memobj_wr
);
566 mapaddr
= (vm_address_t
) addr
;
567 err
= __vm_map (__mach_task_self (),
568 &mapaddr
, (vm_size_t
) len
, 0 /*ELF_MACHINE_USER_ADDRESS_MASK*/,
569 !(flags
& MAP_FIXED
),
571 (vm_offset_t
) offset
,
572 flags
& (MAP_COPY
|MAP_PRIVATE
),
574 (flags
& MAP_SHARED
) ? VM_INHERIT_SHARE
: VM_INHERIT_COPY
);
575 if (err
== KERN_NO_SPACE
&& (flags
& MAP_FIXED
))
577 /* XXX this is not atomic as it is in unix! */
578 /* The region is already allocated; deallocate it first. */
579 err
= __vm_deallocate (__mach_task_self (), mapaddr
, len
);
581 err
= __vm_map (__mach_task_self (),
582 &mapaddr
, (vm_size_t
) len
, 0 /*ELF_MACHINE_USER_ADDRESS_MASK*/,
583 !(flags
& MAP_FIXED
),
584 memobj_rd
, (vm_offset_t
) offset
,
585 flags
& (MAP_COPY
|MAP_PRIVATE
),
588 ? VM_INHERIT_SHARE
: VM_INHERIT_COPY
);
591 if ((flags
& MAP_ANON
) == 0)
592 __mach_port_deallocate (__mach_task_self (), memobj_rd
);
594 return err
? (__ptr_t
) __hurd_fail (err
) : (__ptr_t
) mapaddr
;
598 __fxstat (int vers
, int fd
, struct stat
*buf
)
602 assert (vers
== _STAT_VER
);
604 err
= __io_stat ((mach_port_t
) fd
, buf
);
606 return __hurd_fail (err
);
612 __xstat (int vers
, const char *file
, struct stat
*buf
)
617 assert (vers
== _STAT_VER
);
619 err
= open_file (file
, 0, &port
, buf
);
621 return __hurd_fail (err
);
623 __mach_port_deallocate (__mach_task_self (), port
);
634 if (__proc_getpids (_dl_hurd_data
->portarray
[INIT_PORT_PROC
],
635 &pid
, &ppid
, &orphaned
))
641 /* This is called only in some strange cases trying to guess a value
642 for $ORIGIN for the executable. The dynamic linker copes with
643 getcwd failing (dl-object.c), and it's too much hassle to include
644 the functionality here. (We could, it just requires duplicating or
645 reusing getcwd.c's code but using our special lookup function as in
649 __getcwd (char *buf
, size_t size
)
658 __proc_mark_exit (_dl_hurd_data
->portarray
[INIT_PORT_PROC
],
659 W_EXITCODE (status
, 0), 0);
660 while (__task_terminate (__mach_task_self ()))
661 __mach_task_self_
= (__mach_task_self
) ();
664 /* Try to get a machine dependent instruction which will make the
665 program crash. This is used in case everything else fails. */
666 #include <abort-instr.h>
667 #ifndef ABORT_INSTRUCTION
668 /* No such instruction is available. */
669 # define ABORT_INSTRUCTION
675 /* Try to abort using the system specific command. */
678 /* If the abort instruction failed, exit. */
681 /* If even this fails, make sure we never return. */
683 /* Try for ever and ever. */
687 /* This function is called by interruptible RPC stubs. For initial
688 dynamic linking, just use the normal mach_msg. Since this defn is
689 weak, the real defn in libc.so will override it if we are linked into
690 the user program (-ldl). */
692 error_t weak_function
693 _hurd_intr_rpc_mach_msg (mach_msg_header_t
*msg
,
694 mach_msg_option_t option
,
695 mach_msg_size_t send_size
,
696 mach_msg_size_t rcv_size
,
697 mach_port_t rcv_name
,
698 mach_msg_timeout_t timeout
,
701 return __mach_msg (msg
, option
, send_size
, rcv_size
, rcv_name
,
710 /* There is nothing to print. Hurd has no auxiliary vector. */
714 /* Return an array of useful/necessary hardware capability names. */
715 const struct r_strlenpair
*
717 _dl_important_hwcaps (const char *platform
, size_t platform_len
, size_t *sz
,
718 size_t *max_capstrlen
)
720 struct r_strlenpair
*result
;
722 /* Return an empty array. Hurd has no hardware capabilities. */
723 result
= (struct r_strlenpair
*) malloc (sizeof (*result
));
725 _dl_signal_error (ENOMEM
, NULL
, "cannot create capability list");
727 result
[0].str
= (char *) result
; /* Does not really matter. */