Update.
authorUlrich Drepper <drepper@redhat.com>
Sat, 24 Jul 1999 19:45:13 +0000 (19:45 +0000)
committerUlrich Drepper <drepper@redhat.com>
Sat, 24 Jul 1999 19:45:13 +0000 (19:45 +0000)
1999-07-24  Ulrich Drepper  <drepper@cygnus.com>

* elf/dl-fini.c: Handle DT_FINI_ARRAY.
* elf/link.h (struct link_map): Remove l_init_running.  Add l_runcount
and l_initcount.
* elf/dl-init.c: Handle DT_INIT_ARRAY.
* elf/dynamic-link.h: Change parameters.  Now only get link_map
pointer.  Calculate l_initcount.

* elf/link.h (struct link_map): Add l_runpath_dirs.
* elf/dynamic-link.h: If RUNPATH is given, set RPATH to NULL.
* elf/dl-load.c: Pretty print.
(decompose_rpath): Take new parameter with info from where the path
comes.  Pass it the fillin_rpath.
(_dl_init_paths): Initialize l_runpath_dirs.
(_dl_map_object): Don't search using RPATHs if object has RUNPATH.
Search using RUNPATH after LD_LIBRARY_PATH.
* elf/dl-support.c: Adjust comment.
* elf/rtld.c: Adjust help message.

ChangeLog
elf/dl-fini.c
elf/dl-init.c
elf/dl-load.c
elf/dl-support.c
elf/dynamic-link.h
elf/link.h
elf/rtld.c

index e2a0dc6..1a124aa 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+1999-07-24  Ulrich Drepper  <drepper@cygnus.com>
+
+       * elf/dl-fini.c: Handle DT_FINI_ARRAY.
+       * elf/link.h (struct link_map): Remove l_init_running.  Add l_runcount
+       and l_initcount.
+       * elf/dl-init.c: Handle DT_INIT_ARRAY.
+       * elf/dynamic-link.h: Change parameters.  Now only get link_map
+       pointer.  Calculate l_initcount.
+
+       * elf/link.h (struct link_map): Add l_runpath_dirs.
+       * elf/dynamic-link.h: If RUNPATH is given, set RPATH to NULL.
+       * elf/dl-load.c: Pretty print.
+       (decompose_rpath): Take new parameter with info from where the path
+       comes.  Pass it the fillin_rpath.
+       (_dl_init_paths): Initialize l_runpath_dirs.
+       (_dl_map_object): Don't search using RPATHs if object has RUNPATH.
+       Search using RUNPATH after LD_LIBRARY_PATH.
+       * elf/dl-support.c: Adjust comment.
+       * elf/rtld.c: Adjust help message.
+
 1999-07-24  Andreas Jaeger  <aj@arthur.rhein-neckar.de>
 
        * elf/rtld.c (dl_main): Adopt to changed _dl_lookup_symbol
index 4b578f8..3f2d625 100644 (file)
@@ -1,5 +1,5 @@
 /* Call the termination functions of loaded shared objects.
-   Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1995, 1996, 1998, 1999 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -28,18 +28,48 @@ _dl_fini (void)
   for (l = _dl_loaded; l; l = l->l_next)
     if (l->l_init_called)
       {
-       if (l->l_info[DT_FINI] &&
-           !(l->l_name[0] == '\0' && l->l_type == lt_executable))
+       int first = 1;
+
+       /* Make sure nothing happens if we are called twice.  */
+       l->l_init_called = 0;
+
+       /* Don't call the destructors for objects we are not supposed to.  */
+       if (l->l_name[0] == '\0' && l->l_type == lt_executable)
+         continue;
+
+       /* First see whether an array is given.  */
+       if (l->l_info[DT_FINI_ARRAY] != NULL)
+         {
+           ElfW(Addr) *array =
+             (ElfW(Addr) *) (l->l_addr
+                             + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
+           unsigned int sz = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
+                              / sizeof (ElfW(Addr)));
+           unsigned int cnt;
+
+           for (cnt = 0; cnt < sz; ++cnt)
+             {
+               /* When debugging print a message first.  */
+               if (_dl_debug_impcalls && first)
+                 _dl_debug_message (1, "\ncalling fini: ",
+                                    l->l_name[0] ? l->l_name : _dl_argv[0],
+                                    "\n\n", NULL);
+               first = 0;
+
+               (*(void (*) (void)) (l->l_addr + array[cnt])) ();
+             }
+         }
+
+       /* Next try the old-style destructor.  */
+       if (l->l_info[DT_FINI])
          {
            /* When debugging print a message first.  */
-           if (_dl_debug_impcalls)
+           if (_dl_debug_impcalls && first)
              _dl_debug_message (1, "\ncalling fini: ",
                                 l->l_name[0] ? l->l_name : _dl_argv[0],
                                 "\n\n", NULL);
 
            (*(void (*) (void)) (l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) ();
          }
-       /* Make sure nothing happens if we are called twice.  */
-       l->l_init_called = 0;
       }
 }
