1 /* Operating system support for run-time dynamic linker. Hurd version.
2 Copyright (C) 1995-2019 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 They also need to be set in the ld section of sysdeps/mach/hurd/Versions, to
281 be overridable, and in libc.abilist and ld.abilist to be checked. */
283 /* This macro checks that the function does not get renamed to be hidden: we do
284 need these to be overridable by libc's. */
285 #define check_no_hidden(name) \
286 __typeof (name) __check_##name##_no_hidden \
287 __attribute__ ((alias (#name))) \
288 __attribute_copy__ (name);
290 /* Open FILE_NAME and return a Hurd I/O for it in *PORT, or return an
291 error. If STAT is non-zero, stat the file into that stat buffer. */
293 open_file (const char *file_name
, int flags
,
294 mach_port_t
*port
, struct stat64
*stat
)
296 enum retry_type doretry
;
297 char retryname
[1024]; /* XXX string_t LOSES! */
301 error_t
use_init_port (int which
, error_t (*operate
) (file_t
))
303 return (which
< _dl_hurd_data
->portarraysize
304 ? ((*operate
) (_dl_hurd_data
->portarray
[which
]))
307 file_t
get_dtable_port (int fd
)
309 if ((unsigned int) fd
< _dl_hurd_data
->dtablesize
310 && _dl_hurd_data
->dtable
[fd
] != MACH_PORT_NULL
)
312 __mach_port_mod_refs (__mach_task_self (), _dl_hurd_data
->dtable
[fd
],
313 MACH_PORT_RIGHT_SEND
, +1);
314 return _dl_hurd_data
->dtable
[fd
];
317 return MACH_PORT_NULL
;
320 assert (!(flags
& ~(O_READ
| O_CLOEXEC
)));
322 startdir
= _dl_hurd_data
->portarray
[file_name
[0] == '/' ?
323 INIT_PORT_CRDIR
: INIT_PORT_CWDIR
];
325 while (file_name
[0] == '/')
328 err
= __dir_lookup (startdir
, (char *)file_name
, O_RDONLY
, 0,
329 &doretry
, retryname
, port
);
332 err
= __hurd_file_name_lookup_retry (use_init_port
, get_dtable_port
,
333 __dir_lookup
, doretry
, retryname
,
337 err
= __io_stat (*port
, stat
);
339 __mach_port_deallocate (__mach_task_self (), *port
);
345 check_no_hidden(__open
);
346 check_no_hidden (__open64
);
348 __open (const char *file_name
, int mode
, ...)
351 error_t err
= open_file (file_name
, mode
, &port
, 0);
353 return __hurd_fail (err
);
357 weak_alias (__open
, __open64
)
359 check_no_hidden(__close
);
363 if (fd
!= (int) MACH_PORT_NULL
)
364 __mach_port_deallocate (__mach_task_self (), (mach_port_t
) fd
);
368 check_no_hidden(__read
);
369 __ssize_t weak_function
370 __read (int fd
, void *buf
, size_t nbytes
)
374 mach_msg_type_number_t nread
;
378 err
= __io_read ((mach_port_t
) fd
, &data
, &nread
, -1, nbytes
);
380 return __hurd_fail (err
);
384 memcpy (buf
, data
, nread
);
385 __vm_deallocate (__mach_task_self (), (vm_address_t
) data
, nread
);
390 libc_hidden_weak (__read
)
392 check_no_hidden(__write
);
393 __ssize_t weak_function
394 __write (int fd
, const void *buf
, size_t nbytes
)
397 mach_msg_type_number_t nwrote
;
399 assert (fd
< _hurd_init_dtablesize
);
401 err
= __io_write (_hurd_init_dtable
[fd
], buf
, nbytes
, -1, &nwrote
);
403 return __hurd_fail (err
);
407 libc_hidden_weak (__write
)
409 /* This is only used for printing messages (see dl-misc.c). */
410 check_no_hidden(__writev
);
411 __ssize_t weak_function
412 __writev (int fd
, const struct iovec
*iov
, int niov
)
414 if (fd
>= _hurd_init_dtablesize
)
422 for (i
= 0; i
< niov
; ++i
)
423 total
+= iov
[i
].iov_len
;
427 char buf
[total
], *bufp
= buf
;
429 mach_msg_type_number_t nwrote
;
431 for (i
= 0; i
< niov
; ++i
)
432 bufp
= (memcpy (bufp
, iov
[i
].iov_base
, iov
[i
].iov_len
)
435 err
= __io_write (_hurd_init_dtable
[fd
], buf
, total
, -1, &nwrote
);
437 return __hurd_fail (err
);
444 check_no_hidden(__libc_lseek64
);
445 off64_t weak_function
446 __libc_lseek64 (int fd
, off64_t offset
, int whence
)
450 err
= __io_seek ((mach_port_t
) fd
, offset
, whence
, &offset
);
452 return __hurd_fail (err
);
457 check_no_hidden(__mmap
);
459 __mmap (void *addr
, size_t len
, int prot
, int flags
, int fd
, off_t offset
)
463 vm_address_t mapaddr
;
464 mach_port_t memobj_rd
, memobj_wr
;
466 vmprot
= VM_PROT_NONE
;
467 if (prot
& PROT_READ
)
468 vmprot
|= VM_PROT_READ
;
469 if (prot
& PROT_WRITE
)
470 vmprot
|= VM_PROT_WRITE
;
471 if (prot
& PROT_EXEC
)
472 vmprot
|= VM_PROT_EXECUTE
;
474 if (flags
& MAP_ANON
)
475 memobj_rd
= MACH_PORT_NULL
;
478 assert (!(flags
& MAP_SHARED
));
479 err
= __io_map ((mach_port_t
) fd
, &memobj_rd
, &memobj_wr
);
481 return __hurd_fail (err
), MAP_FAILED
;
482 if (memobj_wr
!= MACH_PORT_NULL
)
483 __mach_port_deallocate (__mach_task_self (), memobj_wr
);
486 mapaddr
= (vm_address_t
) addr
;
487 err
= __vm_map (__mach_task_self (),
488 &mapaddr
, (vm_size_t
) len
, ELF_MACHINE_USER_ADDRESS_MASK
,
489 !(flags
& MAP_FIXED
),
491 (vm_offset_t
) offset
,
492 flags
& (MAP_COPY
|MAP_PRIVATE
),
494 (flags
& MAP_SHARED
) ? VM_INHERIT_SHARE
: VM_INHERIT_COPY
);
495 if (err
== KERN_NO_SPACE
&& (flags
& MAP_FIXED
))
497 /* XXX this is not atomic as it is in unix! */
498 /* The region is already allocated; deallocate it first. */
499 err
= __vm_deallocate (__mach_task_self (), mapaddr
, len
);
501 err
= __vm_map (__mach_task_self (),
502 &mapaddr
, (vm_size_t
) len
,
503 ELF_MACHINE_USER_ADDRESS_MASK
,
504 !(flags
& MAP_FIXED
),
505 memobj_rd
, (vm_offset_t
) offset
,
506 flags
& (MAP_COPY
|MAP_PRIVATE
),
509 ? VM_INHERIT_SHARE
: VM_INHERIT_COPY
);
512 if ((flags
& MAP_ANON
) == 0)
513 __mach_port_deallocate (__mach_task_self (), memobj_rd
);
516 return __hurd_fail (err
), MAP_FAILED
;
517 return (void *) mapaddr
;
520 check_no_hidden(__fxstat64
);
522 __fxstat64 (int vers
, int fd
, struct stat64
*buf
)
526 assert (vers
== _STAT_VER
);
528 err
= __io_stat ((mach_port_t
) fd
, buf
);
530 return __hurd_fail (err
);
534 libc_hidden_def (__fxstat64
)
536 check_no_hidden(__xstat64
);
538 __xstat64 (int vers
, const char *file
, struct stat64
*buf
)
543 assert (vers
== _STAT_VER
);
545 err
= open_file (file
, 0, &port
, buf
);
547 return __hurd_fail (err
);
549 __mach_port_deallocate (__mach_task_self (), port
);
553 libc_hidden_def (__xstat64
)
555 /* This function is called by the dynamic linker (rtld.c) to check
556 whether debugging malloc is allowed even for SUID binaries. This
557 stub will always fail, which means that malloc-debugging is always
558 disabled for SUID binaries. */
559 check_no_hidden(__access
);
561 __access (const char *file
, int type
)
566 check_no_hidden(__access_noerrno
);
568 __access_noerrno (const char *file
, int type
)
573 check_no_hidden(__getpid
);
580 if (__proc_getpids (_dl_hurd_data
->portarray
[INIT_PORT_PROC
],
581 &pid
, &ppid
, &orphaned
))
587 /* We need this alias to satisfy references from libc_pic.a objects
588 that were affected by the libc_hidden_proto declaration for __getpid. */
589 strong_alias (__getpid
, __GI___getpid
)
591 /* This is called only in some strange cases trying to guess a value
592 for $ORIGIN for the executable. The dynamic linker copes with
593 getcwd failing (dl-object.c), and it's too much hassle to include
594 the functionality here. (We could, it just requires duplicating or
595 reusing getcwd.c's code but using our special lookup function as in
597 check_no_hidden(__getcwd
);
599 __getcwd (char *buf
, size_t size
)
605 /* This is used by dl-tunables.c to strdup strings. We can just make this a
607 check_no_hidden(__sbrk
);
609 __sbrk (intptr_t increment
)
612 __vm_allocate (__mach_task_self (), &addr
, increment
, 1);
613 return (void *) addr
;
616 check_no_hidden(__strtoul_internal
);
617 unsigned long int weak_function
618 __strtoul_internal (const char *nptr
, char **endptr
, int base
, int group
)
620 assert (base
== 0 || base
== 10);
622 return _dl_strtoul (nptr
, endptr
);
625 /* We need this alias to satisfy references from libc_pic.a objects
626 that were affected by the libc_hidden_proto declaration for __strtoul_internal. */
627 strong_alias (__strtoul_internal
, __GI___strtoul_internal
)
628 strong_alias (__strtoul_internal
, __GI_____strtoul_internal
)
630 check_no_hidden(_exit
);
631 void weak_function attribute_hidden
634 __proc_mark_exit (_dl_hurd_data
->portarray
[INIT_PORT_PROC
],
635 W_EXITCODE (status
, 0), 0);
636 while (__task_terminate (__mach_task_self ()))
637 __mach_task_self_
= (__mach_task_self
) ();
642 /* We need this alias to satisfy references from libc_pic.a objects
643 that were affected by the libc_hidden_proto declaration for _exit. */
644 strong_alias (_exit
, __GI__exit
)
646 /* Try to get a machine dependent instruction which will make the
647 program crash. This is used in case everything else fails. */
648 #include <abort-instr.h>
649 #ifndef ABORT_INSTRUCTION
650 /* No such instruction is available. */
651 # define ABORT_INSTRUCTION
654 check_no_hidden(abort
);
658 /* Try to abort using the system specific command. */
661 /* If the abort instruction failed, exit. */
664 /* If even this fails, make sure we never return. */
666 /* Try for ever and ever. */
670 /* We need this alias to satisfy references from libc_pic.a objects
671 that were affected by the libc_hidden_proto declaration for abort. */
672 strong_alias (abort
, __GI_abort
)
673 strong_alias (abort
, __GI___chk_fail
)
674 strong_alias (abort
, __GI___fortify_fail
)
675 strong_alias (abort
, __GI___assert_fail
)
676 strong_alias (abort
, __GI___assert_perror_fail
)
678 /* This function is called by interruptible RPC stubs. For initial
679 dynamic linking, just use the normal mach_msg. Since this defn is
680 weak, the real defn in libc.so will override it if we are linked into
681 the user program (-ldl). */
683 error_t weak_function
684 _hurd_intr_rpc_mach_msg (mach_msg_header_t
*msg
,
685 mach_msg_option_t option
,
686 mach_msg_size_t send_size
,
687 mach_msg_size_t rcv_size
,
688 mach_port_t rcv_name
,
689 mach_msg_timeout_t timeout
,
692 return __mach_msg (msg
, option
, send_size
, rcv_size
, rcv_name
,
700 /* There is nothing to print. Hurd has no auxiliary vector. */
705 _dl_init_first (int argc
, ...)
707 /* This no-op definition only gets used if libc is not linked in. */