1 /* Operating system support for run-time dynamic linker.  Hurd version.
2    Copyright (C) 1995-2022 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
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.
9 
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.
14 
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    <https://www.gnu.org/licenses/>.  */
18 
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.  */
21 #ifdef SHARED
22 
23 #include <hurd.h>
24 #include <link.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <stdlib.h>
28 #include <sys/mman.h>
29 #include <ldsodefs.h>
30 #include <sys/wait.h>
31 #include <assert.h>
32 #include <sysdep.h>
33 #include <argz.h>
34 #include <mach/mig_support.h>
35 #include <mach/machine/vm_param.h>
36 #include "hurdstartup.h"
37 #include <hurd/lookup.h>
38 #include <hurd/auth.h>
39 #include <hurd/term.h>
40 #include <stdarg.h>
41 #include <ctype.h>
42 #include <sys/stat.h>
43 #include <sys/uio.h>
44 
45 #include <entry.h>
46 #include <dl-machine.h>
47 #include <dl-procinfo.h>
48 
49 #include <dl-tunables.h>
50 #include <not-errno.h>
51 #include <not-cancel.h>
52 
53 extern void __mach_init (void);
54 
55 extern int _dl_argc;
56 extern char **_dl_argv;
57 extern char **_environ;
58 
59 int __libc_enable_secure = 0;
60 rtld_hidden_data_def (__libc_enable_secure)
61 /* This variable contains the lowest stack address ever used.  */
62 void *__libc_stack_end = NULL;
63 rtld_hidden_data_def(__libc_stack_end)
64 
65 /* TODO: Initialize.  */
66 void *_dl_random attribute_relro = NULL;
67 
68 struct hurd_startup_data *_dl_hurd_data;
69 
70 
71 ElfW(Addr)
_dl_sysdep_start(void ** start_argptr,void (* dl_main)(const ElfW (Phdr)* phdr,ElfW (Word)phent,ElfW (Addr)* user_entry,ElfW (auxv_t)* auxv))72 _dl_sysdep_start (void **start_argptr,
73 		  void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phent,
74 				   ElfW(Addr) *user_entry,
75 				   ElfW(auxv_t) *auxv))
76 {
77   void go (intptr_t *argdata)
78     {
79       char *orig_argv0;
80       char **p;
81 
82       /* Cache the information in various global variables.  */
83       _dl_argc = *argdata;
84       _dl_argv = 1 + (char **) argdata;
85       _environ = &_dl_argv[_dl_argc + 1];
86       for (p = _environ; *p++;); /* Skip environ pointers and terminator.  */
87 
88       orig_argv0 = _dl_argv[0];
89 
90       if ((void *) p == _dl_argv[0])
91 	{
92 	  static struct hurd_startup_data nodata;
93 	  _dl_hurd_data = &nodata;
94 	  nodata.user_entry = (vm_address_t) ENTRY_POINT;
95 	}
96       else
97 	_dl_hurd_data = (void *) p;
98 
99       GLRO(dl_platform) = NULL; /* Default to nothing known about the platform.  */
100 
101       __libc_enable_secure = _dl_hurd_data->flags & EXEC_SECURE;
102 
103       __tunables_init (_environ);
104 
105       /* Initialize DSO sorting algorithm after tunables.  */
106       _dl_sort_maps_init ();
107 
108 #ifdef DL_SYSDEP_INIT
109       DL_SYSDEP_INIT;
110 #endif
111 
112 #ifdef DL_PLATFORM_INIT
113       DL_PLATFORM_INIT;
114 #endif
115 
116       /* Determine the length of the platform name.  */
117       if (GLRO(dl_platform) != NULL)
118 	GLRO(dl_platformlen) = strlen (GLRO(dl_platform));
119 
120       if (_dl_hurd_data->flags & EXEC_STACK_ARGS
121 	  && _dl_hurd_data->user_entry == 0)
122 	_dl_hurd_data->user_entry = (vm_address_t) ENTRY_POINT;
123 
124 #if 0				/* XXX make this work for real someday... */
125       if (_dl_hurd_data->user_entry == (vm_address_t) ENTRY_POINT)
126 	/* We were invoked as a command, not as the program interpreter.
127 	   The generic ld.so code supports this: it will parse the args
128 	   as "ld.so PROGRAM [ARGS...]".  For booting the Hurd, we
129 	   support an additional special syntax:
130 	     ld.so [-LIBS...] PROGRAM [ARGS...]
131 	   Each LIBS word consists of "FILENAME=MEMOBJ";
132 	   for example "-/lib/libc.so=123" says that the contents of
133 	   /lib/libc.so are found in a memory object whose port name
134 	   in our task is 123.  */
135 	while (_dl_argc > 2 && _dl_argv[1][0] == '-' && _dl_argv[1][1] != '-')
136 	  {
137 	    char *lastslash, *memobjname, *p;
138 	    struct link_map *l;
139 	    mach_port_t memobj;
140 	    error_t err;
141 
142 	    --_dl_argc;
143 	    p = _dl_argv++[1] + 1;
144 
145 	    memobjname = strchr (p, '=');
146 	    if (! memobjname)
147 	      _dl_sysdep_fatal ("Bogus library spec: ", p, "\n", NULL);
148 	    *memobjname++ = '\0';
149 	    memobj = 0;
150 	    while (*memobjname != '\0')
151 	      memobj = (memobj * 10) + (*memobjname++ - '0');
152 
153 	    /* Add a user reference on the memory object port, so we will
154 	       still have one after _dl_map_object_from_fd calls our
155 	       `close'.  */
156 	    err = __mach_port_mod_refs (__mach_task_self (), memobj,
157 					MACH_PORT_RIGHT_SEND, +1);
158 	    assert_perror (err);
159 
160 	    lastslash = strrchr (p, '/');
161 	    l = _dl_map_object_from_fd (lastslash ? lastslash + 1 : p, NULL,
162 					memobj, strdup (p), 0);
163 
164 	    /* Squirrel away the memory object port where it
165 	       can be retrieved by the program later.  */
166 	    l->l_info[DT_NULL] = (void *) memobj;
167 	  }
168 #endif
169 
170       /* Call elf/rtld.c's main program.  It will set everything
171 	 up and leave us to transfer control to USER_ENTRY.  */
172       (*dl_main) ((const ElfW(Phdr) *) _dl_hurd_data->phdr,
173 		  _dl_hurd_data->phdrsz / sizeof (ElfW(Phdr)),
174 		  (ElfW(Addr) *) &_dl_hurd_data->user_entry, NULL);
175 
176       /* The call above might screw a few things up.
177 
178 	 P is the location after the terminating NULL of the list of
179 	 environment variables.  It has to point to the Hurd startup
180 	 data or if that's missing then P == ARGV[0] must hold. The
181 	 startup code in init-first.c will get confused if this is not
182 	 the case, so we must rearrange things to make it so.  We'll
183 	 recompute P and move the Hurd data or the new ARGV[0] there.
184 
185 	 Note: directly invoked ld.so can move arguments and env vars.
186 
187 	 We use memmove, since the locations might overlap.  */
188 
189       char **newp;
190       for (newp = _environ; *newp++;);
191 
192       if (newp != p || _dl_argv[0] != orig_argv0)
193 	{
194 	  if (orig_argv0 == (char *) p)
195 	    {
196 	      if ((char *) newp != _dl_argv[0])
197 		{
198 		  assert ((char *) newp < _dl_argv[0]);
199 		  _dl_argv[0] = memmove ((char *) newp, _dl_argv[0],
200 					 strlen (_dl_argv[0]) + 1);
201 		}
202 	    }
203 	  else
204 	    {
205 	      if ((void *) newp != _dl_hurd_data)
206 		memmove (newp, _dl_hurd_data, sizeof (*_dl_hurd_data));
207 	    }
208 	}
209 
210       {
211 	extern void _dl_start_user (void);
212 	/* Unwind the stack to ARGDATA and simulate a return from _dl_start
213 	   to the RTLD_START code which will run the user's entry point.  */
214 	RETURN_TO (argdata, &_dl_start_user, _dl_hurd_data->user_entry);
215       }
216     }
217 
218   /* Set up so we can do RPCs.  */
219   __mach_init ();
220 
221   /* Initialize frequently used global variable.  */
222   GLRO(dl_pagesize) = __getpagesize ();
223 
224   /* See hurd/hurdstartup.c; this deals with getting information
225      from the exec server and slicing up the arguments.
226      Then it will call `go', above.  */
227   _hurd_startup (start_argptr, &go);
228 
229   LOSE;
230   abort ();
231 }
232 
233 void
_dl_sysdep_start_cleanup(void)234 _dl_sysdep_start_cleanup (void)
235 {
236   /* Deallocate the reply port and task port rights acquired by
237      __mach_init.  We are done with them now, and the user will
238      reacquire them for himself when he wants them.  */
239   __mig_dealloc_reply_port (MACH_PORT_NULL);
240   __mach_port_deallocate (__mach_task_self (), __mach_host_self_);
241   __mach_port_deallocate (__mach_task_self (), __mach_task_self_);
242 }
243 
244 /* Minimal open/close/mmap/etc. implementation sufficient for initial loading of
245    shared libraries.  These are weak definitions so that when the
246    dynamic linker re-relocates itself to be user-visible (for -ldl),
247    it will get the user's definition (i.e. usually libc's).
248 
249    They also need to be set in the libc and ld section of
250    sysdeps/mach/hurd/Versions, to be overridable, and in libc.abilist and
251    ld.abilist to be checked. */
252 
253 /* This macro checks that the function does not get renamed to be hidden: we do
254    need these to be overridable by libc's.  */
255 #define check_no_hidden(name)				\
256   __typeof (name) __check_##name##_no_hidden		\
257        __attribute__ ((alias (#name)))			\
258        __attribute_copy__ (name);
259 
260 /* Open FILE_NAME and return a Hurd I/O for it in *PORT, or return an
261    error.  If STAT is non-zero, stat the file into that stat buffer.  */
262 static error_t
open_file(const char * file_name,int flags,mach_port_t * port,struct stat64 * stat)263 open_file (const char *file_name, int flags,
264 	   mach_port_t *port, struct stat64 *stat)
265 {
266   enum retry_type doretry;
267   char retryname[1024];		/* XXX string_t LOSES! */
268   file_t startdir;
269   error_t err;
270 
271   error_t use_init_port (int which, error_t (*operate) (file_t))
272     {
273       return (which < _dl_hurd_data->portarraysize
274 	      ? ((*operate) (_dl_hurd_data->portarray[which]))
275 	      : EGRATUITOUS);
276     }
277   file_t get_dtable_port (int fd)
278     {
279       if ((unsigned int) fd < _dl_hurd_data->dtablesize
280 	  && _dl_hurd_data->dtable[fd] != MACH_PORT_NULL)
281 	{
282 	  __mach_port_mod_refs (__mach_task_self (), _dl_hurd_data->dtable[fd],
283 				MACH_PORT_RIGHT_SEND, +1);
284 	  return _dl_hurd_data->dtable[fd];
285 	}
286       errno = EBADF;
287       return MACH_PORT_NULL;
288     }
289 
290   assert (!(flags & ~(O_READ | O_EXEC | O_CLOEXEC)));
291   flags &= ~O_CLOEXEC;
292 
293   startdir = _dl_hurd_data->portarray[file_name[0] == '/'
294 				      ? INIT_PORT_CRDIR : INIT_PORT_CWDIR];
295 
296   while (file_name[0] == '/')
297     file_name++;
298 
299   err = __dir_lookup (startdir, (char *)file_name, flags, 0,
300 		      &doretry, retryname, port);
301 
302   if (!err)
303     err = __hurd_file_name_lookup_retry (use_init_port, get_dtable_port,
304 					 __dir_lookup, doretry, retryname,
305 					 O_RDONLY, 0, port);
306   if (!err && stat)
307     {
308       err = __io_stat (*port, stat);
309       if (err)
310 	__mach_port_deallocate (__mach_task_self (), *port);
311     }
312 
313   return err;
314 }
315 
316 check_no_hidden(__open);
317 check_no_hidden (__open64);
318 check_no_hidden (__open_nocancel);
319 int weak_function
__open(const char * file_name,int mode,...)320 __open (const char *file_name, int mode, ...)
321 {
322   mach_port_t port;
323   error_t err = open_file (file_name, mode, &port, 0);
324   if (err)
325     return __hurd_fail (err);
326   else
327     return (int)port;
328 }
329 weak_alias (__open, __open64)
330 weak_alias (__open, __open_nocancel)
331 
332 check_no_hidden(__close);
333 check_no_hidden(__close_nocancel);
334 int weak_function
__close(int fd)335 __close (int fd)
336 {
337   if (fd != (int) MACH_PORT_NULL)
338     __mach_port_deallocate (__mach_task_self (), (mach_port_t) fd);
339   return 0;
340 }
341 weak_alias (__close, __close_nocancel)
342 
343 check_no_hidden(__pread64);
344 check_no_hidden(__pread64_nocancel);
345 __ssize_t weak_function
__pread64(int fd,void * buf,size_t nbytes,off64_t offset)346 __pread64 (int fd, void *buf, size_t nbytes, off64_t offset)
347 {
348   error_t err;
349   char *data;
350   mach_msg_type_number_t nread;
351 
352   data = buf;
353   nread = nbytes;
354   err = __io_read ((mach_port_t) fd, &data, &nread, offset, nbytes);
355   if (err)
356     return __hurd_fail (err);
357 
358   if (data != buf)
359     {
360       memcpy (buf, data, nread);
361       __vm_deallocate (__mach_task_self (), (vm_address_t) data, nread);
362     }
363 
364   return nread;
365 }
366 libc_hidden_weak (__pread64)
367 weak_alias (__pread64, __pread64_nocancel)
368 
369 check_no_hidden(__read);
370 check_no_hidden(__read_nocancel);
371 __ssize_t weak_function
__read(int fd,void * buf,size_t nbytes)372 __read (int fd, void *buf, size_t nbytes)
373 {
374   return __pread64 (fd, buf, nbytes, -1);
375 }
376 libc_hidden_weak (__read)
377 weak_alias (__read, __read_nocancel)
378 
379 check_no_hidden(__write);
380 check_no_hidden(__write_nocancel);
381 __ssize_t weak_function
__write(int fd,const void * buf,size_t nbytes)382 __write (int fd, const void *buf, size_t nbytes)
383 {
384   error_t err;
385   mach_msg_type_number_t nwrote;
386 
387   assert (fd < _hurd_init_dtablesize);
388 
389   err = __io_write (_hurd_init_dtable[fd], buf, nbytes, -1, &nwrote);
390   if (err)
391     return __hurd_fail (err);
392 
393   return nwrote;
394 }
395 libc_hidden_weak (__write)
396   weak_alias (__write, __write_nocancel)
397 
398 /* This is only used for printing messages (see dl-misc.c).  */
399 check_no_hidden(__writev);
400 __ssize_t weak_function
__writev(int fd,const struct iovec * iov,int niov)401 __writev (int fd, const struct iovec *iov, int niov)
402 {
403   if (fd >= _hurd_init_dtablesize)
404     {
405       errno = EBADF;
406       return -1;
407     }
408 
409   int i;
410   size_t total = 0;
411   for (i = 0; i < niov; ++i)
412     total += iov[i].iov_len;
413 
414   if (total != 0)
415     {
416       char buf[total], *bufp = buf;
417       error_t err;
418       mach_msg_type_number_t nwrote;
419 
420       for (i = 0; i < niov; ++i)
421 	bufp = (memcpy (bufp, iov[i].iov_base, iov[i].iov_len)
422 		+ iov[i].iov_len);
423 
424       err = __io_write (_hurd_init_dtable[fd], buf, total, -1, &nwrote);
425       if (err)
426 	return __hurd_fail (err);
427 
428       return nwrote;
429     }
430   return 0;
431 }
432 
433 check_no_hidden(__libc_lseek64);
434 off64_t weak_function
__libc_lseek64(int fd,off64_t offset,int whence)435 __libc_lseek64 (int fd, off64_t offset, int whence)
436 {
437   error_t err;
438 
439   err = __io_seek ((mach_port_t) fd, offset, whence, &offset);
440   if (err)
441     return __hurd_fail (err);
442 
443   return offset;
444 }
445 
446 check_no_hidden(__mmap);
447 void *weak_function
__mmap(void * addr,size_t len,int prot,int flags,int fd,off_t offset)448 __mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset)
449 {
450   error_t err;
451   vm_prot_t vmprot;
452   vm_address_t mapaddr;
453   mach_port_t memobj_rd, memobj_wr;
454 
455   vmprot = VM_PROT_NONE;
456   if (prot & PROT_READ)
457     vmprot |= VM_PROT_READ;
458   if (prot & PROT_WRITE)
459     vmprot |= VM_PROT_WRITE;
460   if (prot & PROT_EXEC)
461     vmprot |= VM_PROT_EXECUTE;
462 
463   if (flags & MAP_ANON)
464     memobj_rd = MACH_PORT_NULL;
465   else
466     {
467       assert (!(flags & MAP_SHARED));
468       err = __io_map ((mach_port_t) fd, &memobj_rd, &memobj_wr);
469       if (err)
470 	return __hurd_fail (err), MAP_FAILED;
471       if (memobj_wr != MACH_PORT_NULL)
472 	__mach_port_deallocate (__mach_task_self (), memobj_wr);
473     }
474 
475   mapaddr = (vm_address_t) addr;
476   err = __vm_map (__mach_task_self (),
477 		  &mapaddr, (vm_size_t) len, 0,
478 		  !(flags & MAP_FIXED),
479 		  memobj_rd,
480 		  (vm_offset_t) offset,
481 		  flags & (MAP_COPY|MAP_PRIVATE),
482 		  vmprot, VM_PROT_ALL,
483 		  (flags & MAP_SHARED) ? VM_INHERIT_SHARE : VM_INHERIT_COPY);
484   if (err == KERN_NO_SPACE && (flags & MAP_FIXED))
485     {
486       /* XXX this is not atomic as it is in unix! */
487       /* The region is already allocated; deallocate it first.  */
488       err = __vm_deallocate (__mach_task_self (), mapaddr, len);
489       if (! err)
490 	err = __vm_map (__mach_task_self (),
491 			&mapaddr, (vm_size_t) len,
492 			0,
493 			!(flags & MAP_FIXED),
494 			memobj_rd, (vm_offset_t) offset,
495 			flags & (MAP_COPY|MAP_PRIVATE),
496 			vmprot, VM_PROT_ALL,
497 			(flags & MAP_SHARED)
498 			? VM_INHERIT_SHARE : VM_INHERIT_COPY);
499     }
500 
501   if ((flags & MAP_ANON) == 0)
502     __mach_port_deallocate (__mach_task_self (), memobj_rd);
503 
504   if (err)
505     return __hurd_fail (err), MAP_FAILED;
506   return (void *) mapaddr;
507 }
508 
509 check_no_hidden(__fstat64);
510 int weak_function
__fstat64(int fd,struct stat64 * buf)511 __fstat64 (int fd, struct stat64 *buf)
512 {
513   error_t err;
514 
515   err = __io_stat ((mach_port_t) fd, buf);
516   if (err)
517     return __hurd_fail (err);
518 
519   return 0;
520 }
521 libc_hidden_def (__fstat64)
522 
523 check_no_hidden(__stat64);
524 int weak_function
__stat64(const char * file,struct stat64 * buf)525 __stat64 (const char *file, struct stat64 *buf)
526 {
527   error_t err;
528   mach_port_t port;
529 
530   err = open_file (file, 0, &port, buf);
531   if (err)
532     return __hurd_fail (err);
533 
534   __mach_port_deallocate (__mach_task_self (), port);
535 
536   return 0;
537 }
538 libc_hidden_def (__stat64)
539 
540 /* This function is called by the dynamic linker (rtld.c) to check
541    whether debugging malloc is allowed even for SUID binaries.  This
542    stub will always fail, which means that malloc-debugging is always
543    disabled for SUID binaries.  */
544 check_no_hidden(__access);
545 int weak_function
__access(const char * file,int type)546 __access (const char *file, int type)
547 {
548   errno = ENOSYS;
549   return -1;
550 }
551 check_no_hidden(__access_noerrno);
552 int weak_function
__access_noerrno(const char * file,int type)553 __access_noerrno (const char *file, int type)
554 {
555   return -1;
556 }
557 
558 int
__rtld_execve(const char * file_name,char * const argv[],char * const envp[])559 __rtld_execve (const char *file_name, char *const argv[],
560                char *const envp[])
561 {
562   file_t file;
563   error_t err;
564   char *args, *env;
565   size_t argslen, envlen;
566   mach_port_t *ports = _dl_hurd_data->portarray;
567   unsigned int portarraysize = _dl_hurd_data->portarraysize;
568   file_t *dtable = _dl_hurd_data->dtable;
569   unsigned int dtablesize = _dl_hurd_data->dtablesize;
570   int *intarray = _dl_hurd_data->intarray;
571   unsigned int i, j;
572   mach_port_t *please_dealloc, *pdp;
573   mach_port_t *portnames = NULL;
574   mach_msg_type_number_t nportnames = 0;
575   mach_port_type_t *porttypes = NULL;
576   mach_msg_type_number_t nporttypes = 0;
577   int flags;
578 
579   err = open_file (file_name, O_EXEC, &file, NULL);
580   if (err)
581     goto out;
582 
583   if (argv == NULL)
584     args = NULL, argslen = 0;
585   else if (err = __argz_create (argv, &args, &argslen))
586     goto outfile;
587   if (envp == NULL)
588     env = NULL, envlen = 0;
589   else if (err = __argz_create (envp, &env, &envlen))
590     goto outargs;
591 
592   please_dealloc = __alloca ((portarraysize + dtablesize)
593 			     * sizeof (mach_port_t));
594   pdp = please_dealloc;
595 
596   /* Get all ports that we may not know about and we should thus destroy.  */
597   err = __mach_port_names (__mach_task_self (),
598 			   &portnames, &nportnames,
599 			   &porttypes, &nporttypes);
600   if (err)
601     goto outenv;
602   if (nportnames != nporttypes)
603     {
604       err = EGRATUITOUS;
605       goto outenv;
606     }
607 
608   for (i = 0; i < portarraysize; ++i)
609     if (ports[i] != MACH_PORT_NULL)
610       {
611 	*pdp++ = ports[i];
612 	for (j = 0; j < nportnames; j++)
613 	  if (portnames[j] == ports[i])
614 	    portnames[j] = MACH_PORT_NULL;
615       }
616   for (i = 0; i < dtablesize; ++i)
617     if (dtable[i] != MACH_PORT_NULL)
618       {
619 	*pdp++ = dtable[i];
620 	for (j = 0; j < nportnames; j++)
621 	  if (portnames[j] == dtable[i])
622 	    portnames[j] = MACH_PORT_NULL;
623       }
624 
625   /* Pack ports to be destroyed together.  */
626   for (i = 0, j = 0; i < nportnames; i++)
627     {
628       if (portnames[i] == MACH_PORT_NULL)
629 	continue;
630       if (j != i)
631 	portnames[j] = portnames[i];
632       j++;
633     }
634   nportnames = j;
635 
636   flags = 0;
637 #ifdef EXEC_SIGTRAP
638   if (__sigismember (&intarray[INIT_TRACEMASK], SIGKILL))
639     flags |= EXEC_SIGTRAP;
640 #endif
641 
642   err = __file_exec_paths (file, __mach_task_self (), flags,
643 			   file_name, file_name[0] == '/' ? file_name : "",
644 			   args, argslen,
645 			   env, envlen,
646 			   dtable, MACH_MSG_TYPE_COPY_SEND, dtablesize,
647 			   ports, MACH_MSG_TYPE_COPY_SEND, portarraysize,
648 			   intarray, INIT_INT_MAX,
649 			   please_dealloc, pdp - please_dealloc,
650 			   portnames, nportnames);
651 
652   /* Oh well.  Might as well be tidy.  */
653 outenv:
654   free (env);
655 outargs:
656   free (args);
657 outfile:
658   __mach_port_deallocate (__mach_task_self (), file);
659 out:
660   return err;
661 }
662 
663 check_no_hidden(__getpid);
664 pid_t weak_function
__getpid(void)665 __getpid (void)
666 {
667   pid_t pid, ppid;
668   int orphaned;
669 
670   if (__proc_getpids (_dl_hurd_data->portarray[INIT_PORT_PROC],
671 		      &pid, &ppid, &orphaned))
672     return -1;
673 
674   return pid;
675 }
676 
677 /* We need this alias to satisfy references from libc_pic.a objects
678    that were affected by the libc_hidden_proto declaration for __getpid.  */
679 strong_alias (__getpid, __GI___getpid)
680 
681 /* This is called only in some strange cases trying to guess a value
682    for $ORIGIN for the executable.  The dynamic linker copes with
683    getcwd failing (dl-object.c), and it's too much hassle to include
684    the functionality here.  (We could, it just requires duplicating or
685    reusing getcwd.c's code but using our special lookup function as in
686    `open', above.)  */
687 check_no_hidden(__getcwd);
688 char *weak_function
__getcwd(char * buf,size_t size)689 __getcwd (char *buf, size_t size)
690 {
691   errno = ENOSYS;
692   return NULL;
693 }
694 
695 /* This is used by dl-tunables.c to strdup strings.  We can just make this a
696    mere allocation.  */
697 check_no_hidden(__sbrk);
698 void *weak_function
__sbrk(intptr_t increment)699 __sbrk (intptr_t increment)
700 {
701   vm_address_t addr;
702   __vm_allocate (__mach_task_self (), &addr, increment, 1);
703   return (void *) addr;
704 }
705 
706 /* This is only used by hurdlookup for the /dev/fd/nnn magic.
707  * We avoid pulling the whole libc implementation, and we can keep this hidden.  */
708 unsigned long int weak_function
__strtoul_internal(const char * nptr,char ** endptr,int base,int group)709 __strtoul_internal (const char *nptr, char **endptr, int base, int group)
710 {
711   assert (base == 0 || base == 10);
712   assert (group == 0);
713   return _dl_strtoul (nptr, endptr);
714 }
715 
716 /* We need this alias to satisfy references from libc_pic.a objects
717    that were affected by the libc_hidden_proto declaration for __strtoul_internal.  */
718 strong_alias (__strtoul_internal, __GI___strtoul_internal)
719 strong_alias (__strtoul_internal, __GI_____strtoul_internal)
720 
721 check_no_hidden(_exit);
722 void weak_function attribute_hidden
_exit(int status)723 _exit (int status)
724 {
725   __proc_mark_exit (_dl_hurd_data->portarray[INIT_PORT_PROC],
726 		    W_EXITCODE (status, 0), 0);
727   while (__task_terminate (__mach_task_self ()))
728     __mach_task_self_ = (__mach_task_self) ();
729 
730   LOSE;
731   abort ();
732 }
733 /* We need this alias to satisfy references from libc_pic.a objects
734    that were affected by the libc_hidden_proto declaration for _exit.  */
735 strong_alias (_exit, __GI__exit)
736 
737 /* Try to get a machine dependent instruction which will make the
738    program crash.  This is used in case everything else fails.  */
739 #include <abort-instr.h>
740 #ifndef ABORT_INSTRUCTION
741 /* No such instruction is available.  */
742 # define ABORT_INSTRUCTION
743 #endif
744 
745 check_no_hidden(abort);
746 void weak_function
abort(void)747 abort (void)
748 {
749   /* Try to abort using the system specific command.  */
750   ABORT_INSTRUCTION;
751 
752   /* If the abort instruction failed, exit.  */
753   _exit (127);
754 
755   /* If even this fails, make sure we never return.  */
756   while (1)
757     /* Try for ever and ever.  */
758     ABORT_INSTRUCTION;
759 }
760 
761 /* We need this alias to satisfy references from libc_pic.a objects
762    that were affected by the libc_hidden_proto declaration for abort.  */
strong_alias(abort,__GI_abort)763 strong_alias (abort, __GI_abort)
764 strong_alias (abort, __GI___fortify_fail)
765 strong_alias (abort, __GI___assert_fail)
766 strong_alias (abort, __GI___assert_perror_fail)
767 
768 /* This function is called by interruptible RPC stubs.  For initial
769    dynamic linking, just use the normal mach_msg.  Since this defn is
770    weak, the real defn in libc.so will override it if we are linked into
771    the user program (-ldl).  */
772 
773 error_t weak_function
774 _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg,
775 			 mach_msg_option_t option,
776 			 mach_msg_size_t send_size,
777 			 mach_msg_size_t rcv_size,
778 			 mach_port_t rcv_name,
779 			 mach_msg_timeout_t timeout,
780 			 mach_port_t notify)
781 {
782   return __mach_msg (msg, option, send_size, rcv_size, rcv_name,
783 		     timeout, notify);
784 }
785 
786 
787 void
_dl_show_auxv(void)788 _dl_show_auxv (void)
789 {
790   /* There is nothing to print.  Hurd has no auxiliary vector.  */
791 }
792 
793 
794 void weak_function
_dl_init_first(int argc,...)795 _dl_init_first (int argc, ...)
796 {
797   /* This no-op definition only gets used if libc is not linked in.  */
798 }
799 
800 #endif /* SHARED */
801