index 64aa1ce..c4b1e22 100644 (file)
@@ -1,5 +1,5 @@
 /* Return the next shared object initializer function not yet run.
-   Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1995, 1996, 1998, 1999 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -38,39 +38,59 @@ _dl_init_next (struct r_scope_elem *searchlist)
   while (i-- > 0)
     {
       struct link_map *l = searchlist->r_list[i];
+      ElfW(Addr) *array;
 
       if (l->l_init_called)
        /* This object is all done.  */
        continue;
 
-      if (l->l_init_running)
+      /* Check for object which constructors we do not run here.
+        XXX Maybe this should be pre-computed, but where?  */
+      if (l->l_name[0] == '\0' && l->l_type == lt_executable)
        {
-         /* This object's initializer was just running.
-            Now mark it as having run, so this object
-            will be skipped in the future.  */
-         l->l_init_running = 0;
          l->l_init_called = 1;
          continue;
        }
 
-      if (l->l_info[DT_INIT]
-         && (l->l_name[0] != '\0' || l->l_type != lt_executable))
-       {
-         /* Run this object's initializer.  */
-         l->l_init_running = 1;
+      /* Account for running next constructor.  */
+      ++l->l_runcount;
 
-         /* Print a debug message if wanted.  */
-         if (_dl_debug_impcalls)
-           _dl_debug_message (1, "\ncalling init: ",
-                               l->l_name[0] ? l->l_name : _dl_argv[0],
-                               "\n\n", NULL);
+      if (l->l_runcount == 1)
+       {
+         /* Try running the DT_INIT constructor.  */
+         if (l->l_info[DT_INIT])
+           {
+             /* Print a debug message if wanted.  */
+             if (_dl_debug_impcalls)
+               _dl_debug_message (1, "\ncalling init: ",
+                                  l->l_name[0] ? l->l_name : _dl_argv[0],
+                                  "\n\n", NULL);
+
+             return l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr;
+           }
+
+         /* No DT_INIT, so go on with the array.  */
+         ++l->l_runcount;
+       }
 
-         return l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr;
+      if (l->l_runcount > l->l_initcount)
+       {
+         /* That were all of the constructors.  */
+         l->l_runcount = 0;
+         l->l_init_called = 1;
+         continue;
        }
 
-      /* No initializer for this object.
-        Mark it so we will skip it in the future.  */
-      l->l_init_called = 1;
+      /* Print a debug message if wanted.  */
+      if (_dl_debug_impcalls && l->l_info[DT_INIT] == NULL
+         && l->l_runcount == 2)
+       _dl_debug_message (1, "\ncalling init: ",
+                          l->l_name[0] ? l->l_name : _dl_argv[0],
+                          "\n\n", NULL);
+
+      array = (ElfW(Addr) *) l->l_info[DT_INIT_ARRAY]->d_un.d_ptr;
+      return l->l_addr + array[l->l_runcount - 2];
+      /* NOTREACHED */
     }
 
 
index c1194ce..e8b42a9 100644 (file)
@@ -35,7 +35,7 @@
 
 /* On some systems, no flag bits are given to specify file mapping.  */
 #ifndef MAP_FILE
-#define MAP_FILE       0
+# define MAP_FILE      0
 #endif
 
 /* The right way to map in the shared library files is MAP_COPY, which
@@ -46,7 +46,7 @@
    means if the file is overwritten, we may at some point get some pages
    from the new version after starting with pages from the old version.  */
 #ifndef MAP_COPY
-#define MAP_COPY       MAP_PRIVATE
+# define MAP_COPY      MAP_PRIVATE
 #endif
 
 /* Some systems link their relocatable objects for another base address
    This results in a more efficient address space usage.  Defaults to
    zero for almost all systems.  */
 #ifndef MAP_BASE_ADDR
-#define MAP_BASE_ADDR(l)       0
+# define MAP_BASE_ADDR(l)      0
 #endif
 
 
 #include <endian.h>
 #if BYTE_ORDER == BIG_ENDIAN
