1 /* Operating system support for run-time dynamic linker. Hurd version.
2 Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2010
3 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
31 #include <mach/mig_support.h>
32 #include "hurdstartup.h"
33 #include <hurd/lookup.h>
34 #include <hurd/auth.h>
35 #include <hurd/term.h>
42 #include <dl-machine.h>
43 #include <dl-procinfo.h>
45 extern void __mach_init (void);
48 extern char **_dl_argv
;
49 extern char **_environ
;
51 int __libc_enable_secure
= 0;
52 INTVARDEF(__libc_enable_secure
)
53 int __libc_multiple_libcs
= 0; /* Defining this here avoids the inclusion
55 /* This variable containts the lowest stack address ever used. */
56 void *__libc_stack_end
;
59 hp_timing_t _dl_cpuclock_offset
;
63 struct hurd_startup_data
*_dl_hurd_data
;
65 /* This is used only within ld.so, via dl-minimal.c's __errno_location. */
67 int errno attribute_hidden
;
69 /* Defining these variables here avoids the inclusion of hurdsig.c. */
70 unsigned long int __hurd_sigthread_stack_base
;
71 unsigned long int __hurd_sigthread_stack_end
;
72 unsigned long int *__hurd_sigthread_variables
;
74 /* Defining these variables here avoids the inclusion of init-first.c.
75 We need to provide temporary storage for the per-thread variables
76 of the main user thread here, since it is used for storing the
77 `errno' variable. Note that this information is lost once we
78 relocate the dynamic linker. */
79 static unsigned long int threadvars
[_HURD_THREADVAR_MAX
];
80 unsigned long int __hurd_threadvar_stack_offset
81 = (unsigned long int) &threadvars
;
82 unsigned long int __hurd_threadvar_stack_mask
;
84 #define FMH defined(__i386__)
86 # define fmh() ((void)0)
87 # define unfmh() ((void)0)
89 /* XXX loser kludge for vm_map kernel bug */
90 #undef ELF_MACHINE_USER_ADDRESS_MASK
91 #define ELF_MACHINE_USER_ADDRESS_MASK 0
92 static vm_address_t fmha
;
93 static vm_size_t fmhs
;
94 static void unfmh(void){
95 __vm_deallocate(__mach_task_self(),fmha
,fmhs
);}
96 static void fmh(void) {
97 error_t err
;int x
;mach_port_t p
;
98 vm_address_t a
=0x08000000U
,max
=VM_MAX_ADDRESS
;
99 while (!(err
=__vm_region(__mach_task_self(),&a
,&fmhs
,&x
,&x
,&x
,&x
,&p
,&x
))){
100 __mach_port_deallocate(__mach_task_self(),p
);
101 if (a
+fmhs
>=0x80000000U
){
104 if (err
) assert(err
==KERN_NO_SPACE
);
105 if (!fmha
)fmhs
=0;else{
107 err
= __vm_map (__mach_task_self (),
108 &fmha
, fmhs
, 0, 0, MACH_PORT_NULL
, 0, 1,
109 VM_PROT_NONE
, VM_PROT_NONE
, VM_INHERIT_COPY
);
112 /* XXX loser kludge for vm_map kernel bug */
117 _dl_sysdep_start (void **start_argptr
,
118 void (*dl_main
) (const ElfW(Phdr
) *phdr
, ElfW(Word
) phent
,
119 ElfW(Addr
) *user_entry
,
120 ElfW(auxv_t
) *auxv
)))
122 void go (intptr_t *argdata
)
124 extern unsigned int _dl_skip_args
; /* rtld.c */
127 /* Cache the information in various global variables. */
129 _dl_argv
= 1 + (char **) argdata
;
130 _environ
= &_dl_argv
[_dl_argc
+ 1];
131 for (p
= _environ
; *p
++;); /* Skip environ pointers and terminator. */
133 if ((void *) p
== _dl_argv
[0])
135 static struct hurd_startup_data nodata
;
136 _dl_hurd_data
= &nodata
;
137 nodata
.user_entry
= (vm_address_t
) ENTRY_POINT
;
140 _dl_hurd_data
= (void *) p
;
142 INTUSE(__libc_enable_secure
) = _dl_hurd_data
->flags
& EXEC_SECURE
;
144 if (_dl_hurd_data
->flags
& EXEC_STACK_ARGS
&&
145 _dl_hurd_data
->user_entry
== 0)
146 _dl_hurd_data
->user_entry
= (vm_address_t
) ENTRY_POINT
;
150 #if 0 /* XXX make this work for real someday... */
151 if (_dl_hurd_data
->user_entry
== (vm_address_t
) ENTRY_POINT
)
152 /* We were invoked as a command, not as the program interpreter.
153 The generic ld.so code supports this: it will parse the args
154 as "ld.so PROGRAM [ARGS...]". For booting the Hurd, we
155 support an additional special syntax:
156 ld.so [-LIBS...] PROGRAM [ARGS...]
157 Each LIBS word consists of "FILENAME=MEMOBJ";
158 for example "-/lib/libc.so=123" says that the contents of
159 /lib/libc.so are found in a memory object whose port name
160 in our task is 123. */
161 while (_dl_argc
> 2 && _dl_argv
[1][0] == '-' && _dl_argv
[1][1] != '-')
163 char *lastslash
, *memobjname
, *p
;
170 p
= _dl_argv
++[1] + 1;
172 memobjname
= strchr (p
, '=');
174 _dl_sysdep_fatal ("Bogus library spec: ", p
, "\n", NULL
);
175 *memobjname
++ = '\0';
177 while (*memobjname
!= '\0')
178 memobj
= (memobj
* 10) + (*memobjname
++ - '0');
180 /* Add a user reference on the memory object port, so we will
181 still have one after _dl_map_object_from_fd calls our
183 err
= __mach_port_mod_refs (__mach_task_self (), memobj
,
184 MACH_PORT_RIGHT_SEND
, +1);
187 lastslash
= strrchr (p
, '/');
188 l
= _dl_map_object_from_fd (lastslash
? lastslash
+ 1 : p
,
189 memobj
, strdup (p
), 0);
191 /* Squirrel away the memory object port where it
192 can be retrieved by the program later. */
193 l
->l_info
[DT_NULL
] = (void *) memobj
;
197 /* Call elf/rtld.c's main program. It will set everything
198 up and leave us to transfer control to USER_ENTRY. */
199 (*dl_main
) ((const ElfW(Phdr
) *) _dl_hurd_data
->phdr
,
200 _dl_hurd_data
->phdrsz
/ sizeof (ElfW(Phdr
)),
201 &_dl_hurd_data
->user_entry
, NULLy
);
203 /* The call above might screw a few things up.
205 First of all, if _dl_skip_args is nonzero, we are ignoring
206 the first few arguments. However, if we have no Hurd startup
207 data, it is the magical convention that ARGV[0] == P. The
208 startup code in init-first.c will get confused if this is not
209 the case, so we must rearrange things to make it so. We'll
210 overwrite the origional ARGV[0] at P with ARGV[_dl_skip_args].
212 Secondly, if we need to be secure, it removes some dangerous
213 environment variables. If we have no Hurd startup date this
214 changes P (since that's the location after the terminating
215 NULL in the list of environment variables). We do the same
216 thing as in the first case but make sure we recalculate P.
217 If we do have Hurd startup data, we have to move the data
218 such that it starts just after the terminating NULL in the
221 We use memmove, since the locations might overlap. */
222 if (INTUSE(__libc_enable_secure
) || _dl_skip_args
)
226 for (newp
= _environ
; *newp
++;);
228 if (_dl_argv
[-_dl_skip_args
] == (char *) p
)
230 if ((char *) newp
!= _dl_argv
[0])
232 assert ((char *) newp
< _dl_argv
[0]);
233 _dl_argv
[0] = memmove ((char *) newp
, _dl_argv
[0],
234 strlen (_dl_argv
[0]) + 1);
239 if ((void *) newp
!= _dl_hurd_data
)
240 memmove (newp
, _dl_hurd_data
, sizeof (*_dl_hurd_data
));
245 extern void _dl_start_user (void);
246 /* Unwind the stack to ARGDATA and simulate a return from _dl_start
247 to the RTLD_START code which will run the user's entry point. */
248 RETURN_TO (argdata
, &_dl_start_user
, _dl_hurd_data
->user_entry
);
252 /* Set up so we can do RPCs. */
255 /* Initialize frequently used global variable. */
256 GLRO(dl_pagesize
) = __getpagesize ();
259 HP_TIMING_NOW (_dl_cpuclock_offset
);
264 /* See hurd/hurdstartup.c; this deals with getting information
265 from the exec server and slicing up the arguments.
266 Then it will call `go', above. */
267 _hurd_startup (start_argptr
, &go
);
275 _dl_sysdep_start_cleanup (void)
277 /* Deallocate the reply port and task port rights acquired by
278 __mach_init. We are done with them now, and the user will
279 reacquire them for himself when he wants them. */
280 __mig_dealloc_reply_port (MACH_PORT_NULL
);
281 __mach_port_deallocate (__mach_task_self (), __mach_task_self_
);
284 /* Minimal open/close/mmap implementation sufficient for initial loading of
285 shared libraries. These are weak definitions so that when the
286 dynamic linker re-relocates itself to be user-visible (for -ldl),
287 it will get the user's definition (i.e. usually libc's). */
289 /* Open FILE_NAME and return a Hurd I/O for it in *PORT, or return an
290 error. If STAT is non-zero, stat the file into that stat buffer. */
292 open_file (const char *file_name
, int flags
,
293 mach_port_t
*port
, struct stat64
*stat
)
295 enum retry_type doretry
;
296 char retryname
[1024]; /* XXX string_t LOSES! */
300 error_t
use_init_port (int which
, error_t (*operate
) (file_t
))
302 return (which
< _dl_hurd_data
->portarraysize
303 ? ((*operate
) (_dl_hurd_data
->portarray
[which
]))
306 file_t
get_dtable_port (int fd
)
308 if ((unsigned int) fd
< _dl_hurd_data
->dtablesize
309 && _dl_hurd_data
->dtable
[fd
] != MACH_PORT_NULL
)
311 __mach_port_mod_refs (__mach_task_self (), _dl_hurd_data
->dtable
[fd
],
312 MACH_PORT_RIGHT_SEND
, +1);
313 return _dl_hurd_data
->dtable
[fd
];
316 return MACH_PORT_NULL
;
319 assert (!(flags
& ~O_READ
));
321 startdir
= _dl_hurd_data
->portarray
[file_name
[0] == '/' ?
322 INIT_PORT_CRDIR
: INIT_PORT_CWDIR
];
324 while (file_name
[0] == '/')
327 err
= __dir_lookup (startdir
, (char *)file_name
, O_RDONLY
, 0,
328 &doretry
, retryname
, port
);
331 err
= __hurd_file_name_lookup_retry (use_init_port
, get_dtable_port
,
332 __dir_lookup
, doretry
, retryname
,
336 err
= __io_stat (*port
, stat
);
338 __mach_port_deallocate (__mach_task_self (), *port
);
345 __open (const char *file_name
, int mode
, ...)
348 error_t err
= open_file (file_name
, mode
, &port
, 0);
350 return __hurd_fail (err
);
358 if (fd
!= (int) MACH_PORT_NULL
)
359 __mach_port_deallocate (__mach_task_self (), (mach_port_t
) fd
);
363 __ssize_t weak_function
364 __libc_read (int fd
, void *buf
, size_t nbytes
)
368 mach_msg_type_number_t nread
;
372 err
= __io_read ((mach_port_t
) fd
, &data
, &nread
, -1, nbytes
);
374 return __hurd_fail (err
);
378 memcpy (buf
, data
, nread
);
379 __vm_deallocate (__mach_task_self (), (vm_address_t
) data
, nread
);
384 libc_hidden_weak (__libc_read
)
386 __ssize_t weak_function
387 __libc_write (int fd
, const void *buf
, size_t nbytes
)
390 mach_msg_type_number_t nwrote
;
392 assert (fd
< _hurd_init_dtablesize
);
394 err
= __io_write (_hurd_init_dtable
[fd
], buf
, nbytes
, -1, &nwrote
);
396 return __hurd_fail (err
);
400 libc_hidden_weak (__libc_write
)
402 /* This is only used for printing messages (see dl-misc.c). */
403 __ssize_t weak_function
404 __writev (int fd
, const struct iovec
*iov
, int niov
)
406 if (fd
>= _hurd_init_dtablesize
)
414 for (i
= 0; i
< niov
; ++i
)
415 total
+= iov
[i
].iov_len
;
419 char buf
[total
], *bufp
= buf
;
421 mach_msg_type_number_t nwrote
;
423 for (i
= 0; i
< niov
; ++i
)
424 bufp
= (memcpy (bufp
, iov
[i
].iov_base
, iov
[i
].iov_len
)
427 err
= __io_write (_hurd_init_dtable
[fd
], buf
, total
, -1, &nwrote
);
429 return __hurd_fail (err
);
437 off64_t weak_function
438 __libc_lseek64 (int fd
, off64_t offset
, int whence
)
442 err
= __io_seek ((mach_port_t
) fd
, offset
, whence
, &offset
);
444 return __hurd_fail (err
);
449 __ptr_t weak_function
450 __mmap (__ptr_t addr
, size_t len
, int prot
, int flags
, int fd
, off_t offset
)
454 vm_address_t mapaddr
;
455 mach_port_t memobj_rd
, memobj_wr
;
457 vmprot
= VM_PROT_NONE
;
458 if (prot
& PROT_READ
)
459 vmprot
|= VM_PROT_READ
;
460 if (prot
& PROT_WRITE
)
461 vmprot
|= VM_PROT_WRITE
;
462 if (prot
& PROT_EXEC
)
463 vmprot
|= VM_PROT_EXECUTE
;
465 if (flags
& MAP_ANON
)
466 memobj_rd
= MACH_PORT_NULL
;
469 assert (!(flags
& MAP_SHARED
));
470 err
= __io_map ((mach_port_t
) fd
, &memobj_rd
, &memobj_wr
);
472 return __hurd_fail (err
), MAP_FAILED
;
473 __mach_port_deallocate (__mach_task_self (), memobj_wr
);
476 mapaddr
= (vm_address_t
) addr
;
477 err
= __vm_map (__mach_task_self (),
478 &mapaddr
, (vm_size_t
) len
, ELF_MACHINE_USER_ADDRESS_MASK
,
479 !(flags
& MAP_FIXED
),
481 (vm_offset_t
) offset
,
482 flags
& (MAP_COPY
|MAP_PRIVATE
),
484 (flags
& MAP_SHARED
) ? VM_INHERIT_SHARE
: VM_INHERIT_COPY
);
485 if (err
== KERN_NO_SPACE
&& (flags
& MAP_FIXED
))
487 /* XXX this is not atomic as it is in unix! */
488 /* The region is already allocated; deallocate it first. */
489 err
= __vm_deallocate (__mach_task_self (), mapaddr
, len
);
491 err
= __vm_map (__mach_task_self (),
492 &mapaddr
, (vm_size_t
) len
,
493 ELF_MACHINE_USER_ADDRESS_MASK
,
494 !(flags
& MAP_FIXED
),
495 memobj_rd
, (vm_offset_t
) offset
,
496 flags
& (MAP_COPY
|MAP_PRIVATE
),
499 ? VM_INHERIT_SHARE
: VM_INHERIT_COPY
);
502 if ((flags
& MAP_ANON
) == 0)
503 __mach_port_deallocate (__mach_task_self (), memobj_rd
);
506 return __hurd_fail (err
), MAP_FAILED
;
507 return (__ptr_t
) mapaddr
;
511 __fxstat64 (int vers
, int fd
, struct stat64
*buf
)
515 assert (vers
== _STAT_VER
);
517 err
= __io_stat ((mach_port_t
) fd
, buf
);
519 return __hurd_fail (err
);
523 libc_hidden_def (__fxstat64
)
526 __xstat64 (int vers
, const char *file
, struct stat64
*buf
)
531 assert (vers
== _STAT_VER
);
533 err
= open_file (file
, 0, &port
, buf
);
535 return __hurd_fail (err
);
537 __mach_port_deallocate (__mach_task_self (), port
);
541 libc_hidden_def (__xstat64
)
543 /* This function is called by the dynamic linker (rtld.c) to check
544 whether debugging malloc is allowed even for SUID binaries. This
545 stub will always fail, which means that malloc-debugging is always
546 disabled for SUID binaries. */
548 __access (const char *file
, int type
)
560 if (__proc_getpids (_dl_hurd_data
->portarray
[INIT_PORT_PROC
],
561 &pid
, &ppid
, &orphaned
))
567 /* This is called only in some strange cases trying to guess a value
568 for $ORIGIN for the executable. The dynamic linker copes with
569 getcwd failing (dl-object.c), and it's too much hassle to include
570 the functionality here. (We could, it just requires duplicating or
571 reusing getcwd.c's code but using our special lookup function as in
575 __getcwd (char *buf
, size_t size
)
581 void weak_function attribute_hidden
584 __proc_mark_exit (_dl_hurd_data
->portarray
[INIT_PORT_PROC
],
585 W_EXITCODE (status
, 0), 0);
586 while (__task_terminate (__mach_task_self ()))
587 __mach_task_self_
= (__mach_task_self
) ();
589 /* We need this alias to satisfy references from libc_pic.a objects
590 that were affected by the libc_hidden_proto declaration for _exit. */
591 strong_alias (_exit
, __GI__exit
)
593 /* Try to get a machine dependent instruction which will make the
594 program crash. This is used in case everything else fails. */
595 #include <abort-instr.h>
596 #ifndef ABORT_INSTRUCTION
597 /* No such instruction is available. */
598 # define ABORT_INSTRUCTION
604 /* Try to abort using the system specific command. */
607 /* If the abort instruction failed, exit. */
610 /* If even this fails, make sure we never return. */
612 /* Try for ever and ever. */
616 /* We need this alias to satisfy references from libc_pic.a objects
617 that were affected by the libc_hidden_proto declaration for abort. */
618 strong_alias (abort
, __GI_abort
)
620 /* This function is called by interruptible RPC stubs. For initial
621 dynamic linking, just use the normal mach_msg. Since this defn is
622 weak, the real defn in libc.so will override it if we are linked into
623 the user program (-ldl). */
625 error_t weak_function
626 _hurd_intr_rpc_mach_msg (mach_msg_header_t
*msg
,
627 mach_msg_option_t option
,
628 mach_msg_size_t send_size
,
629 mach_msg_size_t rcv_size
,
630 mach_port_t rcv_name
,
631 mach_msg_timeout_t timeout
,
634 return __mach_msg (msg
, option
, send_size
, rcv_size
, rcv_name
,
643 /* There is nothing to print. Hurd has no auxiliary vector. */
647 /* Return an array of useful/necessary hardware capability names. */
648 const struct r_strlenpair
*
650 _dl_important_hwcaps (const char *platform
, size_t platform_len
, size_t *sz
,
651 size_t *max_capstrlen
)
653 struct r_strlenpair
*result
;
655 /* Return an empty array. Hurd has no hardware capabilities. */
656 result
= (struct r_strlenpair
*) malloc (sizeof (*result
));
658 _dl_signal_error (ENOMEM
, NULL
, NULL
, "cannot create capability list");
660 result
[0].str
= (char *) result
; /* Does not really matter. */
668 _dl_init_first (int argc
, ...)
670 /* This no-op definition only gets used if libc is not linked in. */