1 /* Operating system support for run-time dynamic linker. Hurd version.
2 Copyright (C) 1995,96,97,98,99,2000,2001 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 Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the 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 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
30 #include <mach/mig_support.h>
31 #include "hurdstartup.h"
32 #include <hurd/lookup.h>
33 #include <hurd/auth.h>
34 #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
;
50 int __libc_enable_secure
;
51 int __libc_multiple_libcs
= 0; /* Defining this here avoids the inclusion
53 /* This variable containts the lowest stack address ever used. */
54 void *__libc_stack_end
;
55 unsigned long int _dl_hwcap_mask
= HWCAP_IMPORTANT
;
58 struct hurd_startup_data
*_dl_hurd_data
;
60 /* Defining these variables here avoids the inclusion of hurdsig.c. */
61 unsigned long int __hurd_sigthread_stack_base
;
62 unsigned long int __hurd_sigthread_stack_end
;
63 unsigned long int *__hurd_sigthread_variables
;
65 /* Defining these variables here avoids the inclusion of init-first.c.
66 We need to provide temporary storage for the per-thread variables
67 of the main user thread here, since it is used for storing the
68 `errno' variable. Note that this information is lost once we
69 relocate the dynamic linker. */
70 static unsigned long int threadvars
[_HURD_THREADVAR_MAX
];
71 unsigned long int __hurd_threadvar_stack_offset
72 = (unsigned long int) &threadvars
;
73 unsigned long int __hurd_threadvar_stack_mask
;
75 /* XXX loser kludge for vm_map kernel bug */
76 static vm_address_t fmha
;
77 static vm_size_t fmhs
;
78 static void unfmh(void){
79 __vm_deallocate(__mach_task_self(),fmha
,fmhs
);}
80 static void fmh(void) {
81 error_t err
;int x
;mach_port_t p
;
82 vm_address_t a
=0x08000000U
,max
=VM_MAX_ADDRESS
;
83 while (!(err
=__vm_region(__mach_task_self(),&a
,&fmhs
,&x
,&x
,&x
,&x
,&p
,&x
))){
84 __mach_port_deallocate(__mach_task_self(),p
);
85 if (a
+fmhs
>=0x80000000U
){
88 if (err
) assert(err
==KERN_NO_SPACE
);
89 if (!fmha
)fmhs
=0;else{
91 err
= __vm_map (__mach_task_self (),
92 &fmha
, fmhs
, 0, 0, MACH_PORT_NULL
, 0, 1,
93 VM_PROT_NONE
, VM_PROT_NONE
, VM_INHERIT_COPY
);
96 /* XXX loser kludge for vm_map kernel bug */
101 _dl_sysdep_start (void **start_argptr
,
102 void (*dl_main
) (const Elf32_Phdr
*phdr
, Elf32_Word phent
,
103 Elf32_Addr
*user_entry
))
105 void go (int *argdata
)
107 extern unsigned int _dl_skip_args
; /* rtld.c */
110 /* Cache the information in various global variables. */
112 _dl_argv
= 1 + (char **) argdata
;
113 _environ
= &_dl_argv
[_dl_argc
+ 1];
114 for (p
= _environ
; *p
++;); /* Skip environ pointers and terminator. */
116 if ((void *) p
== _dl_argv
[0])
118 static struct hurd_startup_data nodata
;
119 _dl_hurd_data
= &nodata
;
120 nodata
.user_entry
= (vm_address_t
) ENTRY_POINT
;
123 _dl_hurd_data
= (void *) p
;
125 __libc_enable_secure
= _dl_hurd_data
->flags
& EXEC_SECURE
;
127 if (_dl_hurd_data
->flags
& EXEC_STACK_ARGS
&&
128 _dl_hurd_data
->user_entry
== 0)
129 _dl_hurd_data
->user_entry
= (vm_address_t
) ENTRY_POINT
;
133 #if 0 /* XXX make this work for real someday... */
134 if (_dl_hurd_data
->user_entry
== (vm_address_t
) ENTRY_POINT
)
135 /* We were invoked as a command, not as the program interpreter.
136 The generic ld.so code supports this: it will parse the args
137 as "ld.so PROGRAM [ARGS...]". For booting the Hurd, we
138 support an additional special syntax:
139 ld.so [-LIBS...] PROGRAM [ARGS...]
140 Each LIBS word consists of "FILENAME=MEMOBJ";
141 for example "-/lib/libc.so=123" says that the contents of
142 /lib/libc.so are found in a memory object whose port name
143 in our task is 123. */
144 while (_dl_argc
> 2 && _dl_argv
[1][0] == '-' && _dl_argv
[1][1] != '-')
146 char *lastslash
, *memobjname
, *p
;
153 p
= _dl_argv
++[1] + 1;
155 memobjname
= strchr (p
, '=');
157 _dl_sysdep_fatal ("Bogus library spec: ", p
, "\n", NULL
);
158 *memobjname
++ = '\0';
160 while (*memobjname
!= '\0')
161 memobj
= (memobj
* 10) + (*memobjname
++ - '0');
163 /* Add a user reference on the memory object port, so we will
164 still have one after _dl_map_object_from_fd calls our
166 err
= __mach_port_mod_refs (__mach_task_self (), memobj
,
167 MACH_PORT_RIGHT_SEND
, +1);
170 lastslash
= strrchr (p
, '/');
171 l
= _dl_map_object_from_fd (lastslash
? lastslash
+ 1 : p
,
172 memobj
, strdup (p
), 0);
174 /* Squirrel away the memory object port where it
175 can be retrieved by the program later. */
176 l
->l_info
[DT_NULL
] = (void *) memobj
;
180 /* Call elf/rtld.c's main program. It will set everything
181 up and leave us to transfer control to USER_ENTRY. */
182 (*dl_main
) ((const Elf32_Phdr
*) _dl_hurd_data
->phdr
,
183 _dl_hurd_data
->phdrsz
/ sizeof (Elf32_Phdr
),
184 &_dl_hurd_data
->user_entry
);
186 /* The call above might screw a few things up.
188 First of all, if _dl_skip_args is nonzero, we are ignoring
189 the first few arguments. However, if we have no Hurd startup
190 data, it is the magical convention that ARGV[0] == P. The
191 startup code in init-first.c will get confused if this is not
192 the case, so we must rearrange things to make it so. We'll
193 overwrite the origional ARGV[0] at P with ARGV[_dl_skip_args].
195 Secondly, if we need to be secure, it removes some dangerous
196 environment variables. If we have no Hurd startup date this
197 changes P (since that's the location after the terminating
198 NULL in the list of environment variables). We do the same
199 thing as in the first case but make sure we recalculate P.
200 If we do have Hurd startup data, we have to move the data
201 such that it starts just after the terminating NULL in the
204 We use memmove, since the locations might overlap. */
205 if (__libc_enable_secure
|| _dl_skip_args
)
209 for (newp
= _environ
; *newp
++;);
211 if (_dl_argv
[-_dl_skip_args
] == (char *) p
)
213 if ((char *) newp
!= _dl_argv
[0])
215 assert ((char *) newp
< _dl_argv
[0]);
216 _dl_argv
[0] = memmove ((char *) newp
, _dl_argv
[0],
217 strlen (_dl_argv
[0]) + 1);
222 if ((void *) newp
!= _dl_hurd_data
)
223 memmove (newp
, _dl_hurd_data
, sizeof (*_dl_hurd_data
));
228 extern void _dl_start_user (void);
229 /* Unwind the stack to ARGDATA and simulate a return from _dl_start
230 to the RTLD_START code which will run the user's entry point. */
231 RETURN_TO (argdata
, &_dl_start_user
, _dl_hurd_data
->user_entry
);
235 /* Set up so we can do RPCs. */
238 /* Initialize frequently used global variable. */
239 _dl_pagesize
= __getpagesize ();
243 /* See hurd/hurdstartup.c; this deals with getting information
244 from the exec server and slicing up the arguments.
245 Then it will call `go', above. */
246 _hurd_startup (start_argptr
, &go
);
254 _dl_sysdep_start_cleanup (void)
256 /* Deallocate the reply port and task port rights acquired by
257 __mach_init. We are done with them now, and the user will
258 reacquire them for himself when he wants them. */
259 __mig_dealloc_reply_port (MACH_PORT_NULL
);
260 __mach_port_deallocate (__mach_task_self (), __mach_task_self_
);
263 /* Minimal open/close/mmap implementation sufficient for initial loading of
264 shared libraries. These are weak definitions so that when the
265 dynamic linker re-relocates itself to be user-visible (for -ldl),
266 it will get the user's definition (i.e. usually libc's). */
268 /* Open FILE_NAME and return a Hurd I/O for it in *PORT, or return an
269 error. If STAT is non-zero, stat the file into that stat buffer. */
271 open_file (const char *file_name
, int flags
,
272 mach_port_t
*port
, struct stat
*stat
)
274 enum retry_type doretry
;
275 char retryname
[1024]; /* XXX string_t LOSES! */
279 error_t
use_init_port (int which
, error_t (*operate
) (file_t
))
281 return (which
< _dl_hurd_data
->portarraysize
282 ? ((*operate
) (_dl_hurd_data
->portarray
[which
]))
285 file_t
get_dtable_port (int fd
)
287 if ((unsigned int) fd
< _dl_hurd_data
->dtablesize
288 && _dl_hurd_data
->dtable
[fd
] != MACH_PORT_NULL
)
290 __mach_port_mod_refs (__mach_task_self (), _dl_hurd_data
->dtable
[fd
],
291 MACH_PORT_RIGHT_SEND
, +1);
292 return _dl_hurd_data
->dtable
[fd
];
295 return MACH_PORT_NULL
;
298 assert (!(flags
& ~O_READ
));
300 startdir
= _dl_hurd_data
->portarray
[file_name
[0] == '/' ?
301 INIT_PORT_CRDIR
: INIT_PORT_CWDIR
];
303 while (file_name
[0] == '/')
306 err
= __dir_lookup (startdir
, (char *)file_name
, O_RDONLY
, 0,
307 &doretry
, retryname
, port
);
310 err
= __hurd_file_name_lookup_retry (use_init_port
, get_dtable_port
,
311 __dir_lookup
, doretry
, retryname
,
315 err
= __io_stat (*port
, stat
);
317 __mach_port_deallocate (__mach_task_self (), *port
);
324 __open (const char *file_name
, int mode
, ...)
327 error_t err
= open_file (file_name
, mode
, &port
, 0);
329 return __hurd_fail (err
);
337 if (fd
!= (int) MACH_PORT_NULL
)
338 __mach_port_deallocate (__mach_task_self (), (mach_port_t
) fd
);
342 __ssize_t weak_function
343 __libc_read (int fd
, void *buf
, size_t nbytes
)
347 mach_msg_type_number_t nread
;
350 err
= __io_read ((mach_port_t
) fd
, &data
, &nread
, -1, nbytes
);
352 return __hurd_fail (err
);
356 memcpy (buf
, data
, nread
);
357 __vm_deallocate (__mach_task_self (), (vm_address_t
) data
, nread
);
363 __ssize_t weak_function
364 __libc_write (int fd
, const void *buf
, size_t nbytes
)
367 mach_msg_type_number_t nwrote
;
369 assert (fd
< _hurd_init_dtablesize
);
371 err
= __io_write (_hurd_init_dtable
[fd
], buf
, nbytes
, -1, &nwrote
);
373 return __hurd_fail (err
);
378 /* This is only used for printing messages (see dl-misc.c). */
379 __ssize_t weak_function
380 __writev (int fd
, const struct iovec
*iov
, int niov
)
384 for (i
= 0; i
< niov
; ++i
)
385 total
+= iov
[i
].iov_len
;
387 assert (fd
< _hurd_init_dtablesize
);
391 char buf
[total
], *bufp
= buf
;
393 mach_msg_type_number_t nwrote
;
395 for (i
= 0; i
< niov
; ++i
)
396 bufp
= (memcpy (bufp
, iov
[i
].iov_base
, iov
[i
].iov_len
)
399 err
= __io_write (_hurd_init_dtable
[fd
], buf
, total
, -1, &nwrote
);
401 return __hurd_fail (err
);
410 __lseek (int fd
, off_t offset
, int whence
)
414 err
= __io_seek ((mach_port_t
) fd
, offset
, whence
, &offset
);
416 return __hurd_fail (err
);
421 __ptr_t weak_function
422 __mmap (__ptr_t addr
, size_t len
, int prot
, int flags
, int fd
, off_t offset
)
426 vm_address_t mapaddr
;
427 mach_port_t memobj_rd
, memobj_wr
;
429 vmprot
= VM_PROT_NONE
;
430 if (prot
& PROT_READ
)
431 vmprot
|= VM_PROT_READ
;
432 if (prot
& PROT_WRITE
)
433 vmprot
|= VM_PROT_WRITE
;
434 if (prot
& PROT_EXEC
)
435 vmprot
|= VM_PROT_EXECUTE
;
437 if (flags
& MAP_ANON
)
438 memobj_rd
= MACH_PORT_NULL
;
441 assert (!(flags
& MAP_SHARED
));
442 err
= __io_map ((mach_port_t
) fd
, &memobj_rd
, &memobj_wr
);
444 return (__ptr_t
) __hurd_fail (err
);
445 __mach_port_deallocate (__mach_task_self (), memobj_wr
);
448 mapaddr
= (vm_address_t
) addr
;
449 err
= __vm_map (__mach_task_self (),
450 &mapaddr
, (vm_size_t
) len
, 0 /*ELF_MACHINE_USER_ADDRESS_MASK*/,
451 !(flags
& MAP_FIXED
),
453 (vm_offset_t
) offset
,
454 flags
& (MAP_COPY
|MAP_PRIVATE
),
456 (flags
& MAP_SHARED
) ? VM_INHERIT_SHARE
: VM_INHERIT_COPY
);
457 if (err
== KERN_NO_SPACE
&& (flags
& MAP_FIXED
))
459 /* XXX this is not atomic as it is in unix! */
460 /* The region is already allocated; deallocate it first. */
461 err
= __vm_deallocate (__mach_task_self (), mapaddr
, len
);
463 err
= __vm_map (__mach_task_self (),
464 &mapaddr
, (vm_size_t
) len
, 0 /*ELF_MACHINE_USER_ADDRESS_MASK*/,
465 !(flags
& MAP_FIXED
),
466 memobj_rd
, (vm_offset_t
) offset
,
467 flags
& (MAP_COPY
|MAP_PRIVATE
),
470 ? VM_INHERIT_SHARE
: VM_INHERIT_COPY
);
473 if ((flags
& MAP_ANON
) == 0)
474 __mach_port_deallocate (__mach_task_self (), memobj_rd
);
476 return err
? (__ptr_t
) __hurd_fail (err
) : (__ptr_t
) mapaddr
;
480 __fxstat (int vers
, int fd
, struct stat
*buf
)
484 assert (vers
== _STAT_VER
);
486 err
= __io_stat ((mach_port_t
) fd
, buf
);
488 return __hurd_fail (err
);
494 __xstat (int vers
, const char *file
, struct stat
*buf
)
499 assert (vers
== _STAT_VER
);
501 err
= open_file (file
, 0, &port
, buf
);
503 return __hurd_fail (err
);
505 __mach_port_deallocate (__mach_task_self (), port
);
510 /* This function is called by the dynamic linker (rtld.c) to check
511 whether debugging malloc is allowed even for SUID binaries. This
512 stub will always fail, which means that malloc-debugging is always
513 disabled for SUID binaries. */
515 __access (const char *file
, int type
)
527 if (__proc_getpids (_dl_hurd_data
->portarray
[INIT_PORT_PROC
],
528 &pid
, &ppid
, &orphaned
))
534 /* This is called only in some strange cases trying to guess a value
535 for $ORIGIN for the executable. The dynamic linker copes with
536 getcwd failing (dl-object.c), and it's too much hassle to include
537 the functionality here. (We could, it just requires duplicating or
538 reusing getcwd.c's code but using our special lookup function as in
542 __getcwd (char *buf
, size_t size
)
551 __proc_mark_exit (_dl_hurd_data
->portarray
[INIT_PORT_PROC
],
552 W_EXITCODE (status
, 0), 0);
553 while (__task_terminate (__mach_task_self ()))
554 __mach_task_self_
= (__mach_task_self
) ();
557 /* Try to get a machine dependent instruction which will make the
558 program crash. This is used in case everything else fails. */
559 #include <abort-instr.h>
560 #ifndef ABORT_INSTRUCTION
561 /* No such instruction is available. */
562 # define ABORT_INSTRUCTION
568 /* Try to abort using the system specific command. */
571 /* If the abort instruction failed, exit. */
574 /* If even this fails, make sure we never return. */
576 /* Try for ever and ever. */
580 /* This function is called by interruptible RPC stubs. For initial
581 dynamic linking, just use the normal mach_msg. Since this defn is
582 weak, the real defn in libc.so will override it if we are linked into
583 the user program (-ldl). */
585 error_t weak_function
586 _hurd_intr_rpc_mach_msg (mach_msg_header_t
*msg
,
587 mach_msg_option_t option
,
588 mach_msg_size_t send_size
,
589 mach_msg_size_t rcv_size
,
590 mach_port_t rcv_name
,
591 mach_msg_timeout_t timeout
,
594 return __mach_msg (msg
, option
, send_size
, rcv_size
, rcv_name
,
603 /* There is nothing to print. Hurd has no auxiliary vector. */
607 /* Return an array of useful/necessary hardware capability names. */
608 const struct r_strlenpair
*
610 _dl_important_hwcaps (const char *platform
, size_t platform_len
, size_t *sz
,
611 size_t *max_capstrlen
)
613 struct r_strlenpair
*result
;
615 /* Return an empty array. Hurd has no hardware capabilities. */
616 result
= (struct r_strlenpair
*) malloc (sizeof (*result
));
618 _dl_signal_error (ENOMEM
, NULL
, NULL
, "cannot create capability list");
620 result
[0].str
= (char *) result
; /* Does not really matter. */
628 _dl_init_first (int argc
, ...)
630 /* This no-op definition only gets used if libc is not linked in. */