-#define byteorder ELFDATA2MSB
-#define byteorder_name "big-endian"
+# define byteorder ELFDATA2MSB
+# define byteorder_name "big-endian"
 #elif BYTE_ORDER == LITTLE_ENDIAN
-#define byteorder ELFDATA2LSB
-#define byteorder_name "little-endian"
+# define byteorder ELFDATA2LSB
+# define byteorder_name "little-endian"
 #else
-#error "Unknown BYTE_ORDER " BYTE_ORDER
-#define byteorder ELFDATANONE
+# error "Unknown BYTE_ORDER " BYTE_ORDER
+# define byteorder ELFDATANONE
 #endif
 
 #define STRING(x) __STRING (x)
 
 #ifdef MAP_ANON
 /* The fd is not examined when using MAP_ANON.  */
-#define ANONFD -1
+# define ANONFD -1
 #else
 int _dl_zerofd = -1;
-#define ANONFD _dl_zerofd
+# define ANONFD _dl_zerofd
 #endif
 
 /* Handle situations where we have a preferred location in memory for
@@ -87,10 +87,10 @@ int _dl_zerofd = -1;
 ELF_PREFERRED_ADDRESS_DATA;
 #endif
 #ifndef ELF_PREFERRED_ADDRESS
-#define ELF_PREFERRED_ADDRESS(loader, maplength, mapstartpref) (mapstartpref)
+# define ELF_PREFERRED_ADDRESS(loader, maplength, mapstartpref) (mapstartpref)
 #endif
 #ifndef ELF_FIXED_ADDRESS
-#define ELF_FIXED_ADDRESS(loader, mapstart) ((void) 0)
+# define ELF_FIXED_ADDRESS(loader, mapstart) ((void) 0)
 #endif
 
 size_t _dl_pagesize;
@@ -436,7 +436,7 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
 
 static struct r_search_path_elem **
 internal_function
-decompose_rpath (const char *rpath, struct link_map *l)
+decompose_rpath (const char *rpath, struct link_map *l, const char *what)
 {
   /* Make a copy we can work with.  */
   const char *where = l->l_name;
@@ -445,7 +445,8 @@ decompose_rpath (const char *rpath, struct link_map *l)
   struct r_search_path_elem **result;
   size_t nelems;
 
-  /* First see whether we must forget the RPATH from this object.  */
+  /* First see whether we must forget the RUNPATH and RPATH from this
+     object.  */
   if (_dl_inhibit_rpath != NULL && !__libc_enable_secure)
     {
       const char *found = strstr (_dl_inhibit_rpath, where);
@@ -455,8 +456,8 @@ decompose_rpath (const char *rpath, struct link_map *l)
          if ((found == _dl_inhibit_rpath || found[-1] == ':')
              && (found[len] == '\0' || found[len] == ':'))
            {
-             /* This object is on the list of objects for which the RPATH
-                must not be used.  */
+             /* This object is on the list of objects for which the
+                RUNPATH and RPATH must not be used.  */
              result = (struct r_search_path_elem **)
                malloc (sizeof (*result));
              if (result == NULL)
@@ -473,7 +474,7 @@ decompose_rpath (const char *rpath, struct link_map *l)
      string tokens.  */
   copy = expand_dynamic_string_token (l, rpath);
   if (copy == NULL)
-    _dl_signal_error (ENOMEM, NULL, "cannot create RPATH copy");
+    _dl_signal_error (ENOMEM, NULL, "cannot create RUNPATH/RPATH copy");
 
   /* Count the number of necessary elements in the result array.  */
   nelems = 0;
@@ -488,7 +489,7 @@ decompose_rpath (const char *rpath, struct link_map *l)
   if (result == NULL)
     _dl_signal_error (ENOMEM, NULL, "cannot create cache for search path");
 
-  return fillin_rpath (copy, result, ":", 0, "RPATH", where);
+  return fillin_rpath (copy, result, ":", 0, what, where);
 }
 
 
@@ -570,15 +571,32 @@ _dl_init_paths (const char *llp)
     {
       assert (l->l_type != lt_loaded);
 
-      if (l->l_info[DT_RPATH])
-       /* Allocate room for the search path and fill in information
-          from RPATH.  */
-       l->l_rpath_dirs =
-         decompose_rpath ((const void *) (l->l_info[DT_STRTAB]->d_un.d_ptr
-                                          + l->l_info[DT_RPATH]->d_un.d_val),
-                          l);
+      if (l->l_info[DT_RUNPATH])
+       {
+         /* Allocate room for the search path and fill in information
+            from RUNPATH.  */
+         l->l_runpath_dirs =
+           decompose_rpath ((const void *) (l->l_info[DT_STRTAB]->d_un.d_ptr
+                                            + l->l_info[DT_RUNPATH]->d_un.d_val),
+                            l, "RUNPATH");
+
+         /* The RPATH is ignored.  */
+         l->l_rpath_dirs = NULL;
+       }
       else
-       l->l_rpath_dirs = NULL;
+       {
+         l->l_runpath_dirs = NULL;
+
+         if (l->l_info[DT_RPATH])
+           /* Allocate room for the search path and fill in information
+              from RPATH.  */
+           l->l_rpath_dirs =
+             decompose_rpath ((const void *) (l->l_info[DT_STRTAB]->d_un.d_ptr
+                                              + l->l_info[DT_RPATH]->d_un.d_val),
+                              l, "RPATH");
+         else
+           l->l_rpath_dirs = NULL;
+       }
     }
 #endif /* PIC */
 
@@ -1036,7 +1054,7 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
                         "  phnum:   ", buf3, "\n\n", NULL);
     }
 
