1  /* Operating system support for run-time dynamic linker.  Hurd version.
       2     Copyright (C) 1995-2023 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)
      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        _dl_init_first (argdata);
     211  
     212        {
     213  	extern void _dl_start_user (void);
     214  	/* Unwind the stack to ARGDATA and simulate a return from _dl_start
     215  	   to the RTLD_START code which will run the user's entry point.  */
     216  	RETURN_TO (argdata, &_dl_start_user, _dl_hurd_data->user_entry);
     217        }
     218      }
     219  
     220    /* Set up so we can do RPCs.  */
     221    __mach_init ();
     222  
     223    /* Initialize frequently used global variable.  */
     224    GLRO(dl_pagesize) = __getpagesize ();
     225  
     226    /* See hurd/hurdstartup.c; this deals with getting information
     227       from the exec server and slicing up the arguments.
     228       Then it will call `go', above.  */
     229    _hurd_startup (start_argptr, &go);
     230  
     231    LOSE;
     232    abort ();
     233  }
     234  
     235  void
     236  _dl_sysdep_start_cleanup (void)
     237  {
     238    /* Deallocate the reply port and task port rights acquired by
     239       __mach_init.  We are done with them now, and the user will
     240       reacquire them for himself when he wants them.  */
     241    __mig_dealloc_reply_port (__mig_get_reply_port ());
     242    __mach_port_deallocate (__mach_task_self (), __mach_host_self_);
     243    __mach_port_deallocate (__mach_task_self (), __mach_task_self_);
     244  }
     245  
     246  /* Minimal open/close/mmap/etc. implementation sufficient for initial loading of
     247     shared libraries.  These are weak definitions so that when the
     248     dynamic linker re-relocates itself to be user-visible (for -ldl),
     249     it will get the user's definition (i.e. usually libc's).
     250  
     251     They also need to be set in the libc and ld section of
     252     sysdeps/mach/hurd/Versions, to be overridable, and in libc.abilist and
     253     ld.abilist to be checked. */
     254  
     255  /* This macro checks that the function does not get renamed to be hidden: we do
     256     need these to be overridable by libc's.  */
     257  #define check_no_hidden(name)				\
     258    __typeof (name) __check_##name##_no_hidden		\
     259         __attribute__ ((alias (#name)))			\
     260         __attribute_copy__ (name);
     261  
     262  /* Open FILE_NAME and return a Hurd I/O for it in *PORT, or return an
     263     error.  If STAT is non-zero, stat the file into that stat buffer.  */
     264  static error_t
     265  open_file (const char *file_name, int flags,
     266  	   mach_port_t *port, struct stat64 *stat)
     267  {
     268    enum retry_type doretry;
     269    char retryname[1024];		/* XXX string_t LOSES! */
     270    file_t startdir;
     271    error_t err;
     272  
     273    error_t use_init_port (int which, error_t (*operate) (file_t))
     274      {
     275        return (which < _dl_hurd_data->portarraysize
     276  	      ? ((*operate) (_dl_hurd_data->portarray[which]))
     277  	      : EGRATUITOUS);
     278      }
     279    file_t get_dtable_port (int fd)
     280      {
     281        if ((unsigned int) fd < _dl_hurd_data->dtablesize
     282  	  && _dl_hurd_data->dtable[fd] != MACH_PORT_NULL)
     283  	{
     284  	  __mach_port_mod_refs (__mach_task_self (), _dl_hurd_data->dtable[fd],
     285  				MACH_PORT_RIGHT_SEND, +1);
     286  	  return _dl_hurd_data->dtable[fd];
     287  	}
     288        return __hurd_fail (EBADF), MACH_PORT_NULL;
     289      }
     290  
     291    assert (!(flags & ~(O_READ | O_EXEC | O_CLOEXEC | O_IGNORE_CTTY)));
     292    flags &= ~(O_CLOEXEC | O_IGNORE_CTTY);
     293  
     294    startdir = _dl_hurd_data->portarray[file_name[0] == '/'
     295  				      ? INIT_PORT_CRDIR : INIT_PORT_CWDIR];
     296  
     297    while (file_name[0] == '/')
     298      file_name++;
     299  
     300    err = __dir_lookup (startdir, (char *)file_name, flags, 0,
     301  		      &doretry, retryname, port);
     302  
     303    if (!err)
     304      err = __hurd_file_name_lookup_retry (use_init_port, get_dtable_port,
     305  					 __dir_lookup, doretry, retryname,
     306  					 flags, 0, port);
     307    if (!err && stat)
     308      {
     309        err = __io_stat (*port, stat);
     310        if (err)
     311  	__mach_port_deallocate (__mach_task_self (), *port);
     312      }
     313  
     314    return err;
     315  }
     316  
     317  check_no_hidden(__open);
     318  check_no_hidden (__open64);
     319  check_no_hidden (__open_nocancel);
     320  int weak_function
     321  __open (const char *file_name, int mode, ...)
     322  {
     323    mach_port_t port;
     324    error_t err = open_file (file_name, mode, &port, 0);
     325    if (err)
     326      return __hurd_fail (err);
     327    else
     328      return (int)port;
     329  }
     330  weak_alias (__open, __open64)
     331  weak_alias (__open, __open_nocancel)
     332  
     333  check_no_hidden(__close);
     334  check_no_hidden(__close_nocancel);
     335  int weak_function
     336  __close (int fd)
     337  {
     338    if (fd != (int) MACH_PORT_NULL)
     339      __mach_port_deallocate (__mach_task_self (), (mach_port_t) fd);
     340    return 0;
     341  }
     342  weak_alias (__close, __close_nocancel)
     343  
     344  check_no_hidden(__pread64);
     345  check_no_hidden(__pread64_nocancel);
     346  __ssize_t weak_function
     347  __pread64 (int fd, void *buf, size_t nbytes, off64_t offset)
     348  {
     349    error_t err;
     350    char *data;
     351    mach_msg_type_number_t nread;
     352  
     353    data = buf;
     354    nread = nbytes;
     355    err = __io_read ((mach_port_t) fd, &data, &nread, offset, nbytes);
     356    if (err)
     357      return __hurd_fail (err);
     358  
     359    if (data != buf)
     360      {
     361        memcpy (buf, data, nread);
     362        __vm_deallocate (__mach_task_self (), (vm_address_t) data, nread);
     363      }
     364  
     365    return nread;
     366  }
     367  libc_hidden_weak (__pread64)
     368  weak_alias (__pread64, __pread64_nocancel)
     369  
     370  check_no_hidden(__read);
     371  check_no_hidden(__read_nocancel);
     372  __ssize_t weak_function
     373  __read (int fd, void *buf, size_t nbytes)
     374  {
     375    return __pread64 (fd, buf, nbytes, -1);
     376  }
     377  libc_hidden_weak (__read)
     378  weak_alias (__read, __read_nocancel)
     379  
     380  check_no_hidden(__write);
     381  check_no_hidden(__write_nocancel);
     382  __ssize_t weak_function
     383  __write (int fd, const void *buf, size_t nbytes)
     384  {
     385    error_t err;
     386    vm_size_t nwrote;
     387  
     388    assert (fd < _hurd_init_dtablesize);
     389  
     390    err = __io_write (_hurd_init_dtable[fd], buf, nbytes, -1, &nwrote);
     391    if (err)
     392      return __hurd_fail (err);
     393  
     394    return nwrote;
     395  }
     396  libc_hidden_weak (__write)
     397    weak_alias (__write, __write_nocancel)
     398  
     399  /* This is only used for printing messages (see dl-misc.c).  */
     400  check_no_hidden(__writev);
     401  __ssize_t weak_function
     402  __writev (int fd, const struct iovec *iov, int niov)
     403  {
     404    if (fd >= _hurd_init_dtablesize)
     405      return __hurd_fail (EBADF);
     406  
     407    int i;
     408    size_t total = 0;
     409    for (i = 0; i < niov; ++i)
     410      total += iov[i].iov_len;
     411  
     412    if (total != 0)
     413      {
     414        char buf[total], *bufp = buf;
     415        error_t err;
     416        vm_size_t nwrote;
     417  
     418        for (i = 0; i < niov; ++i)
     419  	bufp = (memcpy (bufp, iov[i].iov_base, iov[i].iov_len)
     420  		+ iov[i].iov_len);
     421  
     422        err = __io_write (_hurd_init_dtable[fd], buf, total, -1, &nwrote);
     423        if (err)
     424  	return __hurd_fail (err);
     425  
     426        return nwrote;
     427      }
     428    return 0;
     429  }
     430  
     431  check_no_hidden(__libc_lseek64);
     432  off64_t weak_function
     433  __libc_lseek64 (int fd, off64_t offset, int whence)
     434  {
     435    error_t err;
     436  
     437    err = __io_seek ((mach_port_t) fd, offset, whence, &offset);
     438    if (err)
     439      return __hurd_fail (err);
     440  
     441    return offset;
     442  }
     443  
     444  check_no_hidden(__mmap);
     445  void *weak_function
     446  __mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset)
     447  {
     448    error_t err;
     449    vm_prot_t vmprot;
     450    vm_address_t mapaddr, mask;
     451    mach_port_t memobj_rd, memobj_wr;
     452  
     453    vmprot = VM_PROT_NONE;
     454    if (prot & PROT_READ)
     455      vmprot |= VM_PROT_READ;
     456    if (prot & PROT_WRITE)
     457      vmprot |= VM_PROT_WRITE;
     458    if (prot & PROT_EXEC)
     459      vmprot |= VM_PROT_EXECUTE;
     460  
     461  #ifdef __LP64__
     462    if ((addr == NULL) && (prot & PROT_EXEC)
     463        && HAS_ARCH_FEATURE (Prefer_MAP_32BIT_EXEC))
     464      flags |= MAP_32BIT;
     465  #endif
     466    mask = (flags & MAP_32BIT) ? ~(vm_address_t) 0x7FFFFFFF : 0;
     467  
     468    if (flags & MAP_ANON)
     469      memobj_rd = MACH_PORT_NULL;
     470    else
     471      {
     472        assert (!(flags & MAP_SHARED));
     473        err = __io_map ((mach_port_t) fd, &memobj_rd, &memobj_wr);
     474        if (err)
     475  	return __hurd_fail (err), MAP_FAILED;
     476        if (MACH_PORT_VALID (memobj_wr))
     477  	__mach_port_deallocate (__mach_task_self (), memobj_wr);
     478      }
     479  
     480    mapaddr = (vm_address_t) addr;
     481    err = __vm_map (__mach_task_self (),
     482  		  &mapaddr, (vm_size_t) len, mask,
     483  		  !(flags & MAP_FIXED),
     484  		  memobj_rd,
     485  		  (vm_offset_t) offset,
     486  		  flags & (MAP_COPY|MAP_PRIVATE),
     487  		  vmprot, VM_PROT_ALL,
     488  		  (flags & MAP_SHARED) ? VM_INHERIT_SHARE : VM_INHERIT_COPY);
     489    if (err == KERN_NO_SPACE && (flags & MAP_FIXED))
     490      {
     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);
     494        if (! err)
     495  	err = __vm_map (__mach_task_self (),
     496  			&mapaddr, (vm_size_t) len,
     497  			mask,
     498  			!(flags & MAP_FIXED),
     499  			memobj_rd, (vm_offset_t) offset,
     500  			flags & (MAP_COPY|MAP_PRIVATE),
     501  			vmprot, VM_PROT_ALL,
     502  			(flags & MAP_SHARED)
     503  			? VM_INHERIT_SHARE : VM_INHERIT_COPY);
     504      }
     505  
     506    if ((flags & MAP_ANON) == 0)
     507      __mach_port_deallocate (__mach_task_self (), memobj_rd);
     508  
     509    if (err)
     510      return __hurd_fail (err), MAP_FAILED;
     511    return (void *) mapaddr;
     512  }
     513  
     514  check_no_hidden(__fstat64);
     515  int weak_function
     516  __fstat64 (int fd, struct stat64 *buf)
     517  {
     518    error_t err;
     519  
     520    err = __io_stat ((mach_port_t) fd, buf);
     521    if (err)
     522      return __hurd_fail (err);
     523  
     524    return 0;
     525  }
     526  libc_hidden_def (__fstat64)
     527  
     528  check_no_hidden(__stat64);
     529  int weak_function
     530  __stat64 (const char *file, struct stat64 *buf)
     531  {
     532    error_t err;
     533    mach_port_t port;
     534  
     535    err = open_file (file, 0, &port, buf);
     536    if (err)
     537      return __hurd_fail (err);
     538  
     539    __mach_port_deallocate (__mach_task_self (), port);
     540  
     541    return 0;
     542  }
     543  libc_hidden_def (__stat64)
     544  
     545  /* This function is called by the dynamic linker (rtld.c) to check
     546     whether debugging malloc is allowed even for SUID binaries.  This
     547     stub will always fail, which means that malloc-debugging is always
     548     disabled for SUID binaries.  */
     549  check_no_hidden(__access);
     550  int weak_function
     551  __access (const char *file, int type)
     552  {
     553    return __hurd_fail (ENOSYS);
     554  }
     555  check_no_hidden(__access_noerrno);
     556  int weak_function
     557  __access_noerrno (const char *file, int type)
     558  {
     559    return -1;
     560  }
     561  
     562  int
     563  __rtld_execve (const char *file_name, char *const argv[],
     564                 char *const envp[])
     565  {
     566    file_t file;
     567    error_t err;
     568    char *args, *env;
     569    size_t argslen, envlen;
     570    mach_port_t *ports = _dl_hurd_data->portarray;
     571    unsigned int portarraysize = _dl_hurd_data->portarraysize;
     572    file_t *dtable = _dl_hurd_data->dtable;
     573    unsigned int dtablesize = _dl_hurd_data->dtablesize;
     574    int *intarray = _dl_hurd_data->intarray;
     575    unsigned int i, j;
     576    mach_port_t *please_dealloc, *pdp;
     577    mach_port_t *portnames = NULL;
     578    mach_msg_type_number_t nportnames = 0;
     579    mach_port_type_t *porttypes = NULL;
     580    mach_msg_type_number_t nporttypes = 0;
     581    int flags;
     582  
     583    err = open_file (file_name, O_EXEC, &file, NULL);
     584    if (err)
     585      goto out;
     586  
     587    if (argv == NULL)
     588      args = NULL, argslen = 0;
     589    else if (err = __argz_create (argv, &args, &argslen))
     590      goto outfile;
     591    if (envp == NULL)
     592      env = NULL, envlen = 0;
     593    else if (err = __argz_create (envp, &env, &envlen))
     594      goto outargs;
     595  
     596    please_dealloc = __alloca ((portarraysize + dtablesize)
     597  			     * sizeof (mach_port_t));
     598    pdp = please_dealloc;
     599  
     600    /* Get all ports that we may not know about and we should thus destroy.  */
     601    err = __mach_port_names (__mach_task_self (),
     602  			   &portnames, &nportnames,
     603  			   &porttypes, &nporttypes);
     604    if (err)
     605      goto outenv;
     606    if (nportnames != nporttypes)
     607      {
     608        err = EGRATUITOUS;
     609        goto outenv;
     610      }
     611  
     612    for (i = 0; i < portarraysize; ++i)
     613      if (ports[i] != MACH_PORT_NULL)
     614        {
     615  	*pdp++ = ports[i];
     616  	for (j = 0; j < nportnames; j++)
     617  	  if (portnames[j] == ports[i])
     618  	    portnames[j] = MACH_PORT_NULL;
     619        }
     620    for (i = 0; i < dtablesize; ++i)
     621      if (dtable[i] != MACH_PORT_NULL)
     622        {
     623  	*pdp++ = dtable[i];
     624  	for (j = 0; j < nportnames; j++)
     625  	  if (portnames[j] == dtable[i])
     626  	    portnames[j] = MACH_PORT_NULL;
     627        }
     628  
     629    /* Pack ports to be destroyed together.  */
     630    for (i = 0, j = 0; i < nportnames; i++)
     631      {
     632        if (portnames[i] == MACH_PORT_NULL)
     633  	continue;
     634        if (j != i)
     635  	portnames[j] = portnames[i];
     636        j++;
     637      }
     638    nportnames = j;
     639  
     640    flags = 0;
     641  #ifdef EXEC_SIGTRAP
     642    if (__sigismember (&intarray[INIT_TRACEMASK], SIGKILL))
     643      flags |= EXEC_SIGTRAP;
     644  #endif
     645  
     646    err = __file_exec_paths (file, __mach_task_self (), flags,
     647  			   file_name, file_name[0] == '/' ? file_name : "",
     648  			   args, argslen,
     649  			   env, envlen,
     650  			   dtable, MACH_MSG_TYPE_COPY_SEND, dtablesize,
     651  			   ports, MACH_MSG_TYPE_COPY_SEND, portarraysize,
     652  			   intarray, INIT_INT_MAX,
     653  			   please_dealloc, pdp - please_dealloc,
     654  			   portnames, nportnames);
     655  
     656    /* Oh well.  Might as well be tidy.  */
     657  outenv:
     658    free (env);
     659  outargs:
     660    free (args);
     661  outfile:
     662    __mach_port_deallocate (__mach_task_self (), file);
     663  out:
     664    return err;
     665  }
     666  
     667  check_no_hidden(__getpid);
     668  pid_t weak_function
     669  __getpid (void)
     670  {
     671    pid_t pid, ppid;
     672    int orphaned;
     673  
     674    if (__proc_getpids (_dl_hurd_data->portarray[INIT_PORT_PROC],
     675  		      &pid, &ppid, &orphaned))
     676      return -1;
     677  
     678    return pid;
     679  }
     680  
     681  /* We need this alias to satisfy references from libc_pic.a objects
     682     that were affected by the libc_hidden_proto declaration for __getpid.  */
     683  strong_alias (__getpid, __GI___getpid)
     684  
     685  /* This is called only in some strange cases trying to guess a value
     686     for $ORIGIN for the executable.  The dynamic linker copes with
     687     getcwd failing (dl-object.c), and it's too much hassle to include
     688     the functionality here.  (We could, it just requires duplicating or
     689     reusing getcwd.c's code but using our special lookup function as in
     690     `open', above.)  */
     691  check_no_hidden(__getcwd);
     692  char *weak_function
     693  __getcwd (char *buf, size_t size)
     694  {
     695    return __hurd_fail (ENOSYS), NULL;
     696  }
     697  
     698  /* This is used by dl-tunables.c to strdup strings.  We can just make this a
     699     mere allocation.  */
     700  check_no_hidden(__sbrk);
     701  void *weak_function
     702  __sbrk (intptr_t increment)
     703  {
     704    vm_address_t addr;
     705    if (__vm_allocate (__mach_task_self (), &addr, increment, 1))
     706      return NULL;
     707    return (void *) addr;
     708  }
     709  
     710  /* This is only used by hurdlookup for the /dev/fd/nnn magic.
     711   * We avoid pulling the whole libc implementation, and we can keep this hidden.  */
     712  unsigned long int weak_function
     713  __strtoul_internal (const char *nptr, char **endptr, int base, int group)
     714  {
     715    assert (base == 0 || base == 10);
     716    assert (group == 0);
     717    return _dl_strtoul (nptr, endptr);
     718  }
     719  
     720  /* We need this alias to satisfy references from libc_pic.a objects
     721     that were affected by the libc_hidden_proto declaration for __strtoul_internal.  */
     722  strong_alias (__strtoul_internal, __GI___strtoul_internal)
     723  strong_alias (__strtoul_internal, __GI_____strtoul_internal)
     724  
     725  check_no_hidden(_exit);
     726  void weak_function attribute_hidden
     727  _exit (int status)
     728  {
     729    __proc_mark_exit (_dl_hurd_data->portarray[INIT_PORT_PROC],
     730  		    W_EXITCODE (status, 0), 0);
     731    while (__task_terminate (__mach_task_self ()))
     732      __mach_task_self_ = (__mach_task_self) ();
     733  
     734    LOSE;
     735    abort ();
     736  }
     737  /* We need this alias to satisfy references from libc_pic.a objects
     738     that were affected by the libc_hidden_proto declaration for _exit.  */
     739  strong_alias (_exit, __GI__exit)
     740  
     741  /* Try to get a machine dependent instruction which will make the
     742     program crash.  This is used in case everything else fails.  */
     743  #include <abort-instr.h>
     744  #ifndef ABORT_INSTRUCTION
     745  /* No such instruction is available.  */
     746  # define ABORT_INSTRUCTION
     747  #endif
     748  
     749  check_no_hidden(abort);
     750  void weak_function
     751  abort (void)
     752  {
     753    /* Try to abort using the system specific command.  */
     754    ABORT_INSTRUCTION;
     755  
     756    /* If the abort instruction failed, exit.  */
     757    _exit (127);
     758  
     759    /* If even this fails, make sure we never return.  */
     760    while (1)
     761      /* Try for ever and ever.  */
     762      ABORT_INSTRUCTION;
     763  }
     764  
     765  /* We need this alias to satisfy references from libc_pic.a objects
     766     that were affected by the libc_hidden_proto declaration for abort.  */
     767  strong_alias (abort, __GI_abort)
     768  strong_alias (abort, __GI___fortify_fail)
     769  strong_alias (abort, __GI___assert_fail)
     770  strong_alias (abort, __GI___assert_perror_fail)
     771  
     772  /* This function is called by interruptible RPC stubs.  For initial
     773     dynamic linking, just use the normal mach_msg.  Since this defn is
     774     weak, the real defn in libc.so will override it if we are linked into
     775     the user program (-ldl).  */
     776  
     777  error_t weak_function
     778  _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg,
     779  			 mach_msg_option_t option,
     780  			 mach_msg_size_t send_size,
     781  			 mach_msg_size_t rcv_size,
     782  			 mach_port_t rcv_name,
     783  			 mach_msg_timeout_t timeout,
     784  			 mach_port_t notify)
     785  {
     786    return __mach_msg (msg, option, send_size, rcv_size, rcv_name,
     787  		     timeout, notify);
     788  }
     789  
     790  
     791  void
     792  _dl_show_auxv (void)
     793  {
     794    /* There is nothing to print.  Hurd has no auxiliary vector.  */
     795  }
     796  
     797  
     798  void weak_function
     799  _dl_init_first (void *p)
     800  {
     801    /* This no-op definition only gets used if libc is not linked in.  */
     802  }
     803  
     804  #endif /* SHARED */