1 /* Operating system support for run-time dynamic linker. Hurd version.
2 Copyright (C) 1995-2015 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 "hurdstartup.h"
35 #include <hurd/lookup.h>
36 #include <hurd/auth.h>
37 #include <hurd/term.h>
44 #include <dl-machine.h>
45 #include <dl-procinfo.h>
47 extern void __mach_init (void);
50 extern char **_dl_argv
;
51 extern char **_environ
;
53 int __libc_enable_secure
= 0;
54 rtld_hidden_data_def (__libc_enable_secure
)
55 int __libc_multiple_libcs
= 0; /* Defining this here avoids the inclusion
57 /* This variable contains the lowest stack address ever used. */
58 void *__libc_stack_end
;
61 hp_timing_t _dl_cpuclock_offset
;
65 struct hurd_startup_data
*_dl_hurd_data
;
67 /* This is used only within ld.so, via dl-minimal.c's __errno_location. */
69 int errno attribute_hidden
;
71 /* Defining these variables here avoids the inclusion of hurdsig.c. */
72 unsigned long int __hurd_sigthread_stack_base
;
73 unsigned long int __hurd_sigthread_stack_end
;
74 unsigned long int *__hurd_sigthread_variables
;
76 /* Defining these variables here avoids the inclusion of init-first.c.
77 We need to provide temporary storage for the per-thread variables
78 of the main user thread here, since it is used for storing the
79 `errno' variable. Note that this information is lost once we
80 relocate the dynamic linker. */
81 static unsigned long int threadvars
[_HURD_THREADVAR_MAX
];
82 unsigned long int __hurd_threadvar_stack_offset
83 = (unsigned long int) &threadvars
;
84 unsigned long int __hurd_threadvar_stack_mask
;
86 #define FMH defined(__i386__)
88 # define fmh() ((void)0)
89 # define unfmh() ((void)0)
91 /* XXX loser kludge for vm_map kernel bug */
92 #undef ELF_MACHINE_USER_ADDRESS_MASK
93 #define ELF_MACHINE_USER_ADDRESS_MASK 0
94 static vm_address_t fmha
;
95 static vm_size_t fmhs
;
96 static void unfmh(void){
97 __vm_deallocate(__mach_task_self(),fmha
,fmhs
);}
98 static void fmh(void) {
99 error_t err
;int x
;mach_port_t p
;
100 vm_address_t a
=0x08000000U
,max
=VM_MAX_ADDRESS
;
101 while (!(err
=__vm_region(__mach_task_self(),&a
,&fmhs
,&x
,&x
,&x
,&x
,&p
,&x
))){
102 __mach_port_deallocate(__mach_task_self(),p
);
103 if (a
+fmhs
>=0x80000000U
){
106 if (err
) assert(err
==KERN_NO_SPACE
);
107 if (!fmha
)fmhs
=0;else{
109 err
= __vm_map (__mach_task_self (),
110 &fmha
, fmhs
, 0, 0, MACH_PORT_NULL
, 0, 1,
111 VM_PROT_NONE
, VM_PROT_NONE
, VM_INHERIT_COPY
);
114 /* XXX loser kludge for vm_map kernel bug */
119 _dl_sysdep_start (void **start_argptr
,
120 void (*dl_main
) (const ElfW(Phdr
) *phdr
, ElfW(Word
) phent
,
121 ElfW(Addr
) *user_entry
,
124 void go (intptr_t *argdata
)
128 /* Cache the information in various global variables. */
130 _dl_argv
= 1 + (char **) argdata
;
131 _environ
= &_dl_argv
[_dl_argc
+ 1];
132 for (p
= _environ
; *p
++;); /* Skip environ pointers and terminator. */
134 if ((void *) p
== _dl_argv
[0])
136 static struct hurd_startup_data nodata
;
137 _dl_hurd_data
= &nodata
;
138 nodata
.user_entry
= (vm_address_t
) ENTRY_POINT
;
141 _dl_hurd_data
= (void *) p
;
143 __libc_enable_secure
= _dl_hurd_data
->flags
& EXEC_SECURE
;
145 if (_dl_hurd_data
->flags
& EXEC_STACK_ARGS
&&
146 _dl_hurd_data
->user_entry
== 0)
147 _dl_hurd_data
->user_entry
= (vm_address_t
) ENTRY_POINT
;
151 #if 0 /* XXX make this work for real someday... */
152 if (_dl_hurd_data
->user_entry
== (vm_address_t
) ENTRY_POINT
)
153 /* We were invoked as a command, not as the program interpreter.
154 The generic ld.so code supports this: it will parse the args
155 as "ld.so PROGRAM [ARGS...]". For booting the Hurd, we
156 support an additional special syntax:
157 ld.so [-LIBS...] PROGRAM [ARGS...]
158 Each LIBS word consists of "FILENAME=MEMOBJ";
159 for example "-/lib/libc.so=123" says that the contents of
160 /lib/libc.so are found in a memory object whose port name
161 in our task is 123. */
162 while (_dl_argc
> 2 && _dl_argv
[1][0] == '-' && _dl_argv
[1][1] != '-')
164 char *lastslash
, *memobjname
, *p
;
171 p
= _dl_argv
++[1] + 1;
173 memobjname
= strchr (p
, '=');
175 _dl_sysdep_fatal ("Bogus library spec: ", p
, "\n", NULL
);
176 *memobjname
++ = '\0';
178 while (*memobjname
!= '\0')
179 memobj
= (memobj
* 10) + (*memobjname
++ - '0');
181 /* Add a user reference on the memory object port, so we will
182 still have one after _dl_map_object_from_fd calls our
184 err
= __mach_port_mod_refs (__mach_task_self (), memobj
,
185 MACH_PORT_RIGHT_SEND
, +1);
188 lastslash
= strrchr (p
, '/');
189 l
= _dl_map_object_from_fd (lastslash
? lastslash
+ 1 : p
,
190 memobj
, strdup (p
), 0);
192 /* Squirrel away the memory object port where it
193 can be retrieved by the program later. */
194 l
->l_info
[DT_NULL
] = (void *) memobj
;
198 /* Call elf/rtld.c's main program. It will set everything
199 up and leave us to transfer control to USER_ENTRY. */
200 (*dl_main
) ((const ElfW(Phdr
) *) _dl_hurd_data
->phdr
,
201 _dl_hurd_data
->phdrsz
/ sizeof (ElfW(Phdr
)),
202 &_dl_hurd_data
->user_entry
, NULL
);
204 /* The call above might screw a few things up.
206 First of all, if _dl_skip_args is nonzero, we are ignoring
207 the first few arguments. However, if we have no Hurd startup
208 data, it is the magical convention that ARGV[0] == P. The
209 startup code in init-first.c will get confused if this is not
210 the case, so we must rearrange things to make it so. We'll
211 overwrite the origional ARGV[0] at P with ARGV[_dl_skip_args].
213 Secondly, if we need to be secure, it removes some dangerous
214 environment variables. If we have no Hurd startup date this
215 changes P (since that's the location after the terminating
216 NULL in the list of environment variables). We do the same
217 thing as in the first case but make sure we recalculate P.
218 If we do have Hurd startup data, we have to move the data
219 such that it starts just after the terminating NULL in the
222 We use memmove, since the locations might overlap. */
223 if (__libc_enable_secure
|| _dl_skip_args
)
227 for (newp
= _environ
; *newp
++;);
229 if (_dl_argv
[-_dl_skip_args
] == (char *) p
)
231 if ((char *) newp
!= _dl_argv
[0])
233 assert ((char *) newp
< _dl_argv
[0]);
234 _dl_argv
[0] = memmove ((char *) newp
, _dl_argv
[0],
235 strlen (_dl_argv
[0]) + 1);
240 if ((void *) newp
!= _dl_hurd_data
)
241 memmove (newp
, _dl_hurd_data
, sizeof (*_dl_hurd_data
));
246 extern void _dl_start_user (void);
247 /* Unwind the stack to ARGDATA and simulate a return from _dl_start
248 to the RTLD_START code which will run the user's entry point. */
249 RETURN_TO (argdata
, &_dl_start_user
, _dl_hurd_data
->user_entry
);
253 /* Set up so we can do RPCs. */
256 /* Initialize frequently used global variable. */
257 GLRO(dl_pagesize
) = __getpagesize ();
260 HP_TIMING_NOW (_dl_cpuclock_offset
);
265 /* See hurd/hurdstartup.c; this deals with getting information
266 from the exec server and slicing up the arguments.
267 Then it will call `go', above. */
268 _hurd_startup (start_argptr
, &go
);
276 _dl_sysdep_start_cleanup (void)
278 /* Deallocate the reply port and task port rights acquired by
279 __mach_init. We are done with them now, and the user will
280 reacquire them for himself when he wants them. */
281 __mig_dealloc_reply_port (MACH_PORT_NULL
);
282 __mach_port_deallocate (__mach_task_self (), __mach_task_self_
);
285 /* Minimal open/close/mmap implementation sufficient for initial loading of
286 shared libraries. These are weak definitions so that when the
287 dynamic linker re-relocates itself to be user-visible (for -ldl),
288 it will get the user's definition (i.e. usually libc's). */
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
);
346 __open (const char *file_name
, int mode
, ...)
349 error_t err
= open_file (file_name
, mode
, &port
, 0);
351 return __hurd_fail (err
);
359 if (fd
!= (int) MACH_PORT_NULL
)
360 __mach_port_deallocate (__mach_task_self (), (mach_port_t
) fd
);
364 __ssize_t weak_function
365 __libc_read (int fd
, void *buf
, size_t nbytes
)
369 mach_msg_type_number_t nread
;
373 err
= __io_read ((mach_port_t
) fd
, &data
, &nread
, -1, nbytes
);
375 return __hurd_fail (err
);
379 memcpy (buf
, data
, nread
);
380 __vm_deallocate (__mach_task_self (), (vm_address_t
) data
, nread
);
385 libc_hidden_weak (__libc_read
)
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 __ssize_t weak_function
405 __writev (int fd
, const struct iovec
*iov
, int niov
)
407 if (fd
>= _hurd_init_dtablesize
)
415 for (i
= 0; i
< niov
; ++i
)
416 total
+= iov
[i
].iov_len
;
420 char buf
[total
], *bufp
= buf
;
422 mach_msg_type_number_t nwrote
;
424 for (i
= 0; i
< niov
; ++i
)
425 bufp
= (memcpy (bufp
, iov
[i
].iov_base
, iov
[i
].iov_len
)
428 err
= __io_write (_hurd_init_dtable
[fd
], buf
, total
, -1, &nwrote
);
430 return __hurd_fail (err
);
438 off64_t weak_function
439 __libc_lseek64 (int fd
, off64_t offset
, int whence
)
443 err
= __io_seek ((mach_port_t
) fd
, offset
, whence
, &offset
);
445 return __hurd_fail (err
);
450 __ptr_t weak_function
451 __mmap (__ptr_t addr
, size_t len
, int prot
, int flags
, int fd
, off_t offset
)
455 vm_address_t mapaddr
;
456 mach_port_t memobj_rd
, memobj_wr
;
458 vmprot
= VM_PROT_NONE
;
459 if (prot
& PROT_READ
)
460 vmprot
|= VM_PROT_READ
;
461 if (prot
& PROT_WRITE
)
462 vmprot
|= VM_PROT_WRITE
;
463 if (prot
& PROT_EXEC
)
464 vmprot
|= VM_PROT_EXECUTE
;
466 if (flags
& MAP_ANON
)
467 memobj_rd
= MACH_PORT_NULL
;
470 assert (!(flags
& MAP_SHARED
));
471 err
= __io_map ((mach_port_t
) fd
, &memobj_rd
, &memobj_wr
);
473 return __hurd_fail (err
), MAP_FAILED
;
474 __mach_port_deallocate (__mach_task_self (), memobj_wr
);
477 mapaddr
= (vm_address_t
) addr
;
478 err
= __vm_map (__mach_task_self (),
479 &mapaddr
, (vm_size_t
) len
, ELF_MACHINE_USER_ADDRESS_MASK
,
480 !(flags
& MAP_FIXED
),
482 (vm_offset_t
) offset
,
483 flags
& (MAP_COPY
|MAP_PRIVATE
),
485 (flags
& MAP_SHARED
) ? VM_INHERIT_SHARE
: VM_INHERIT_COPY
);
486 if (err
== KERN_NO_SPACE
&& (flags
& MAP_FIXED
))
488 /* XXX this is not atomic as it is in unix! */
489 /* The region is already allocated; deallocate it first. */
490 err
= __vm_deallocate (__mach_task_self (), mapaddr
, len
);
492 err
= __vm_map (__mach_task_self (),
493 &mapaddr
, (vm_size_t
) len
,
494 ELF_MACHINE_USER_ADDRESS_MASK
,
495 !(flags
& MAP_FIXED
),
496 memobj_rd
, (vm_offset_t
) offset
,
497 flags
& (MAP_COPY
|MAP_PRIVATE
),
500 ? VM_INHERIT_SHARE
: VM_INHERIT_COPY
);
503 if ((flags
& MAP_ANON
) == 0)
504 __mach_port_deallocate (__mach_task_self (), memobj_rd
);
507 return __hurd_fail (err
), MAP_FAILED
;
508 return (__ptr_t
) mapaddr
;
512 __fxstat64 (int vers
, int fd
, struct stat64
*buf
)
516 assert (vers
== _STAT_VER
);
518 err
= __io_stat ((mach_port_t
) fd
, buf
);
520 return __hurd_fail (err
);
524 libc_hidden_def (__fxstat64
)
527 __xstat64 (int vers
, const char *file
, struct stat64
*buf
)
532 assert (vers
== _STAT_VER
);
534 err
= open_file (file
, 0, &port
, buf
);
536 return __hurd_fail (err
);
538 __mach_port_deallocate (__mach_task_self (), port
);
542 libc_hidden_def (__xstat64
)
544 /* This function is called by the dynamic linker (rtld.c) to check
545 whether debugging malloc is allowed even for SUID binaries. This
546 stub will always fail, which means that malloc-debugging is always
547 disabled for SUID binaries. */
549 __access (const char *file
, int type
)
561 if (__proc_getpids (_dl_hurd_data
->portarray
[INIT_PORT_PROC
],
562 &pid
, &ppid
, &orphaned
))
568 /* This is called only in some strange cases trying to guess a value
569 for $ORIGIN for the executable. The dynamic linker copes with
570 getcwd failing (dl-object.c), and it's too much hassle to include
571 the functionality here. (We could, it just requires duplicating or
572 reusing getcwd.c's code but using our special lookup function as in
576 __getcwd (char *buf
, size_t size
)
582 void weak_function attribute_hidden
585 __proc_mark_exit (_dl_hurd_data
->portarray
[INIT_PORT_PROC
],
586 W_EXITCODE (status
, 0), 0);
587 while (__task_terminate (__mach_task_self ()))
588 __mach_task_self_
= (__mach_task_self
) ();
590 /* We need this alias to satisfy references from libc_pic.a objects
591 that were affected by the libc_hidden_proto declaration for _exit. */
592 strong_alias (_exit
, __GI__exit
)
594 /* Try to get a machine dependent instruction which will make the
595 program crash. This is used in case everything else fails. */
596 #include <abort-instr.h>
597 #ifndef ABORT_INSTRUCTION
598 /* No such instruction is available. */
599 # define ABORT_INSTRUCTION
605 /* Try to abort using the system specific command. */
608 /* If the abort instruction failed, exit. */
611 /* If even this fails, make sure we never return. */
613 /* Try for ever and ever. */
617 /* We need this alias to satisfy references from libc_pic.a objects
618 that were affected by the libc_hidden_proto declaration for abort. */
619 strong_alias (abort
, __GI_abort
)
621 /* This function is called by interruptible RPC stubs. For initial
622 dynamic linking, just use the normal mach_msg. Since this defn is
623 weak, the real defn in libc.so will override it if we are linked into
624 the user program (-ldl). */
626 error_t weak_function
627 _hurd_intr_rpc_mach_msg (mach_msg_header_t
*msg
,
628 mach_msg_option_t option
,
629 mach_msg_size_t send_size
,
630 mach_msg_size_t rcv_size
,
631 mach_port_t rcv_name
,
632 mach_msg_timeout_t timeout
,
635 return __mach_msg (msg
, option
, send_size
, rcv_size
, rcv_name
,
644 /* There is nothing to print. Hurd has no auxiliary vector. */
649 _dl_init_first (int argc
, ...)
651 /* This no-op definition only gets used if libc is not linked in. */