-  elf_get_dynamic_info (l->l_ld, l->l_addr, l->l_info);
+  elf_get_dynamic_info (l);
   if (l->l_info[DT_HASH])
     _dl_setup_hash (l);
 
@@ -1292,35 +1310,59 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
 
       fd = -1;
 
-      /* First try the DT_RPATH of the dependent object that caused NAME
-        to be loaded.  Then that object's dependent, and on up.  */
-      for (l = loader; fd == -1 && l; l = l->l_loader)
-       if (l->l_info[DT_RPATH])
-         {
-           /* Make sure the cache information is available.  */
-           if (l->l_rpath_dirs == NULL)
+      /* When the object has the RUNPATH information we don't use any
+         RPATHs.  */
+      if (loader != NULL && loader->l_info[DT_RUNPATH] == NULL)
+       {
+         /* First try the DT_RPATH of the dependent object that caused NAME
+            to be loaded.  Then that object's dependent, and on up.  */
+         for (l = loader; fd == -1 && l; l = l->l_loader)
+           if (l->l_info[DT_RPATH])
              {
-               size_t ptrval = (l->l_info[DT_STRTAB]->d_un.d_ptr
-                                + l->l_info[DT_RPATH]->d_un.d_val);
-               l->l_rpath_dirs =
-                 decompose_rpath ((const char *) ptrval, l);
-             }
+               /* Make sure the cache information is available.  */
+               if (l->l_rpath_dirs == NULL)
+                 {
+                   size_t ptrval = (l->l_info[DT_STRTAB]->d_un.d_ptr
+                                    + l->l_info[DT_RPATH]->d_un.d_val);
+                   l->l_rpath_dirs =
+                     decompose_rpath ((const char *) ptrval, l, "RPATH");
+                 }
 
-           if (l->l_rpath_dirs != NULL)
-             fd = open_path (name, namelen, preloaded, l->l_rpath_dirs,
-                             &realname);
-         }
+               if (l->l_rpath_dirs != NULL)
+                 fd = open_path (name, namelen, preloaded, l->l_rpath_dirs,
+                                 &realname);
+             }
 
-      /* If dynamically linked, try the DT_RPATH of the executable itself.  */
-      l = _dl_loaded;
-      if (fd == -1 && l && l->l_type != lt_loaded && l != loader
-         && l->l_rpath_dirs != NULL)
-       fd = open_path (name, namelen, preloaded, l->l_rpath_dirs, &realname);
+         /* If dynamically linked, try the DT_RPATH of the executable
+             itself.  */
+         l = _dl_loaded;
+         if (fd == -1 && l && l->l_type != lt_loaded && l != loader
+             && l->l_rpath_dirs != NULL)
+           fd = open_path (name, namelen, preloaded, l->l_rpath_dirs,
+                           &realname);
+       }
 
       /* Try the LD_LIBRARY_PATH environment variable.  */
       if (fd == -1 && env_path_list != NULL)
        fd = open_path (name, namelen, preloaded, env_path_list, &realname);
 
