1 /* Operating system support for run-time dynamic linker. Hurd version.
2 Copyright (C) 1995-2018 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, see
17 <http://www.gnu.org/licenses/>. */
19 /* In the static library, this is all handled by dl-support.c
20 or by the vanilla definitions in the rest of the C library. */
33 #include <mach/mig_support.h>
34 #include <mach/machine/vm_param.h>
35 #include "hurdstartup.h"
36 #include <hurd/lookup.h>
37 #include <hurd/auth.h>
38 #include <hurd/term.h>
45 #include <dl-machine.h>
46 #include <dl-procinfo.h>
48 #include <dl-tunables.h>
49 #include <not-errno.h>
51 extern void __mach_init (void);
54 extern char **_dl_argv
;
55 extern char **_environ
;
57 int __libc_enable_secure
= 0;
58 rtld_hidden_data_def (__libc_enable_secure
)
59 int __libc_multiple_libcs
= 0; /* Defining this here avoids the inclusion
61 /* This variable contains the lowest stack address ever used. */
62 void *__libc_stack_end
= NULL
;
63 rtld_hidden_data_def(__libc_stack_end
)
66 hp_timing_t _dl_cpuclock_offset
;
69 /* TODO: Initialize. */
70 void *_dl_random attribute_relro
= NULL
;
72 struct hurd_startup_data
*_dl_hurd_data
;
74 #define FMH defined(__i386__)
76 # define fmh() ((void)0)
77 # define unfmh() ((void)0)
79 /* XXX loser kludge for vm_map kernel bug */
80 #undef ELF_MACHINE_USER_ADDRESS_MASK
81 #define ELF_MACHINE_USER_ADDRESS_MASK 0
82 static vm_address_t fmha
;
83 static vm_size_t fmhs
;
84 static void unfmh(void){
85 __vm_deallocate(__mach_task_self(),fmha
,fmhs
);}
86 static void fmh(void) {
87 error_t err
;int x
;vm_offset_t o
;mach_port_t p
;
88 vm_address_t a
=0x08000000U
,max
=VM_MAX_ADDRESS
;
89 while (!(err
=__vm_region(__mach_task_self(),&a
,&fmhs
,&x
,&x
,&x
,&x
,&p
,&o
))){
90 __mach_port_deallocate(__mach_task_self(),p
);
91 if (a
+fmhs
>=0x80000000U
){
94 if (err
) assert(err
==KERN_NO_SPACE
);
95 if (!fmha
)fmhs
=0;else{
97 err
= __vm_map (__mach_task_self (),
98 &fmha
, fmhs
, 0, 0, MACH_PORT_NULL
, 0, 1,
99 VM_PROT_NONE
, VM_PROT_NONE
, VM_INHERIT_COPY
);
102 /* XXX loser kludge for vm_map kernel bug */
107 _dl_sysdep_start (void **start_argptr
,
108 void (*dl_main
) (const ElfW(Phdr
) *phdr
, ElfW(Word
) phent
,
109 ElfW(Addr
) *user_entry
,
112 void go (intptr_t *argdata
)
116 /* Cache the information in various global variables. */
118 _dl_argv
= 1 + (char **) argdata
;
119 _environ
= &_dl_argv
[_dl_argc
+ 1];
120 for (p
= _environ
; *p
++;); /* Skip environ pointers and terminator. */
122 if ((void *) p
== _dl_argv
[0])
124 static struct hurd_startup_data nodata
;
125 _dl_hurd_data
= &nodata
;
126 nodata
.user_entry
= (vm_address_t
) ENTRY_POINT
;
129 _dl_hurd_data
= (void *) p
;
131 __libc_enable_secure
= _dl_hurd_data
->flags
& EXEC_SECURE
;
133 __tunables_init (_environ
);
135 if (_dl_hurd_data
->flags
& EXEC_STACK_ARGS
&&
136 _dl_hurd_data
->user_entry
== 0)
137 _dl_hurd_data
->user_entry
= (vm_address_t
) ENTRY_POINT
;
141 #if 0 /* XXX make this work for real someday... */
142 if (_dl_hurd_data
->user_entry
== (vm_address_t
) ENTRY_POINT
)
143 /* We were invoked as a command, not as the program interpreter.
144 The generic ld.so code supports this: it will parse the args
145 as "ld.so PROGRAM [ARGS...]". For booting the Hurd, we
146 support an additional special syntax:
147 ld.so [-LIBS...] PROGRAM [ARGS...]
148 Each LIBS word consists of "FILENAME=MEMOBJ";
149 for example "-/lib/libc.so=123" says that the contents of
150 /lib/libc.so are found in a memory object whose port name
151 in our task is 123. */
152 while (_dl_argc
> 2 && _dl_argv
[1][0] == '-' && _dl_argv
[1][1] != '-')
154 char *lastslash
, *memobjname
, *p
;
161 p
= _dl_argv
++[1] + 1;
163 memobjname
= strchr (p
, '=');
165 _dl_sysdep_fatal ("Bogus library spec: ", p
, "\n", NULL
);
166 *memobjname
++ = '\0';
168 while (*memobjname
!= '\0')
169 memobj
= (memobj
* 10) + (*memobjname
++ - '0');
171 /* Add a user reference on the memory object port, so we will
172 still have one after _dl_map_object_from_fd calls our
174 err
= __mach_port_mod_refs (__mach_task_self (), memobj
,
175 MACH_PORT_RIGHT_SEND
, +1);
178 lastslash
= strrchr (p
, '/');
179 l
= _dl_map_object_from_fd (lastslash
? lastslash
+ 1 : p
, NULL
,
180 memobj
, strdup (p
), 0);
182 /* Squirrel away the memory object port where it
183 can be retrieved by the program later. */
184 l
->l_info
[DT_NULL
] = (void *) memobj
;
188 /* Call elf/rtld.c's main program. It will set everything
189 up and leave us to transfer control to USER_ENTRY. */
190 (*dl_main
) ((const ElfW(Phdr
) *) _dl_hurd_data
->phdr
,
191 _dl_hurd_data
->phdrsz
/ sizeof (ElfW(Phdr
)),
192 (ElfW(Addr
) *) &_dl_hurd_data
->user_entry
, NULL
);
194 /* The call above might screw a few things up.
196 First of all, if _dl_skip_args is nonzero, we are ignoring
197 the first few arguments. However, if we have no Hurd startup
198 data, it is the magical convention that ARGV[0] == P. The
199 startup code in init-first.c will get confused if this is not
200 the case, so we must rearrange things to make it so. We'll
201 overwrite the origional ARGV[0] at P with ARGV[_dl_skip_args].
203 Secondly, if we need to be secure, it removes some dangerous
204 environment variables. If we have no Hurd startup date this
205 changes P (since that's the location after the terminating
206 NULL in the list of environment variables). We do the same
207 thing as in the first case but make sure we recalculate P.
208 If we do have Hurd startup data, we have to move the data
209 such that it starts just after the terminating NULL in the
212 We use memmove, since the locations might overlap. */
213 if (__libc_enable_secure
|| _dl_skip_args
)
217 for (newp
= _environ
; *newp
++;);
219 if (_dl_argv
[-_dl_skip_args
] == (char *) p
)
221 if ((char *) newp
!= _dl_argv
[0])
223 assert ((char *) newp
< _dl_argv
[0]);
224 _dl_argv
[0] = memmove ((char *) newp
, _dl_argv
[0],
225 strlen (_dl_argv
[0]) + 1);
230 if ((void *) newp
!= _dl_hurd_data
)
231 memmove (newp
, _dl_hurd_data
, sizeof (*_dl_hurd_data
));
236 extern void _dl_start_user (void);
237 /* Unwind the stack to ARGDATA and simulate a return from _dl_start
238 to the RTLD_START code which will run the user's entry point. */
239 RETURN_TO (argdata
, &_dl_start_user
, _dl_hurd_data
->user_entry
);
243 /* Set up so we can do RPCs. */
246 /* Initialize frequently used global variable. */
247 GLRO(dl_pagesize
) = __getpagesize ();
250 HP_TIMING_NOW (_dl_cpuclock_offset
);
255 /* See hurd/hurdstartup.c; this deals with getting information
256 from the exec server and slicing up the arguments.
257 Then it will call `go', above. */
258 _hurd_startup (start_argptr
, &go
);
265 _dl_sysdep_start_cleanup (void)
267 /* Deallocate the reply port and task port rights acquired by
268 __mach_init. We are done with them now, and the user will
269 reacquire them for himself when he wants them. */
270 __mig_dealloc_reply_port (MACH_PORT_NULL
);
271 __mach_port_deallocate (__mach_task_self (), __mach_host_self_
);
272 __mach_port_deallocate (__mach_task_self (), __mach_task_self_
);
275 /* Minimal open/close/mmap implementation sufficient for initial loading of
276 shared libraries. These are weak definitions so that when the
277 dynamic linker re-relocates itself to be user-visible (for -ldl),
278 it will get the user's definition (i.e. usually libc's). */
280 /* This macro checks that the function does not get renamed to be hidden: we do
281 need these to be overridable by libc's. */
282 #define check_no_hidden(name) \
283 static __typeof (name) __check_##name##_no_hidden \
284 __attribute__ ((alias (#name)));
286 /* Open FILE_NAME and return a Hurd I/O for it in *PORT, or return an
287 error. If STAT is non-zero, stat the file into that stat buffer. */
289 open_file (const char *file_name
, int flags
,
290 mach_port_t
*port
, struct stat64
*stat
)
292 enum retry_type doretry
;
293 char retryname
[1024]; /* XXX string_t LOSES! */
297 error_t
use_init_port (int which
, error_t (*operate
) (file_t
))
299 return (which
< _dl_hurd_data
->portarraysize
300 ? ((*operate
) (_dl_hurd_data
->portarray
[which
]))
303 file_t
get_dtable_port (int fd
)
305 if ((unsigned int) fd
< _dl_hurd_data
->dtablesize
306 && _dl_hurd_data
->dtable
[fd
] != MACH_PORT_NULL
)
308 __mach_port_mod_refs (__mach_task_self (), _dl_hurd_data
->dtable
[fd
],
309 MACH_PORT_RIGHT_SEND
, +1);
310 return _dl_hurd_data
->dtable
[fd
];
313 return MACH_PORT_NULL
;
316 assert (!(flags
& ~(O_READ
| O_CLOEXEC
)));
318 startdir
= _dl_hurd_data
->portarray
[file_name
[0] == '/' ?
319 INIT_PORT_CRDIR
: INIT_PORT_CWDIR
];
321 while (file_name
[0] == '/')
324 err
= __dir_lookup (startdir
, (char *)file_name
, O_RDONLY
, 0,
325 &doretry
, retryname
, port
);
328 err
= __hurd_file_name_lookup_retry (use_init_port
, get_dtable_port
,
329 __dir_lookup
, doretry
, retryname
,
333 err
= __io_stat (*port
, stat
);
335 __mach_port_deallocate (__mach_task_self (), *port
);
341 check_no_hidden(__open
);
343 __open (const char *file_name
, int mode
, ...)
346 error_t err
= open_file (file_name
, mode
, &port
, 0);
348 return __hurd_fail (err
);
353 check_no_hidden(__close
);
357 if (fd
!= (int) MACH_PORT_NULL
)
358 __mach_port_deallocate (__mach_task_self (), (mach_port_t
) fd
);
362 check_no_hidden(__libc_read
);
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 check_no_hidden(__libc_write
);
387 __ssize_t weak_function
388 __libc_write (int fd
, const void *buf
, size_t nbytes
)
391 mach_msg_type_number_t nwrote
;
393 assert (fd
< _hurd_init_dtablesize
);
395 err
= __io_write (_hurd_init_dtable
[fd
], buf
, nbytes
, -1, &nwrote
);
397 return __hurd_fail (err
);
401 libc_hidden_weak (__libc_write
)
403 /* This is only used for printing messages (see dl-misc.c). */
404 check_no_hidden(__writev
);
405 __ssize_t weak_function
406 __writev (int fd
, const struct iovec
*iov
, int niov
)
408 if (fd
>= _hurd_init_dtablesize
)
416 for (i
= 0; i
< niov
; ++i
)
417 total
+= iov
[i
].iov_len
;
421 char buf
[total
], *bufp
= buf
;
423 mach_msg_type_number_t nwrote
;
425 for (i
= 0; i
< niov
; ++i
)
426 bufp
= (memcpy (bufp
, iov
[i
].iov_base
, iov
[i
].iov_len
)
429 err
= __io_write (_hurd_init_dtable
[fd
], buf
, total
, -1, &nwrote
);
431 return __hurd_fail (err
);
438 check_no_hidden(__libc_lseek64
);
439 off64_t weak_function
440 __libc_lseek64 (int fd
, off64_t offset
, int whence
)
444 err
= __io_seek ((mach_port_t
) fd
, offset
, whence
, &offset
);
446 return __hurd_fail (err
);
451 check_no_hidden(__mmap
);
453 __mmap (void *addr
, size_t len
, int prot
, int flags
, int fd
, off_t offset
)
457 vm_address_t mapaddr
;
458 mach_port_t memobj_rd
, memobj_wr
;
460 vmprot
= VM_PROT_NONE
;
461 if (prot
& PROT_READ
)
462 vmprot
|= VM_PROT_READ
;
463 if (prot
& PROT_WRITE
)
464 vmprot
|= VM_PROT_WRITE
;
465 if (prot
& PROT_EXEC
)
466 vmprot
|= VM_PROT_EXECUTE
;
468 if (flags
& MAP_ANON
)
469 memobj_rd
= MACH_PORT_NULL
;
472 assert (!(flags
& MAP_SHARED
));
473 err
= __io_map ((mach_port_t
) fd
, &memobj_rd
, &memobj_wr
);
475 return __hurd_fail (err
), MAP_FAILED
;
476 if (memobj_wr
!= MACH_PORT_NULL
)
477 __mach_port_deallocate (__mach_task_self (), memobj_wr
);
480 mapaddr
= (vm_address_t
) addr
;
481 err
= __vm_map (__mach_task_self (),
482 &mapaddr
, (vm_size_t
) len
, ELF_MACHINE_USER_ADDRESS_MASK
,
483 !(flags
& MAP_FIXED
),
485 (vm_offset_t
) offset
,
486 flags
& (MAP_COPY
|MAP_PRIVATE
),
488 (flags
& MAP_SHARED
) ? VM_INHERIT_SHARE
: VM_INHERIT_COPY
);
489 if (err
== KERN_NO_SPACE
&& (flags
& MAP_FIXED
))
491 /* XXX this is not atomic as it is in unix! */
492 /* The region is already allocated; deallocate it first. */
493 err
= __vm_deallocate (__mach_task_self (), mapaddr
, len
);
495 err
= __vm_map (__mach_task_self (),
496 &mapaddr
, (vm_size_t
) len
,
497 ELF_MACHINE_USER_ADDRESS_MASK
,
498 !(flags
& MAP_FIXED
),
499 memobj_rd
, (vm_offset_t
) offset
,
500 flags
& (MAP_COPY
|MAP_PRIVATE
),
503 ? VM_INHERIT_SHARE
: VM_INHERIT_COPY
);
506 if ((flags
& MAP_ANON
) == 0)
507 __mach_port_deallocate (__mach_task_self (), memobj_rd
);
510 return __hurd_fail (err
), MAP_FAILED
;
511 return (void *) mapaddr
;
514 check_no_hidden(__fxstat64
);
516 __fxstat64 (int vers
, int fd
, struct stat64
*buf
)
520 assert (vers
== _STAT_VER
);
522 err
= __io_stat ((mach_port_t
) fd
, buf
);
524 return __hurd_fail (err
);
528 libc_hidden_def (__fxstat64
)
530 check_no_hidden(__xstat64
);
532 __xstat64 (int vers
, const char *file
, struct stat64
*buf
)
537 assert (vers
== _STAT_VER
);
539 err
= open_file (file
, 0, &port
, buf
);
541 return __hurd_fail (err
);
543 __mach_port_deallocate (__mach_task_self (), port
);
547 libc_hidden_def (__xstat64
)
549 /* This function is called by the dynamic linker (rtld.c) to check
550 whether debugging malloc is allowed even for SUID binaries. This
551 stub will always fail, which means that malloc-debugging is always
552 disabled for SUID binaries. */
553 check_no_hidden(__access
);
555 __access (const char *file
, int type
)
560 check_no_hidden(__access_noerrno
);
562 __access_noerrno (const char *file
, int type
)
567 check_no_hidden(__getpid
);
574 if (__proc_getpids (_dl_hurd_data
->portarray
[INIT_PORT_PROC
],
575 &pid
, &ppid
, &orphaned
))
581 /* We need this alias to satisfy references from libc_pic.a objects
582 that were affected by the libc_hidden_proto declaration for __getpid. */
583 strong_alias (__getpid
, __GI___getpid
)
585 /* This is called only in some strange cases trying to guess a value
586 for $ORIGIN for the executable. The dynamic linker copes with
587 getcwd failing (dl-object.c), and it's too much hassle to include
588 the functionality here. (We could, it just requires duplicating or
589 reusing getcwd.c's code but using our special lookup function as in
591 check_no_hidden(__getcwd
);
593 __getcwd (char *buf
, size_t size
)
599 /* This is used by dl-tunables.c to strdup strings. We can just make this a
601 check_no_hidden(__sbrk
);
603 __sbrk (intptr_t increment
)
606 __vm_allocate (__mach_task_self (), &addr
, increment
, 1);
607 return (void *) addr
;
610 check_no_hidden(__strtoul_internal
);
611 unsigned long int weak_function
612 __strtoul_internal (const char *nptr
, char **endptr
, int base
, int group
)
614 assert (base
== 0 || base
== 10);
616 return _dl_strtoul (nptr
, endptr
);
619 /* We need this alias to satisfy references from libc_pic.a objects
620 that were affected by the libc_hidden_proto declaration for __strtoul_internal. */
621 strong_alias (__strtoul_internal
, __GI___strtoul_internal
)
622 strong_alias (__strtoul_internal
, __GI_____strtoul_internal
)
624 check_no_hidden(_exit
);
625 void weak_function attribute_hidden
628 __proc_mark_exit (_dl_hurd_data
->portarray
[INIT_PORT_PROC
],
629 W_EXITCODE (status
, 0), 0);
630 while (__task_terminate (__mach_task_self ()))
631 __mach_task_self_
= (__mach_task_self
) ();
636 /* We need this alias to satisfy references from libc_pic.a objects
637 that were affected by the libc_hidden_proto declaration for _exit. */
638 strong_alias (_exit
, __GI__exit
)
640 /* Try to get a machine dependent instruction which will make the
641 program crash. This is used in case everything else fails. */
642 #include <abort-instr.h>
643 #ifndef ABORT_INSTRUCTION
644 /* No such instruction is available. */
645 # define ABORT_INSTRUCTION
648 check_no_hidden(abort
);
652 /* Try to abort using the system specific command. */
655 /* If the abort instruction failed, exit. */
658 /* If even this fails, make sure we never return. */
660 /* Try for ever and ever. */
664 /* We need this alias to satisfy references from libc_pic.a objects
665 that were affected by the libc_hidden_proto declaration for abort. */
666 strong_alias (abort
, __GI_abort
)
667 strong_alias (abort
, __GI___chk_fail
)
668 strong_alias (abort
, __GI___fortify_fail
)
669 strong_alias (abort
, __GI___assert_fail
)
670 strong_alias (abort
, __GI___assert_perror_fail
)
672 /* This function is called by interruptible RPC stubs. For initial
673 dynamic linking, just use the normal mach_msg. Since this defn is
674 weak, the real defn in libc.so will override it if we are linked into
675 the user program (-ldl). */
677 error_t weak_function
678 _hurd_intr_rpc_mach_msg (mach_msg_header_t
*msg
,
679 mach_msg_option_t option
,
680 mach_msg_size_t send_size
,
681 mach_msg_size_t rcv_size
,
682 mach_port_t rcv_name
,
683 mach_msg_timeout_t timeout
,
686 return __mach_msg (msg
, option
, send_size
, rcv_size
, rcv_name
,
694 /* There is nothing to print. Hurd has no auxiliary vector. */
699 _dl_init_first (int argc
, ...)
701 /* This no-op definition only gets used if libc is not linked in. */