Back to index

glibc  2.9
dl-sysdep.c
Go to the documentation of this file.
00001 /* Operating system support for run-time dynamic linker.  Hurd version.
00002    Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004
00003        Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <hurd.h>
00022 #include <link.h>
00023 #include <unistd.h>
00024 #include <fcntl.h>
00025 #include <stdlib.h>
00026 #include <sys/mman.h>
00027 #include <ldsodefs.h>
00028 #include <sys/wait.h>
00029 #include <assert.h>
00030 #include <sysdep.h>
00031 #include <mach/mig_support.h>
00032 #include "hurdstartup.h"
00033 #include <hurd/lookup.h>
00034 #include <hurd/auth.h>
00035 #include <hurd/term.h>
00036 #include <stdarg.h>
00037 #include <ctype.h>
00038 #include <sys/stat.h>
00039 #include <sys/uio.h>
00040 
00041 #include <entry.h>
00042 #include <dl-machine.h>
00043 #include <dl-procinfo.h>
00044 
00045 extern void __mach_init (void);
00046 
00047 extern int _dl_argc;
00048 extern char **_dl_argv;
00049 extern char **_environ;
00050 
00051 int __libc_enable_secure = 0;
00052 INTVARDEF(__libc_enable_secure)
00053 int __libc_multiple_libcs = 0;     /* Defining this here avoids the inclusion
00054                                of init-first.  */
00055 /* This variable containts the lowest stack address ever used.  */
00056 void *__libc_stack_end;
00057 
00058 #if HP_TIMING_AVAIL
00059 hp_timing_t _dl_cpuclock_offset;
00060 #endif
00061 
00062 
00063 struct hurd_startup_data *_dl_hurd_data;
00064 
00065 /* This is used only within ld.so, via dl-minimal.c's __errno_location.  */
00066 #undef errno
00067 int errno attribute_hidden;
00068 
00069 /* Defining these variables here avoids the inclusion of hurdsig.c.  */
00070 unsigned long int __hurd_sigthread_stack_base;
00071 unsigned long int __hurd_sigthread_stack_end;
00072 unsigned long int *__hurd_sigthread_variables;
00073 
00074 /* Defining these variables here avoids the inclusion of init-first.c.
00075    We need to provide temporary storage for the per-thread variables
00076    of the main user thread here, since it is used for storing the
00077    `errno' variable.  Note that this information is lost once we
00078    relocate the dynamic linker.  */
00079 static unsigned long int threadvars[_HURD_THREADVAR_MAX];
00080 unsigned long int __hurd_threadvar_stack_offset
00081   = (unsigned long int) &threadvars;
00082 unsigned long int __hurd_threadvar_stack_mask;
00083 
00084 #define FMH defined(__i386__)
00085 #if ! FMH
00086 # define fmh()              ((void)0)
00087 # define unfmh()     ((void)0)
00088 #else
00089 /* XXX loser kludge for vm_map kernel bug */
00090 #undef ELF_MACHINE_USER_ADDRESS_MASK
00091 #define ELF_MACHINE_USER_ADDRESS_MASK     0
00092 static vm_address_t fmha;
00093 static vm_size_t fmhs;
00094 static void unfmh(void){
00095 __vm_deallocate(__mach_task_self(),fmha,fmhs);}
00096 static void fmh(void) {
00097     error_t err;int x;mach_port_t p;
00098     vm_address_t a=0x08000000U,max=VM_MAX_ADDRESS;
00099     while (!(err=__vm_region(__mach_task_self(),&a,&fmhs,&x,&x,&x,&x,&p,&x))){
00100       __mach_port_deallocate(__mach_task_self(),p);
00101       if (a+fmhs>=0x80000000U){
00102        max=a; break;}
00103       fmha=a+=fmhs;}
00104     if (err) assert(err==KERN_NO_SPACE);
00105     if (!fmha)fmhs=0;else{
00106     fmhs=max-fmha;
00107     err = __vm_map (__mach_task_self (),
00108                   &fmha, fmhs, 0, 0, MACH_PORT_NULL, 0, 1,
00109                   VM_PROT_NONE, VM_PROT_NONE, VM_INHERIT_COPY);
00110     assert_perror(err);}
00111   }
00112 /* XXX loser kludge for vm_map kernel bug */
00113 #endif
00114 
00115 
00116 ElfW(Addr)
00117 _dl_sysdep_start (void **start_argptr,
00118                 void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phent,
00119                                ElfW(Addr) *user_entry))
00120 {
00121   void go (intptr_t *argdata)
00122     {
00123       extern unsigned int _dl_skip_args; /* rtld.c */
00124       char **p;
00125 
00126       /* Cache the information in various global variables.  */
00127       _dl_argc = *argdata;
00128       _dl_argv = 1 + (char **) argdata;
00129       _environ = &_dl_argv[_dl_argc + 1];
00130       for (p = _environ; *p++;); /* Skip environ pointers and terminator.  */
00131 
00132       if ((void *) p == _dl_argv[0])
00133        {
00134          static struct hurd_startup_data nodata;
00135          _dl_hurd_data = &nodata;
00136          nodata.user_entry = (vm_address_t) ENTRY_POINT;
00137        }
00138       else
00139        _dl_hurd_data = (void *) p;
00140 
00141       INTUSE(__libc_enable_secure) = _dl_hurd_data->flags & EXEC_SECURE;
00142 
00143       if (_dl_hurd_data->flags & EXEC_STACK_ARGS &&
00144          _dl_hurd_data->user_entry == 0)
00145        _dl_hurd_data->user_entry = (vm_address_t) ENTRY_POINT;
00146 
00147 unfmh();                    /* XXX */
00148 
00149 #if 0                       /* XXX make this work for real someday... */
00150       if (_dl_hurd_data->user_entry == (vm_address_t) ENTRY_POINT)
00151        /* We were invoked as a command, not as the program interpreter.
00152           The generic ld.so code supports this: it will parse the args
00153           as "ld.so PROGRAM [ARGS...]".  For booting the Hurd, we
00154           support an additional special syntax:
00155             ld.so [-LIBS...] PROGRAM [ARGS...]
00156           Each LIBS word consists of "FILENAME=MEMOBJ";
00157           for example "-/lib/libc.so=123" says that the contents of
00158           /lib/libc.so are found in a memory object whose port name
00159           in our task is 123.  */
00160        while (_dl_argc > 2 && _dl_argv[1][0] == '-' && _dl_argv[1][1] != '-')
00161          {
00162            char *lastslash, *memobjname, *p;
00163            struct link_map *l;
00164            mach_port_t memobj;
00165            error_t err;
00166 
00167            ++_dl_skip_args;
00168            --_dl_argc;
00169            p = _dl_argv++[1] + 1;
00170 
00171            memobjname = strchr (p, '=');
00172            if (! memobjname)
00173              _dl_sysdep_fatal ("Bogus library spec: ", p, "\n", NULL);
00174            *memobjname++ = '\0';
00175            memobj = 0;
00176            while (*memobjname != '\0')
00177              memobj = (memobj * 10) + (*memobjname++ - '0');
00178 
00179            /* Add a user reference on the memory object port, so we will
00180               still have one after _dl_map_object_from_fd calls our
00181               `close'.  */
00182            err = __mach_port_mod_refs (__mach_task_self (), memobj,
00183                                    MACH_PORT_RIGHT_SEND, +1);
00184            assert_perror (err);
00185 
00186            lastslash = strrchr (p, '/');
00187            l = _dl_map_object_from_fd (lastslash ? lastslash + 1 : p,
00188                                    memobj, strdup (p), 0);
00189 
00190            /* Squirrel away the memory object port where it
00191               can be retrieved by the program later.  */
00192            l->l_info[DT_NULL] = (void *) memobj;
00193          }
00194 #endif
00195 
00196       /* Call elf/rtld.c's main program.  It will set everything
00197         up and leave us to transfer control to USER_ENTRY.  */
00198       (*dl_main) ((const ElfW(Phdr) *) _dl_hurd_data->phdr,
00199                 _dl_hurd_data->phdrsz / sizeof (ElfW(Phdr)),
00200                 &_dl_hurd_data->user_entry);
00201 
00202       /* The call above might screw a few things up.
00203 
00204         First of all, if _dl_skip_args is nonzero, we are ignoring
00205         the first few arguments.  However, if we have no Hurd startup
00206         data, it is the magical convention that ARGV[0] == P.  The
00207         startup code in init-first.c will get confused if this is not
00208         the case, so we must rearrange things to make it so.  We'll
00209         overwrite the origional ARGV[0] at P with ARGV[_dl_skip_args].
00210 
00211         Secondly, if we need to be secure, it removes some dangerous
00212         environment variables.  If we have no Hurd startup date this
00213         changes P (since that's the location after the terminating
00214         NULL in the list of environment variables).  We do the same
00215         thing as in the first case but make sure we recalculate P.
00216         If we do have Hurd startup data, we have to move the data
00217         such that it starts just after the terminating NULL in the
00218         environment list.
00219 
00220         We use memmove, since the locations might overlap.  */
00221       if (INTUSE(__libc_enable_secure) || _dl_skip_args)
00222        {
00223          char **newp;
00224 
00225          for (newp = _environ; *newp++;);
00226 
00227          if (_dl_argv[-_dl_skip_args] == (char *) p)
00228            {
00229              if ((char *) newp != _dl_argv[0])
00230               {
00231                 assert ((char *) newp < _dl_argv[0]);
00232                 _dl_argv[0] = memmove ((char *) newp, _dl_argv[0],
00233                                     strlen (_dl_argv[0]) + 1);
00234               }
00235            }
00236          else
00237            {
00238              if ((void *) newp != _dl_hurd_data)
00239               memmove (newp, _dl_hurd_data, sizeof (*_dl_hurd_data));
00240            }
00241        }
00242 
00243       {
00244        extern void _dl_start_user (void);
00245        /* Unwind the stack to ARGDATA and simulate a return from _dl_start
00246           to the RTLD_START code which will run the user's entry point.  */
00247        RETURN_TO (argdata, &_dl_start_user, _dl_hurd_data->user_entry);
00248       }
00249     }
00250 
00251   /* Set up so we can do RPCs.  */
00252   __mach_init ();
00253 
00254   /* Initialize frequently used global variable.  */
00255   GLRO(dl_pagesize) = __getpagesize ();
00256 
00257 #if HP_TIMING_AVAIL
00258   HP_TIMING_NOW (_dl_cpuclock_offset);
00259 #endif
00260 
00261 fmh();                      /* XXX */
00262 
00263   /* See hurd/hurdstartup.c; this deals with getting information
00264      from the exec server and slicing up the arguments.
00265      Then it will call `go', above.  */
00266   _hurd_startup (start_argptr, &go);
00267 
00268   LOSE;
00269   abort ();
00270 }
00271 
00272 void
00273 internal_function
00274 _dl_sysdep_start_cleanup (void)
00275 {
00276   /* Deallocate the reply port and task port rights acquired by
00277      __mach_init.  We are done with them now, and the user will
00278      reacquire them for himself when he wants them.  */
00279   __mig_dealloc_reply_port (MACH_PORT_NULL);
00280   __mach_port_deallocate (__mach_task_self (), __mach_task_self_);
00281 }
00282 
00283 /* Minimal open/close/mmap implementation sufficient for initial loading of
00284    shared libraries.  These are weak definitions so that when the
00285    dynamic linker re-relocates itself to be user-visible (for -ldl),
00286    it will get the user's definition (i.e. usually libc's).  */
00287 
00288 /* Open FILE_NAME and return a Hurd I/O for it in *PORT, or return an
00289    error.  If STAT is non-zero, stat the file into that stat buffer.  */
00290 static error_t
00291 open_file (const char *file_name, int flags,
00292           mach_port_t *port, struct stat64 *stat)
00293 {
00294   enum retry_type doretry;
00295   char retryname[1024];            /* XXX string_t LOSES! */
00296   file_t startdir;
00297   error_t err;
00298 
00299   error_t use_init_port (int which, error_t (*operate) (file_t))
00300     {
00301       return (which < _dl_hurd_data->portarraysize
00302              ? ((*operate) (_dl_hurd_data->portarray[which]))
00303              : EGRATUITOUS);
00304     }
00305   file_t get_dtable_port (int fd)
00306     {
00307       if ((unsigned int) fd < _dl_hurd_data->dtablesize
00308          && _dl_hurd_data->dtable[fd] != MACH_PORT_NULL)
00309        {
00310          __mach_port_mod_refs (__mach_task_self (), _dl_hurd_data->dtable[fd],
00311                             MACH_PORT_RIGHT_SEND, +1);
00312          return _dl_hurd_data->dtable[fd];
00313        }
00314       errno = EBADF;
00315       return MACH_PORT_NULL;
00316     }
00317 
00318   assert (!(flags & ~O_READ));
00319 
00320   startdir = _dl_hurd_data->portarray[file_name[0] == '/' ?
00321                                   INIT_PORT_CRDIR : INIT_PORT_CWDIR];
00322 
00323   while (file_name[0] == '/')
00324     file_name++;
00325 
00326   err = __dir_lookup (startdir, (char *)file_name, O_RDONLY, 0,
00327                     &doretry, retryname, port);
00328 
00329   if (!err)
00330     err = __hurd_file_name_lookup_retry (use_init_port, get_dtable_port,
00331                                     __dir_lookup, doretry, retryname,
00332                                     O_RDONLY, 0, port);
00333   if (!err && stat)
00334     {
00335       err = __io_stat (*port, stat);
00336       if (err)
00337        __mach_port_deallocate (__mach_task_self (), *port);
00338     }
00339 
00340   return err;
00341 }
00342 
00343 int weak_function
00344 __open (const char *file_name, int mode, ...)
00345 {
00346   mach_port_t port;
00347   error_t err = open_file (file_name, mode, &port, 0);
00348   if (err)
00349     return __hurd_fail (err);
00350   else
00351     return (int)port;
00352 }
00353 
00354 int weak_function
00355 __close (int fd)
00356 {
00357   if (fd != (int) MACH_PORT_NULL)
00358     __mach_port_deallocate (__mach_task_self (), (mach_port_t) fd);
00359   return 0;
00360 }
00361 
00362 __ssize_t weak_function
00363 __libc_read (int fd, void *buf, size_t nbytes)
00364 {
00365   error_t err;
00366   char *data;
00367   mach_msg_type_number_t nread;
00368 
00369   data = buf;
00370   nread = nbytes;
00371   err = __io_read ((mach_port_t) fd, &data, &nread, -1, nbytes);
00372   if (err)
00373     return __hurd_fail (err);
00374 
00375   if (data != buf)
00376     {
00377       memcpy (buf, data, nread);
00378       __vm_deallocate (__mach_task_self (), (vm_address_t) data, nread);
00379     }
00380 
00381   return nread;
00382 }
00383 libc_hidden_weak (__libc_read)
00384 
00385 __ssize_t weak_function
00386 __libc_write (int fd, const void *buf, size_t nbytes)
00387 {
00388   error_t err;
00389   mach_msg_type_number_t nwrote;
00390 
00391   assert (fd < _hurd_init_dtablesize);
00392 
00393   err = __io_write (_hurd_init_dtable[fd], buf, nbytes, -1, &nwrote);
00394   if (err)
00395     return __hurd_fail (err);
00396 
00397   return nwrote;
00398 }
00399 libc_hidden_weak (__libc_write)
00400 
00401 /* This is only used for printing messages (see dl-misc.c).  */
00402 __ssize_t weak_function
00403 __writev (int fd, const struct iovec *iov, int niov)
00404 {
00405   if (fd >= _hurd_init_dtablesize)
00406     {
00407       errno = EBADF;
00408       return -1;
00409     }
00410 
00411   int i;
00412   size_t total = 0;
00413   for (i = 0; i < niov; ++i)
00414     total += iov[i].iov_len;
00415 
00416   if (total != 0)
00417     {
00418       char buf[total], *bufp = buf;
00419       error_t err;
00420       mach_msg_type_number_t nwrote;
00421 
00422       for (i = 0; i < niov; ++i)
00423        bufp = (memcpy (bufp, iov[i].iov_base, iov[i].iov_len)
00424               + iov[i].iov_len);
00425 
00426       err = __io_write (_hurd_init_dtable[fd], buf, total, -1, &nwrote);
00427       if (err)
00428        return __hurd_fail (err);
00429 
00430       return nwrote;
00431     }
00432   return 0;
00433 }
00434 
00435 
00436 off64_t weak_function
00437 __libc_lseek64 (int fd, off64_t offset, int whence)
00438 {
00439   error_t err;
00440 
00441   err = __io_seek ((mach_port_t) fd, offset, whence, &offset);
00442   if (err)
00443     return __hurd_fail (err);
00444 
00445   return offset;
00446 }
00447 
00448 __ptr_t weak_function
00449 __mmap (__ptr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
00450 {
00451   error_t err;
00452   vm_prot_t vmprot;
00453   vm_address_t mapaddr;
00454   mach_port_t memobj_rd, memobj_wr;
00455 
00456   vmprot = VM_PROT_NONE;
00457   if (prot & PROT_READ)
00458     vmprot |= VM_PROT_READ;
00459   if (prot & PROT_WRITE)
00460     vmprot |= VM_PROT_WRITE;
00461   if (prot & PROT_EXEC)
00462     vmprot |= VM_PROT_EXECUTE;
00463 
00464   if (flags & MAP_ANON)
00465     memobj_rd = MACH_PORT_NULL;
00466   else
00467     {
00468       assert (!(flags & MAP_SHARED));
00469       err = __io_map ((mach_port_t) fd, &memobj_rd, &memobj_wr);
00470       if (err)
00471        return __hurd_fail (err), MAP_FAILED;
00472       __mach_port_deallocate (__mach_task_self (), memobj_wr);
00473     }
00474 
00475   mapaddr = (vm_address_t) addr;
00476   err = __vm_map (__mach_task_self (),
00477                 &mapaddr, (vm_size_t) len, ELF_MACHINE_USER_ADDRESS_MASK,
00478                 !(flags & MAP_FIXED),
00479                 memobj_rd,
00480                 (vm_offset_t) offset,
00481                 flags & (MAP_COPY|MAP_PRIVATE),
00482                 vmprot, VM_PROT_ALL,
00483                 (flags & MAP_SHARED) ? VM_INHERIT_SHARE : VM_INHERIT_COPY);
00484   if (err == KERN_NO_SPACE && (flags & MAP_FIXED))
00485     {
00486       /* XXX this is not atomic as it is in unix! */
00487       /* The region is already allocated; deallocate it first.  */
00488       err = __vm_deallocate (__mach_task_self (), mapaddr, len);
00489       if (! err)
00490        err = __vm_map (__mach_task_self (),
00491                      &mapaddr, (vm_size_t) len,
00492                      ELF_MACHINE_USER_ADDRESS_MASK,
00493                      !(flags & MAP_FIXED),
00494                      memobj_rd, (vm_offset_t) offset,
00495                      flags & (MAP_COPY|MAP_PRIVATE),
00496                      vmprot, VM_PROT_ALL,
00497                      (flags & MAP_SHARED)
00498                      ? VM_INHERIT_SHARE : VM_INHERIT_COPY);
00499     }
00500 
00501   if ((flags & MAP_ANON) == 0)
00502     __mach_port_deallocate (__mach_task_self (), memobj_rd);
00503 
00504   if (err)
00505     return __hurd_fail (err), MAP_FAILED;
00506   return (__ptr_t) mapaddr;
00507 }
00508 
00509 int weak_function
00510 __fxstat64 (int vers, int fd, struct stat64 *buf)
00511 {
00512   error_t err;
00513 
00514   assert (vers == _STAT_VER);
00515 
00516   err = __io_stat ((mach_port_t) fd, buf);
00517   if (err)
00518     return __hurd_fail (err);
00519 
00520   return 0;
00521 }
00522 libc_hidden_def (__fxstat64)
00523 
00524 int weak_function
00525 __xstat64 (int vers, const char *file, struct stat64 *buf)
00526 {
00527   error_t err;
00528   mach_port_t port;
00529 
00530   assert (vers == _STAT_VER);
00531 
00532   err = open_file (file, 0, &port, buf);
00533   if (err)
00534     return __hurd_fail (err);
00535 
00536   __mach_port_deallocate (__mach_task_self (), port);
00537 
00538   return 0;
00539 }
00540 libc_hidden_def (__xstat64)
00541 
00542 /* This function is called by the dynamic linker (rtld.c) to check
00543    whether debugging malloc is allowed even for SUID binaries.  This
00544    stub will always fail, which means that malloc-debugging is always
00545    disabled for SUID binaries.  */
00546 int weak_function
00547 __access (const char *file, int type)
00548 {
00549   errno = ENOSYS;
00550   return -1;
00551 }
00552 
00553 pid_t weak_function
00554 __getpid ()
00555 {
00556   pid_t pid, ppid;
00557   int orphaned;
00558 
00559   if (__proc_getpids (_dl_hurd_data->portarray[INIT_PORT_PROC],
00560                     &pid, &ppid, &orphaned))
00561     return -1;
00562 
00563   return pid;
00564 }
00565 
00566 /* This is called only in some strange cases trying to guess a value
00567    for $ORIGIN for the executable.  The dynamic linker copes with
00568    getcwd failing (dl-object.c), and it's too much hassle to include
00569    the functionality here.  (We could, it just requires duplicating or
00570    reusing getcwd.c's code but using our special lookup function as in
00571    `open', above.)  */
00572 char *
00573 weak_function
00574 __getcwd (char *buf, size_t size)
00575 {
00576   errno = ENOSYS;
00577   return NULL;
00578 }
00579 
00580 void weak_function attribute_hidden
00581 _exit (int status)
00582 {
00583   __proc_mark_exit (_dl_hurd_data->portarray[INIT_PORT_PROC],
00584                   W_EXITCODE (status, 0), 0);
00585   while (__task_terminate (__mach_task_self ()))
00586     __mach_task_self_ = (__mach_task_self) ();
00587 }
00588 /* We need this alias to satisfy references from libc_pic.a objects
00589    that were affected by the libc_hidden_proto declaration for _exit.  */
00590 strong_alias (_exit, __GI__exit)
00591 
00592 /* Try to get a machine dependent instruction which will make the
00593    program crash.  This is used in case everything else fails.  */
00594 #include <abort-instr.h>
00595 #ifndef ABORT_INSTRUCTION
00596 /* No such instruction is available.  */
00597 # define ABORT_INSTRUCTION
00598 #endif
00599 
00600 void weak_function
00601 abort (void)
00602 {
00603   /* Try to abort using the system specific command.  */
00604   ABORT_INSTRUCTION;
00605 
00606   /* If the abort instruction failed, exit.  */
00607   _exit (127);
00608 
00609   /* If even this fails, make sure we never return.  */
00610   while (1)
00611     /* Try for ever and ever.  */
00612     ABORT_INSTRUCTION;
00613 }
00614 
00615 /* We need this alias to satisfy references from libc_pic.a objects
00616    that were affected by the libc_hidden_proto declaration for abort.  */
00617 strong_alias (abort, __GI_abort)
00618 
00619 /* This function is called by interruptible RPC stubs.  For initial
00620    dynamic linking, just use the normal mach_msg.  Since this defn is
00621    weak, the real defn in libc.so will override it if we are linked into
00622    the user program (-ldl).  */
00623 
00624 error_t weak_function
00625 _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg,
00626                       mach_msg_option_t option,
00627                       mach_msg_size_t send_size,
00628                       mach_msg_size_t rcv_size,
00629                       mach_port_t rcv_name,
00630                       mach_msg_timeout_t timeout,
00631                       mach_port_t notify)
00632 {
00633   return __mach_msg (msg, option, send_size, rcv_size, rcv_name,
00634                    timeout, notify);
00635 }
00636 
00637 
00638 void
00639 internal_function
00640 _dl_show_auxv (void)
00641 {
00642   /* There is nothing to print.  Hurd has no auxiliary vector.  */
00643 }
00644 
00645 
00646 /* Return an array of useful/necessary hardware capability names.  */
00647 const struct r_strlenpair *
00648 internal_function
00649 _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
00650                     size_t *max_capstrlen)
00651 {
00652   struct r_strlenpair *result;
00653 
00654   /* Return an empty array.  Hurd has no hardware capabilities.  */
00655   result = (struct r_strlenpair *) malloc (sizeof (*result));
00656   if (result == NULL)
00657     _dl_signal_error (ENOMEM, NULL, NULL, "cannot create capability list");
00658 
00659   result[0].str = (char *) result; /* Does not really matter.  */
00660   result[0].len = 0;
00661 
00662   *sz = 1;
00663   return result;
00664 }
00665 
00666 void weak_function
00667 _dl_init_first (int argc, ...)
00668 {
00669   /* This no-op definition only gets used if libc is not linked in.  */
00670 }