+      /* Look at the RUNPATH informaiton for this binary.  */
+      if (loader != NULL && loader->l_info[DT_RUNPATH])
+       {
+         /* Make sure the cache information is available.  */
+          if (loader->l_runpath_dirs == NULL)
+             {
+               size_t ptrval = (loader->l_info[DT_STRTAB]->d_un.d_ptr
+                                + loader->l_info[DT_RUNPATH]->d_un.d_val);
+               loader->l_runpath_dirs =
+                 decompose_rpath ((const char *) ptrval, loader, "RUNPATH");
+             }
+
+          if (loader->l_runpath_dirs != NULL)
+             fd = open_path (name, namelen, preloaded, loader->l_runpath_dirs,
+                             &realname);
+       }
+
       if (fd == -1)
        {
          /* Check the list of libraries in the file /etc/ld.so.cache,
index b3ff0c6..edf5874 100644 (file)
@@ -51,7 +51,8 @@ struct r_search_path *_dl_search_paths;
 /* We never do profiling.  */
 const char *_dl_profile;
 
-/* Names of shared object for which the RPATHs should be ignored.  */
+/* Names of shared object for which the RUNPATHs and RPATHs should be
+   ignored.  */
 const char *_dl_inhibit_rpath;
 
 /* The map for the object we will profile.  */
index 59a6001..bdd297e 100644 (file)
@@ -34,13 +34,18 @@ extern int _dl_verbose __attribute__ ((unused));
 /* Read the dynamic section at DYN and fill in INFO with indices DT_*.  */
 
 static inline void __attribute__ ((unused))
-elf_get_dynamic_info (ElfW(Dyn) *dyn, ElfW(Addr) l_addr,
-                     ElfW(Dyn) *info[DT_NUM + DT_PROCNUM + DT_VERSIONTAGNUM
-                                    + DT_EXTRANUM])
+elf_get_dynamic_info (struct link_map *l)
 {
+  ElfW(Dyn) *dyn = l->l_ld;
+  ElfW(Addr) l_addr;
+  ElfW(Dyn) **info;
+
   if (! dyn)
     return;
 
+  l_addr = l->l_addr;
+  info = l->l_info;
+
   while (dyn->d_tag != DT_NULL)
     {
       if (dyn->d_tag < DT_NUM)
@@ -106,6 +111,16 @@ elf_get_dynamic_info (ElfW(Dyn) *dyn, ElfW(Addr) l_addr,
       if (flags & DF_BIND_NOW)
        info[DT_BIND_NOW] = info[DT_FLAGS];
     }
+  /* Determine how many constructors there are.  */
+  if (info[DT_INIT_ARRAY] != NULL)
+    info[DT_INIT_ARRAY]->d_un.d_ptr += l_addr;
+  l->l_initcount = 1 + (info[DT_INIT_ARRAY]
+                       ? (info[DT_INIT_ARRAYSZ]->d_un.d_val
+                          / sizeof (ElfW(Addr)))
+                       : 0);
+  if (info[DT_RUNPATH] != NULL)
+    /* If both RUNPATH and RPATH are given, the latter is ignored.  */
+    info[DT_RPATH] = NULL;
 }
 
 #ifdef RESOLVE
index 5e9d7a8..cda739d 100644 (file)
@@ -163,7 +163,6 @@ struct link_map
       } l_type:2;
     unsigned int l_relocated:1;        /* Nonzero if object's relocations done.  */
     unsigned int l_init_called:1; /* Nonzero if DT_INIT function called.  */
-    unsigned int l_init_running:1; /* Nonzero while DT_INIT function runs.  */
     unsigned int l_global:1;   /* Nonzero if object in _dl_global_scope.  */
     unsigned int l_reserved:2; /* Reserved for internal use.  */
 
@@ -202,6 +201,16 @@ struct link_map
 
     /* Nonzero if the data structure pointed to by `l_phdr' is allocated.  */
     int l_phdr_allocated;
+
+    /* Counter for running constructors and destructors.  */
+    unsigned int l_runcount;
+
+    /* Number of constructors.  We compute this during loading to avoid
+       duplication of this during the possibly many calls to _dl_init_next.  */
+    unsigned int l_initcount;
+
+    /* Collected information about own RUNPATH directories.  */
+    struct r_search_path_elem **l_runpath_dirs;
   };
 
 #endif /* link.h */
index 808cc9d..6029380 100644 (file)
@@ -448,7 +448,8 @@ of this helper program; chances are you did not intend to run this program.\n\
                         object we get handle\n\
   --library-path PATH   use given PATH instead of content of the environment\n\
                         variable LD_LIBRARY_PATH\n\
-  --inhibit-rpath LIST  ignore RPATH information in object names in LIST\n",
+  --inhibit-rpath LIST  ignore RUNPATH and RPATH information in object names\n\
+                        in LIST\n",
                          NULL);
 
       ++_dl_skip_args;