Add new parameter to _dl_map_object calls.
[kopensolaris-gnu/glibc.git] / sysdeps / mach / hurd / dl-sysdep.c
1 /* Operating system support for run-time dynamic linker.  Hurd version.
2    Copyright (C) 1995, 96, 97, 98, 99, 2000 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 Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    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    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #include <hurd.h>
21 #include <link.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <stdlib.h>
25 #include <sys/mman.h>
26 #include <ldsodefs.h>
27 #include <sys/wait.h>
28 #include <assert.h>
29 #include <sysdep.h>
30 #include <mach/mig_support.h>
31 #include "hurdstartup.h"
32 #include <mach/host_info.h>
33 #include <stdio-common/_itoa.h>
34 #include <hurd/auth.h>
35 #include <hurd/term.h>
36 #include <stdarg.h>
37 #include <ctype.h>
38 #include <sys/stat.h>
39
40 #include <entry.h>
41 #include <dl-machine.h>
42 #include <dl-procinfo.h>
43
44 extern void __mach_init (void);
45
46 extern int _dl_argc;
47 extern char **_dl_argv;
48 extern char **_environ;
49 extern void ENTRY_POINT (void);
50
51 int __libc_enable_secure;
52 int __libc_multiple_libcs;      /* Defining this here avoids the inclusion
53                                    of init-first.  */
54 /* This variable containts the lowest stack address ever used.  */
55 void *__libc_stack_end;
56 unsigned long int _dl_hwcap_mask = HWCAP_IMPORTANT;
57
58
59 struct hurd_startup_data *_dl_hurd_data;
60
61 /* Defining these variables here avoids the inclusion of hurdsig.c.  */
62 unsigned long int __hurd_sigthread_stack_base;
63 unsigned long int __hurd_sigthread_stack_end;
64 unsigned long int *__hurd_sigthread_variables;
65
66 /* Defining these variables here avoids the inclusion of init-first.c.
67    We need to provide temporary storage for the per-thread variables
68    of the main user thread here, since it is used for storing the
69    `errno' variable.  Note that this information is lost once we
70    relocate the dynamic linker.  */
71 static unsigned long int threadvars[_HURD_THREADVAR_MAX];
72 unsigned long int __hurd_threadvar_stack_offset
73   = (unsigned long int) &threadvars;
74 unsigned long int __hurd_threadvar_stack_mask;
75
76 /* XXX loser kludge for vm_map kernel bug */
77 static vm_address_t fmha;
78 static vm_size_t fmhs;
79 static void unfmh(void){
80 __vm_deallocate(__mach_task_self(),fmha,fmhs);}
81 static void fmh(void) {
82     error_t err;int x;mach_port_t p;
83     vm_address_t a=0x08000000U,max=VM_MAX_ADDRESS;
84     while (!(err=__vm_region(__mach_task_self(),&a,&fmhs,&x,&x,&x,&x,&p,&x))){
85       __mach_port_deallocate(__mach_task_self(),p);
86       if (a+fmhs>=0x80000000U){
87         max=a; break;}
88       fmha=a+=fmhs;}
89     if (err) assert(err==KERN_NO_SPACE);
90     if (!fmha)fmhs=0;else{
91     fmhs=max-fmha;
92     err = __vm_map (__mach_task_self (),
93                     &fmha, fmhs, 0, 0, MACH_PORT_NULL, 0, 1,
94                     VM_PROT_NONE, VM_PROT_NONE, VM_INHERIT_COPY);
95     assert_perror(err);}
96   }
97 /* XXX loser kludge for vm_map kernel bug */
98
99
100
101 Elf32_Addr
102 _dl_sysdep_start (void **start_argptr,
103                   void (*dl_main) (const Elf32_Phdr *phdr, Elf32_Word phent,
104                                    Elf32_Addr *user_entry))
105 {
106   void go (int *argdata)
107     {
108       extern unsigned int _dl_skip_args; /* rtld.c */
109       char **p;
110
111       /* Cache the information in various global variables.  */
112       _dl_argc = *argdata;
113       _dl_argv = 1 + (char **) argdata;
114       _environ = &_dl_argv[_dl_argc + 1];
115       for (p = _environ; *p++;); /* Skip environ pointers and terminator.  */
116
117       if ((void *) p == _dl_argv[0])
118         {
119           static struct hurd_startup_data nodata;
120           _dl_hurd_data = &nodata;
121           nodata.user_entry = (vm_address_t) &ENTRY_POINT;
122         }
123       else
124         _dl_hurd_data = (void *) p;
125
126       __libc_enable_secure = _dl_hurd_data->flags & EXEC_SECURE;
127
128       if (_dl_hurd_data->flags & EXEC_STACK_ARGS &&
129           _dl_hurd_data->user_entry == 0)
130         _dl_hurd_data->user_entry = (vm_address_t) &ENTRY_POINT;
131
132 unfmh();                        /* XXX */
133
134 #if 0                           /* XXX make this work for real someday... */
135       if (_dl_hurd_data->user_entry == (vm_address_t) &ENTRY_POINT)
136         /* We were invoked as a command, not as the program interpreter.
137            The generic ld.so code supports this: it will parse the args
138            as "ld.so PROGRAM [ARGS...]".  For booting the Hurd, we
139            support an additional special syntax:
140              ld.so [-LIBS...] PROGRAM [ARGS...]
141            Each LIBS word consists of "FILENAME=MEMOBJ";
142            for example "-/lib/libc.so=123" says that the contents of
143            /lib/libc.so are found in a memory object whose port name
144            in our task is 123.  */
145         while (_dl_argc > 2 && _dl_argv[1][0] == '-' && _dl_argv[1][1] != '-')
146           {
147             char *lastslash, *memobjname, *p;
148             struct link_map *l;
149             mach_port_t memobj;
150             error_t err;
151
152             ++_dl_skip_args;
153             --_dl_argc;
154             p = _dl_argv++[1] + 1;
155
156             memobjname = strchr (p, '=');
157             if (! memobjname)
158               _dl_sysdep_fatal ("Bogus library spec: ", p, "\n", NULL);
159             *memobjname++ = '\0';
160             memobj = 0;
161             while (*memobjname != '\0')
162               memobj = (memobj * 10) + (*memobjname++ - '0');
163
164             /* Add a user reference on the memory object port, so we will
165                still have one after _dl_map_object_from_fd calls our
166                `close'.  */
167             err = __mach_port_mod_refs (__mach_task_self (), memobj,
168                                         MACH_PORT_RIGHT_SEND, +1);
169             assert_perror (err);
170
171             lastslash = strrchr (p, '/');
172             l = _dl_map_object_from_fd (lastslash ? lastslash + 1 : p,
173                                         memobj, strdup (p), 0);
174
175             /* Squirrel away the memory object port where it
176                can be retrieved by the program later.  */
177             l->l_info[DT_NULL] = (void *) memobj;
178           }
179 #endif
180
181       /* Call elf/rtld.c's main program.  It will set everything
182          up and leave us to transfer control to USER_ENTRY.  */
183       (*dl_main) ((const Elf32_Phdr *) _dl_hurd_data->phdr,
184                   _dl_hurd_data->phdrsz / sizeof (Elf32_Phdr),
185                   &_dl_hurd_data->user_entry);
186
187       if (_dl_skip_args && _dl_argv[-_dl_skip_args] == (char *) p)
188         {
189           /* We are ignoring the first few arguments, but we have no Hurd
190              startup data.  It is magical convention that ARGV[0] == P in
191              this case.  The startup code in init-first.c will get confused
192              if this is not the case, so we must rearrange things to make
193              it so.  Overwrite the original ARGV[0] at P with
194              ARGV[_dl_skip_args].  */
195           assert ((char *) p < _dl_argv[0]);
196           _dl_argv[0] = strcpy ((char *) p, _dl_argv[0]);
197         }
198
199       {
200         extern void _dl_start_user (void);
201         /* Unwind the stack to ARGDATA and simulate a return from _dl_start
202            to the RTLD_START code which will run the user's entry point.  */
203         RETURN_TO (argdata, &_dl_start_user, _dl_hurd_data->user_entry);
204       }
205     }
206
207   /* Set up so we can do RPCs.  */
208   __mach_init ();
209
210   /* Initialize frequently used global variable.  */
211   _dl_pagesize = __getpagesize ();
212
213 fmh();                          /* XXX */
214
215   /* See hurd/hurdstartup.c; this deals with getting information
216      from the exec server and slicing up the arguments.
217      Then it will call `go', above.  */
218   _hurd_startup (start_argptr, &go);
219
220   LOSE;
221   abort ();
222 }
223
224 void
225 _dl_sysdep_start_cleanup (void)
226 {
227   /* Deallocate the reply port and task port rights acquired by
228      __mach_init.  We are done with them now, and the user will
229      reacquire them for himself when he wants them.  */
230   __mig_dealloc_reply_port (MACH_PORT_NULL);
231   __mach_port_deallocate (__mach_task_self (), __mach_task_self_);
232 }
233 \f
234 /* Minimal open/close/mmap implementation sufficient for initial loading of
235    shared libraries.  These are weak definitions so that when the
236    dynamic linker re-relocates itself to be user-visible (for -ldl),
237    it will get the user's definition (i.e. usually libc's).  */
238
239 /* Open FILE_NAME and return a Hurd I/O for it in *PORT, or
240    return an error.  If STAT is non-zero, stat the file into that stat buffer.  */
241 static error_t
242 open_file (const char *file_name, int mode,
243            mach_port_t *port, struct stat *stat)
244 {
245   enum retry_type doretry;
246   char retryname[1024];         /* XXX string_t LOSES! */
247   file_t startdir, newpt, fileport;
248   int dealloc_dir;
249   int nloops;
250   error_t err;
251
252   assert (!(mode & ~O_READ));
253
254   startdir = _dl_hurd_data->portarray[file_name[0] == '/' ?
255                                       INIT_PORT_CRDIR : INIT_PORT_CWDIR];
256
257   while (file_name[0] == '/')
258     file_name++;
259
260   if (err = __dir_lookup (startdir, (char *)file_name, mode, 0,
261                           &doretry, retryname, &fileport))
262     return err;
263
264   dealloc_dir = 0;
265   nloops = 0;
266
267   while (1)
268     {
269       if (dealloc_dir)
270         __mach_port_deallocate (__mach_task_self (), startdir);
271       if (err)
272         return err;
273
274       switch (doretry)
275         {
276         case FS_RETRY_REAUTH:
277           {
278             mach_port_t ref = __mach_reply_port ();
279             err = __io_reauthenticate (fileport, ref, MACH_MSG_TYPE_MAKE_SEND);
280             if (! err)
281               err = __auth_user_authenticate
282                 (_dl_hurd_data->portarray[INIT_PORT_AUTH],
283                  ref, MACH_MSG_TYPE_MAKE_SEND,
284                  &newpt);
285             __mach_port_destroy (__mach_task_self (), ref);
286           }
287           __mach_port_deallocate (__mach_task_self (), fileport);
288           if (err)
289             return err;
290           fileport = newpt;
291           /* Fall through.  */
292
293         case FS_RETRY_NORMAL:
294 #ifdef SYMLOOP_MAX
295           if (nloops++ >= SYMLOOP_MAX)
296             return ELOOP;
297 #endif
298
299           /* An empty RETRYNAME indicates we have the final port.  */
300           if (retryname[0] == '\0')
301             {
302               dealloc_dir = 1;
303             opened:
304               /* We have the file open.  Now map it.  */
305               if (stat)
306                 err = __io_stat (fileport, stat);
307
308               if (err)
309                 {
310                   if (dealloc_dir)
311                     __mach_port_deallocate (__mach_task_self (), fileport);
312                 }
313               else
314                 {
315                   if (!dealloc_dir)
316                     __mach_port_mod_refs (__mach_task_self (), fileport,
317                                           MACH_PORT_RIGHT_SEND, 1);
318                   *port = fileport;
319                 }
320
321               return err;
322             }
323
324           startdir = fileport;
325           dealloc_dir = 1;
326           file_name = retryname;
327           break;
328
329         case FS_RETRY_MAGICAL:
330           switch (retryname[0])
331             {
332             case '/':
333               startdir = _dl_hurd_data->portarray[INIT_PORT_CRDIR];
334               dealloc_dir = 0;
335               if (fileport != MACH_PORT_NULL)
336                 __mach_port_deallocate (__mach_task_self (), fileport);
337               file_name = &retryname[1];
338               break;
339
340             case 'f':
341               if (retryname[1] == 'd' && retryname[2] == '/' &&
342                   isdigit (retryname[3]))
343                 {
344                   /* We can't use strtol for the decoding here
345                      because it brings in hairy locale bloat.  */
346                   char *p;
347                   int fd = 0;
348                   for (p = &retryname[3]; isdigit (*p); ++p)
349                     fd = (fd * 10) + (*p - '0');
350                   /* Check for excess text after the number.  A slash is
351                      valid; it ends the component.  Anything else does not
352                      name a numeric file descriptor.  */
353                   if (*p != '/' && *p != '\0')
354                     return ENOENT;
355                   if (fd < 0 || fd >= _dl_hurd_data->dtablesize ||
356                       _dl_hurd_data->dtable[fd] == MACH_PORT_NULL)
357                     /* If the name was a proper number, but the file
358                        descriptor does not exist, we return EBADF instead
359                        of ENOENT.  */
360                     return EBADF;
361                   fileport = _dl_hurd_data->dtable[fd];
362                   if (*p == '\0')
363                     {
364                       /* This descriptor is the file port we want.  */
365                       dealloc_dir = 0;
366                       goto opened;
367                     }
368                   else
369                     {
370                       /* Do a normal retry on the remaining components.  */
371                       startdir = fileport;
372                       dealloc_dir = 1;
373                       file_name = p + 1; /* Skip the slash.  */
374                       break;
375                     }
376                 }
377               else
378                 goto bad_magic;
379               break;
380
381             case 'm':
382               if (retryname[1] == 'a' && retryname[2] == 'c' &&
383                   retryname[3] == 'h' && retryname[4] == 't' &&
384                   retryname[5] == 'y' && retryname[6] == 'p' &&
385                   retryname[7] == 'e')
386                 {
387                   error_t err;
388                   struct host_basic_info hostinfo;
389                   mach_msg_type_number_t hostinfocnt = HOST_BASIC_INFO_COUNT;
390                   char *p;
391                   if (err = __host_info (__mach_host_self (), HOST_BASIC_INFO,
392                                          (natural_t *) &hostinfo,
393                                          &hostinfocnt))
394                     return err;
395                   if (hostinfocnt != HOST_BASIC_INFO_COUNT)
396                     return EGRATUITOUS;
397                   p = _itoa (hostinfo.cpu_subtype, &retryname[8], 10, 0);
398                   *--p = '/';
399                   p = _itoa (hostinfo.cpu_type, &retryname[8], 10, 0);
400                   if (p < retryname)
401                     abort ();   /* XXX write this right if this ever happens */
402                   if (p > retryname)
403                     strcpy (retryname, p);
404                   startdir = fileport;
405                   dealloc_dir = 1;
406                 }
407               else
408                 goto bad_magic;
409               break;
410
411             case 't':
412               if (retryname[1] == 't' && retryname[2] == 'y')
413                 switch (retryname[3])
414                   {
415                     error_t opentty (file_t *result)
416                       {
417                         error_t err;
418                         file_t unauth;
419                         err = __termctty_open_terminal
420                           (_dl_hurd_data->portarray[INIT_PORT_CTTYID],
421                            mode, &unauth);
422                         if (! err)
423                           {
424                             mach_port_t ref = __mach_reply_port ();
425                             err = __io_reauthenticate
426                               (unauth, ref, MACH_MSG_TYPE_MAKE_SEND);
427                             if (! err)
428                               err = __auth_user_authenticate
429                                 (_dl_hurd_data->portarray[INIT_PORT_AUTH],
430                                  ref, MACH_MSG_TYPE_MAKE_SEND,
431                                  result);
432                             __mach_port_deallocate (__mach_task_self (),
433                                                     unauth);
434                             __mach_port_destroy (__mach_task_self (), ref);
435                           }
436                         return err;
437                       }
438
439                   case '\0':
440                     if (err = opentty (&fileport))
441                       return err;
442                     dealloc_dir = 1;
443                     goto opened;
444                   case '/':
445                     if (err = opentty (&startdir))
446                       return err;
447                     dealloc_dir = 1;
448                     strcpy (retryname, &retryname[4]);
449                     break;
450                   default:
451                     goto bad_magic;
452                   }
453               else
454                 goto bad_magic;
455               break;
456
457             default:
458             bad_magic:
459               return EGRATUITOUS;
460             }
461           break;
462
463         default:
464           return EGRATUITOUS;
465         }
466
467       err = __dir_lookup (startdir, (char *)file_name, mode, 0,
468                           &doretry, retryname, &fileport);
469     }
470 }
471
472 int weak_function
473 __open (const char *file_name, int mode, ...)
474 {
475   mach_port_t port;
476   error_t err = open_file (file_name, mode, &port, 0);
477   if (err)
478     return __hurd_fail (err);
479   else
480     return (int)port;
481 }
482
483 int weak_function
484 __close (int fd)
485 {
486   if (fd != (int) MACH_PORT_NULL)
487     __mach_port_deallocate (__mach_task_self (), (mach_port_t) fd);
488   return 0;
489 }
490
491 __ssize_t weak_function
492 __libc_read (int fd, void *buf, size_t nbytes)
493 {
494   error_t err;
495   char *data;
496   mach_msg_type_number_t nread;
497
498   data = buf;
499   err = __io_read ((mach_port_t) fd, &data, &nread, -1, nbytes);
500   if (err)
501     return __hurd_fail (err);
502
503   if (data != buf)
504     {
505       memcpy (buf, data, nread);
506       __vm_deallocate (__mach_task_self (), (vm_address_t) data, nread);
507     }
508
509   return nread;
510 }
511
512 __ssize_t weak_function
513 __libc_write (int fd, const void *buf, size_t nbytes)
514 {
515   error_t err;
516   mach_msg_type_number_t nwrote;
517
518   assert (fd < _hurd_init_dtablesize);
519
520   err = __io_write (_hurd_init_dtable[fd], buf, nbytes, -1, &nwrote);
521   if (err)
522     return __hurd_fail (err);
523
524   return nwrote;
525 }
526
527 off_t weak_function
528 __lseek (int fd, off_t offset, int whence)
529 {
530   error_t err;
531
532   err = __io_seek ((mach_port_t) fd, offset, whence, &offset);
533   if (err)
534     return __hurd_fail (err);
535
536   return offset;
537 }
538
539 __ptr_t weak_function
540 __mmap (__ptr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
541 {
542   error_t err;
543   vm_prot_t vmprot;
544   vm_address_t mapaddr;
545   mach_port_t memobj_rd, memobj_wr;
546
547   vmprot = VM_PROT_NONE;
548   if (prot & PROT_READ)
549     vmprot |= VM_PROT_READ;
550   if (prot & PROT_WRITE)
551     vmprot |= VM_PROT_WRITE;
552   if (prot & PROT_EXEC)
553     vmprot |= VM_PROT_EXECUTE;
554
555   if (flags & MAP_ANON)
556     memobj_rd = MACH_PORT_NULL;
557   else
558     {
559       assert (!(flags & MAP_SHARED));
560       err = __io_map ((mach_port_t) fd, &memobj_rd, &memobj_wr);
561       if (err)
562         return (__ptr_t) __hurd_fail (err);
563       __mach_port_deallocate (__mach_task_self (), memobj_wr);
564     }
565
566   mapaddr = (vm_address_t) addr;
567   err = __vm_map (__mach_task_self (),
568                   &mapaddr, (vm_size_t) len, 0 /*ELF_MACHINE_USER_ADDRESS_MASK*/,
569                   !(flags & MAP_FIXED),
570                   memobj_rd,
571                   (vm_offset_t) offset,
572                   flags & (MAP_COPY|MAP_PRIVATE),
573                   vmprot, VM_PROT_ALL,
574                   (flags & MAP_SHARED) ? VM_INHERIT_SHARE : VM_INHERIT_COPY);
575   if (err == KERN_NO_SPACE && (flags & MAP_FIXED))
576     {
577       /* XXX this is not atomic as it is in unix! */
578       /* The region is already allocated; deallocate it first.  */
579       err = __vm_deallocate (__mach_task_self (), mapaddr, len);
580       if (! err)
581         err = __vm_map (__mach_task_self (),
582                         &mapaddr, (vm_size_t) len, 0 /*ELF_MACHINE_USER_ADDRESS_MASK*/,
583                         !(flags & MAP_FIXED),
584                         memobj_rd, (vm_offset_t) offset,
585                         flags & (MAP_COPY|MAP_PRIVATE),
586                         vmprot, VM_PROT_ALL,
587                         (flags & MAP_SHARED)
588                         ? VM_INHERIT_SHARE : VM_INHERIT_COPY);
589     }
590
591   if ((flags & MAP_ANON) == 0)
592     __mach_port_deallocate (__mach_task_self (), memobj_rd);
593
594   return err ? (__ptr_t) __hurd_fail (err) : (__ptr_t) mapaddr;
595 }
596
597 int weak_function
598 __fxstat (int vers, int fd, struct stat *buf)
599 {
600   error_t err;
601
602   assert (vers == _STAT_VER);
603
604   err = __io_stat ((mach_port_t) fd, buf);
605   if (err)
606     return __hurd_fail (err);
607
608   return 0;
609 }
610
611 int weak_function
612 __xstat (int vers, const char *file, struct stat *buf)
613 {
614   error_t err;
615   mach_port_t port;
616
617   assert (vers == _STAT_VER);
618
619   err = open_file (file, 0, &port, buf);
620   if (err)
621     return __hurd_fail (err);
622
623   __mach_port_deallocate (__mach_task_self (), port);
624
625   return 0;
626 }
627
628 pid_t weak_function
629 __getpid ()
630 {
631   pid_t pid, ppid;
632   int orphaned;
633
634   if (__proc_getpids (_dl_hurd_data->portarray[INIT_PORT_PROC],
635                       &pid, &ppid, &orphaned))
636     return -1;
637
638   return pid;
639 }
640
641 /* This is called only in some strange cases trying to guess a value
642    for $ORIGIN for the executable.  The dynamic linker copes with
643    getcwd failing (dl-object.c), and it's too much hassle to include
644    the functionality here.  (We could, it just requires duplicating or
645    reusing getcwd.c's code but using our special lookup function as in
646    `open', above.)  */
647 char *
648 weak_function
649 __getcwd (char *buf, size_t size)
650 {
651   errno = ENOSYS;
652   return NULL;
653 }
654
655 void weak_function
656 _exit (int status)
657 {
658   __proc_mark_exit (_dl_hurd_data->portarray[INIT_PORT_PROC],
659                     W_EXITCODE (status, 0), 0);
660   while (__task_terminate (__mach_task_self ()))
661     __mach_task_self_ = (__mach_task_self) ();
662 }
663
664 /* Try to get a machine dependent instruction which will make the
665    program crash.  This is used in case everything else fails.  */
666 #include <abort-instr.h>
667 #ifndef ABORT_INSTRUCTION
668 /* No such instruction is available.  */
669 # define ABORT_INSTRUCTION
670 #endif
671
672 void weak_function
673 abort (void)
674 {
675   /* Try to abort using the system specific command.  */
676   ABORT_INSTRUCTION;
677
678   /* If the abort instruction failed, exit.  */
679   _exit (127);
680
681   /* If even this fails, make sure we never return.  */
682   while (1)
683     /* Try for ever and ever.  */
684     ABORT_INSTRUCTION;
685 }
686 \f
687 /* This function is called by interruptible RPC stubs.  For initial
688    dynamic linking, just use the normal mach_msg.  Since this defn is
689    weak, the real defn in libc.so will override it if we are linked into
690    the user program (-ldl).  */
691
692 error_t weak_function
693 _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg,
694                          mach_msg_option_t option,
695                          mach_msg_size_t send_size,
696                          mach_msg_size_t rcv_size,
697                          mach_port_t rcv_name,
698                          mach_msg_timeout_t timeout,
699                          mach_port_t notify)
700 {
701   return __mach_msg (msg, option, send_size, rcv_size, rcv_name,
702                      timeout, notify);
703 }
704
705
706 void
707 internal_function
708 _dl_show_auxv (void)
709 {
710   /* There is nothing to print.  Hurd has no auxiliary vector.  */
711 }
712
713
714 /* Return an array of useful/necessary hardware capability names.  */
715 const struct r_strlenpair *
716 internal_function
717 _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
718                       size_t *max_capstrlen)
719 {
720   struct r_strlenpair *result;
721
722   /* Return an empty array.  Hurd has no hardware capabilities.  */
723   result = (struct r_strlenpair *) malloc (sizeof (*result));
724   if (result == NULL)
725     _dl_signal_error (ENOMEM, NULL, "cannot create capability list");
726
727   result[0].str = (char *) result;      /* Does not really matter.  */
728   result[0].len = 0;
729
730   *sz = 1;
731   return result;
732 }
733
734 void weak_function
735 _dl_init_first (int argc, ...)
736 {
737   /* This no-op definition only gets used if libc is not linked in.  */
738 }