Update.
authorUlrich Drepper <drepper@redhat.com>
Wed, 5 May 1999 23:29:18 +0000 (23:29 +0000)
committerUlrich Drepper <drepper@redhat.com>
Wed, 5 May 1999 23:29:18 +0000 (23:29 +0000)
* Versions.def (ld.so): Add GLIBC_2.1.1.
* elf/Makefile (routines): Add dl-origin.
(tests): Add origtest.  Add dependencies for the program.
* elf/Versions (ld.so) [GLIBC_2.1.1]: Add _dl_origin_path,
_dl_platformlen, _dl_dst_count and _dl_dst_substitute.
* elf/dl-deps.c (expand_dst): New macro.  Expand DSTs in filename.
(_dl_map_object_deps): Use expand_dst to expand DSTs in DT_NEEDED,
DT_AUXILIARY, and DT_FILTER filenames.
* elf/dl-load.c (expand_dynamic_string_token): Explode into
two functions and three macros.
(_dl_dst_count, _dl_dst_substitute): New functions.
* elf/dl-dst.h: New file.
* elf/dl-open.c (_dl_open): Take extra parameter with address of
caller.  Pass address in args structure.
(dl_open_worker): Recognize and expand DSTs in filename.
* elf/ldsodefs.h (_dl_open): Adapt prototype.
* elf/dlopen.c (dlopen_doit): Pass caller address to _dl_open.
(__dlopen_check): Pass caller address to dlopen_doit in args.
* elf/dlopendoit.c: Likewise.
* iconv/gconv_dl.c: Adapt call of _dl_open.
* nss/nsswitch.c: Likewise.
* elf/origtest.c: New file.
* sysdeps/generic/dl-origin.h: Moved to...
* sysdeps/generic/dl-origin.c: ...here.
* sysdeps/unix/sysv/linux/dl-origin.h: Moved to...
* sysdeps/unix/sysv/linux/dl-origin.c: ...here.

16 files changed:
ChangeLog
Versions.def
elf/Makefile
elf/Versions
elf/dl-deps.c
elf/dl-dst.h [new file with mode: 0644]
elf/dl-load.c
elf/dl-open.c
elf/dlopen.c
elf/dlopenold.c
elf/ldsodefs.h
elf/origtest.c [new file with mode: 0644]
iconv/gconv_dl.c
nss/nsswitch.c
sysdeps/generic/dl-origin.c [moved from sysdeps/generic/dl-origin.h with 88% similarity]
sysdeps/unix/sysv/linux/dl-origin.c [moved from sysdeps/unix/sysv/linux/dl-origin.h with 90% similarity]

index c82015c..3a5767f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,32 @@
 1999-05-05  Ulrich Drepper  <drepper@cygnus.com>
 
+       * Versions.def (ld.so): Add GLIBC_2.1.1.
+       * elf/Makefile (routines): Add dl-origin.
+       (tests): Add origtest.  Add dependencies for the program.
+       * elf/Versions (ld.so) [GLIBC_2.1.1]: Add _dl_origin_path,
+       _dl_platformlen, _dl_dst_count and _dl_dst_substitute.
+       * elf/dl-deps.c (expand_dst): New macro.  Expand DSTs in filename.
+       (_dl_map_object_deps): Use expand_dst to expand DSTs in DT_NEEDED,
+       DT_AUXILIARY, and DT_FILTER filenames.
+       * elf/dl-load.c (expand_dynamic_string_token): Explode into
+       two functions and three macros.
+       (_dl_dst_count, _dl_dst_substitute): New functions.
+       * elf/dl-dst.h: New file.
+       * elf/dl-open.c (_dl_open): Take extra parameter with address of
+       caller.  Pass address in args structure.
+       (dl_open_worker): Recognize and expand DSTs in filename.
+       * elf/ldsodefs.h (_dl_open): Adapt prototype.
+       * elf/dlopen.c (dlopen_doit): Pass caller address to _dl_open.
+       (__dlopen_check): Pass caller address to dlopen_doit in args.
+       * elf/dlopendoit.c: Likewise.
+       * iconv/gconv_dl.c: Adapt call of _dl_open.
+       * nss/nsswitch.c: Likewise.
+       * elf/origtest.c: New file.
+       * sysdeps/generic/dl-origin.h: Moved to...
+       * sysdeps/generic/dl-origin.c: ...here.
+       * sysdeps/unix/sysv/linux/dl-origin.h: Moved to...
+       * sysdeps/unix/sysv/linux/dl-origin.c: ...here.
+
        * stdio-common/_itoa.c (_itoa): Fix special 32bit platform case
        with specific bases and only few bits set in second word.
 
index 3cfd493..a0ed3b4 100644 (file)
@@ -72,4 +72,5 @@ libdb1 {
 ld.so {
   GLIBC_2.0
   GLIBC_2.1 GLIBC_2.0
+  GLIBC_2.1.1 GLIBC_2.1
 }
index 26a0832..d6c37c2 100644 (file)
@@ -22,7 +22,7 @@ subdir                := elf
 
 headers                = elf.h bits/elfclass.h bits/dlfcn.h link.h dlfcn.h
 routines       = $(dl-routines) dl-open dl-close dl-symbol dl-support \
-                 dl-addr enbl-secure dl-profstub
+                 dl-addr enbl-secure dl-profstub dl-origin
 
 # The core dynamic linking functions are in libc for the static and
 # profiled libraries.
@@ -78,7 +78,7 @@ install-rootsbin += ldconfig
 endif
 
 ifeq (yes,$(build-shared))
-tests = loadtest restest1 preloadtest loadfail multiload
+tests = loadtest restest1 preloadtest loadfail multiload origtest
 endif
 modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
                testobj1_1 failobj
@@ -253,6 +253,9 @@ LDFLAGS-multiload = -rdynamic
 CFLAGS-multiload.c = -DOBJDIR=\"$(elf-objpfx)\"
 
 $(objpfx)multiload.out: $(objpfx)testobj1.so
+
+$(objpfx)origtest: $(libdl)
+$(objpfx)origtest.out: $(objpfx)testobj1.so
 \f
 # muwahaha
 
index 8e6dca8..e26e096 100644 (file)
@@ -37,6 +37,13 @@ ld.so {
     # functions used in other libraries
     _dl_mcount; _dl_unload_cache;
   }
+  GLIBC_2.1.1 {
+    # global variables
+    _dl_origin_path; _dl_platformlen;
+
+    # functions used in other libraries
+    _dl_dst_count; _dl_dst_substitute;
+  }
 }
 
 libdl {
index 7291cde..56f91f6 100644 (file)
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <assert.h>
 #include <dlfcn.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/param.h>
 #include <elf/ldsodefs.h>
 
-#include <assert.h>
+#include <dl-dst.h>
 
 /* Whether an shared object references one or more auxiliary objects
    is signaled by the AUXTAG entry in l_info.  */
@@ -39,6 +41,7 @@
    reset if in _dl_close if the last global object is removed.  */
 size_t _dl_global_scope_alloc;
 
+extern size_t _dl_platformlen;
 
 /* When loading auxiliary objects we must ignore errors.  It's ok if
    an object is missing.  */
@@ -48,7 +51,7 @@ struct openaux_args
     struct link_map *map;
     int trace_mode;
     const char *strtab;
-    const ElfW(Dyn) *d;
+    const char *name;
 
     /* The return value of openaux.  */
     struct link_map *aux;
@@ -59,7 +62,7 @@ openaux (void *a)
 {
   struct openaux_args *args = (struct openaux_args *) a;
 
-  args->aux = _dl_map_object (args->map, args->strtab + args->d->d_un.d_val, 0,
+  args->aux = _dl_map_object (args->map, args->name, 0,
                              (args->map->l_type == lt_executable
                               ? lt_library : args->map->l_type),
                              args->trace_mode);
@@ -84,6 +87,43 @@ struct list
   };
 
 
+/* Macro to expand DST.  It is an macro since we use `alloca'.  */
+#define expand_dst(l, str, fatal) \
+  ({                                                                         \
+    const char *__str = (str);                                               \
+    const char *__result = __str;                                            \
+    size_t __cnt = DL_DST_COUNT(__str, 0);                                   \
+                                                                             \
+    if (__cnt != 0)                                                          \
+      {                                                                              \
+       char *__newp = (char *) alloca (DL_DST_REQUIRED (l, __str,            \
+                                                        strlen (__str),      \
+                                                        __cnt));             \
+                                                                             \
+       __result = DL_DST_SUBSTITUTE (l, __str, __newp, 0);                   \
+                                                                             \
+       if (*__result == '\0')                                                \
+         {                                                                   \
+           /* The replacement for the DST is not known.  We can't            \
+              processed.  */                                                 \
+           if (fatal)                                                        \
+             _dl_signal_error (0, __str,                                     \
+                               "empty dynamics string token substitution");  \
+           else                                                              \
+             {                                                               \
+               /* This is for DT_AUXILIARY.  */                              \
+               if (_dl_debug_libs)                                           \
+                 _dl_debug_message (1, "cannot load auxiliary `", __str,     \
+                                    "' because of empty dynamic string"      \
+                                    " token substitution\n", NULL);          \
+               continue;                                                     \
+             }                                                               \
+         }                                                                   \
+      }                                                                              \
+                                                                             \
+    __result; })
+
+
 unsigned int
 internal_function
 _dl_map_object_deps (struct link_map *map,
@@ -166,14 +206,21 @@ _dl_map_object_deps (struct link_map *map,
            if (__builtin_expect (d->d_tag, DT_NEEDED) == DT_NEEDED)
              {
                /* Map in the needed object.  */
-               struct link_map *dep
-                 = _dl_map_object (l, strtab + d->d_un.d_val, 0,
-                                   l->l_type == lt_executable ? lt_library :
-                                   l->l_type, trace_mode);
+               struct link_map *dep;
                /* Allocate new entry.  */
-               struct list *newp = alloca (sizeof (struct list));
+               struct list *newp;
+               /* Object name.  */
+               const char *name;
+
+               /* Recognize DSTs.  */
+               name = expand_dst (l, strtab + d->d_un.d_val, 0);
+
+               dep = _dl_map_object (l, name, 0,
+                                     l->l_type == lt_executable ? lt_library :
+                                     l->l_type, trace_mode);
 
                /* Add it in any case to the duplicate list.  */
+               newp = alloca (sizeof (struct list));
                newp->map = dep;
                newp->dup = NULL;
                dtail->dup = newp;
@@ -202,17 +249,22 @@ _dl_map_object_deps (struct link_map *map,
              {
                char *errstring;
                struct list *newp;
+               /* Object name.  */
+               const char *name;
+
+               /* Recognize DSTs.  */
+               name = expand_dst (l, strtab + d->d_un.d_val,
+                                  d->d_tag == DT_AUXILIARY);
 
                if (d->d_tag == DT_AUXILIARY)
                  {
                    /* Store the tag in the argument structure.  */
-                   args.d = d;
+                   args.name = name;
 
                    /* Say that we are about to load an auxiliary library.  */
                    if (_dl_debug_libs)
                      _dl_debug_message (1, "load auxiliary object=",
-                                        strtab + d->d_un.d_val,
-                                        " requested by file=",
+                                        name, " requested by file=",
                                         l->l_name[0]
                                         ? l->l_name : _dl_argv[0],
                                         "\n", NULL);
@@ -233,15 +285,14 @@ _dl_map_object_deps (struct link_map *map,
                  {
                    /* Say that we are about to load an auxiliary library.  */
                    if (_dl_debug_libs)
-                     _dl_debug_message (1, "load filtered object=",
-                                        strtab + d->d_un.d_val,
+                     _dl_debug_message (1, "load filtered object=", name,
                                         " requested by file=",
                                         l->l_name[0]
                                         ? l->l_name : _dl_argv[0],
                                         "\n", NULL);
 
                    /* For filter objects the dependency must be available.  */
-                   args.aux = _dl_map_object (l, strtab + d->d_un.d_val, 0,
+                   args.aux = _dl_map_object (l, name, 0,
                                               (l->l_type == lt_executable
                                                ? lt_library : l->l_type),
                                               trace_mode);
diff --git a/elf/dl-dst.h b/elf/dl-dst.h
new file mode 100644 (file)
index 0000000..4b014d6
--- /dev/null
@@ -0,0 +1,72 @@
+/* Handling of dynamic sring tokens.
+   Copyright (C) 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
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* Determine the number of DST elements in the name.  Only if IS_PATH is
+   nonzero paths are recognized (i.e., multiple, ':' separated filenames).  */
+#define DL_DST_COUNT(name, is_path) \
+  ({                                                                         \
+    size_t __cnt = 0;                                                        \
+    const char *__sf = strchr (name, '$');                                   \
+                                                                             \
+    if (__sf != NULL)                                                        \
+      __cnt = _dl_dst_count (__sf, is_path);                                 \
+                                                                             \
+    __cnt; })
+
+/* Prototype for used function.  */
+extern size_t _dl_dst_count (const char *name, int is_path);
+
+
+/* Guess from the number of DSTs the length of the restul string.  */
+#define DL_DST_REQUIRED(l, name, len, cnt) \
+  ({                                                                         \
+    size_t origin_len;                                                       \
+    size_t __len = (len);                                                    \
+                                                                             \
+    /* Now we make a guess how many extra characters on top of the length     \
+       of S we need to represent the result.  We know that we have CNT       \
+       replacements.  Each at most can use                                   \
+         MAX (strlen (ORIGIN), strlen (_dl_platform))                        \
+       minus 7 (which is the length of "$ORIGIN").                           \
+                                                                             \
+       First get the origin string if it is not available yet.  This can      \
+       only happen for the map of the executable.  */                        \
+    if ((l)->l_origin == NULL)                                               \
+      {                                                                              \
+       assert ((l)->l_name[0] == '\0');                                      \
+       (l)->l_origin = _dl_get_origin ();                                    \
+       origin_len = ((l)->l_origin && (l)->l_origin != (char *) -1           \
+                     ? strlen ((l)->l_origin) : 0);                          \
+      }                                                                              \
+    else                                                                     \
+      origin_len = (l)->l_origin == (char *) -1 ? 0 : strlen ((l)->l_origin); \
+                                                                             \
+    __len + cnt * (MAX (origin_len, _dl_platformlen) - 7); })
+
+/* Find origin of the executable.  */
+extern const char *_dl_get_origin (void);
+
+
+/* Perform the DST substitution.  */
+#define DL_DST_SUBSTITUTE(l, name, res, is_path) \
+  _dl_dst_substitute (l, name, res, is_path)
+
+/* Prototype for used function.  */
+extern char *_dl_dst_substitute (struct link_map *l, const char *name,
+                                char *result, int is_path);
index 46f0b67..6e8b977 100644 (file)
@@ -31,8 +31,7 @@
 #include "dynamic-link.h"
 #include <stdio-common/_itoa.h>
 
-#include <dl-origin.h>
-
+#include <dl-dst.h>
 
 /* On some systems, no flag bits are given to specify file mapping.  */
 #ifndef MAP_FILE
@@ -146,129 +145,139 @@ local_strdup (const char *s)
   return (char *) memcpy (new, s, len);
 }
 
-/* Return copy of argument with all recognized dynamic string tokens
-   ($ORIGIN and $PLATFORM for now) replaced.  On some platforms it
-   might not be possible to determine the path from which the object
-   belonging to the map is loaded.  In this case the path element
-   containing $ORIGIN is left out.  */
-static char *
-expand_dynamic_string_token (struct link_map *l, const char *s)
+
+size_t
+_dl_dst_count (const char *name, int is_path)
 {
-  /* We make two runs over the string.  First we determine how large the
-     resulting string is and then we copy it over.  Since this is now
-     frequently executed operation we are looking here not for performance
-     but rather for code size.  */
-  const char *sf;
   size_t cnt = 0;
-  size_t origin_len;
-  size_t total;
-  char *result, *last_elem, *wp;
 
-  sf = strchr (s, '$');
-  while (sf != NULL)
+  do
     {
       size_t len = 1;
 
       /* $ORIGIN is not expanded for SUID/GUID programs.  */
       if ((((!__libc_enable_secure
-            && strncmp (&sf[1], "ORIGIN", 6) == 0 && (len = 7) != 0)
-           || (strncmp (&sf[1], "PLATFORM", 8) == 0 && (len = 9) != 0))
-          && (s[len] == '\0' || s[len] == '/' || s[len] == ':'))
-         || (s[1] == '{'
+            && strncmp (&name[1], "ORIGIN", 6) == 0 && (len = 7) != 0)
+           || (strncmp (&name[1], "PLATFORM", 8) == 0 && (len = 9) != 0))
+          && (name[len] == '\0' || name[len] == '/'
+              || (is_path && name[len] == ':')))
+         || (name[1] == '{'
              && ((!__libc_enable_secure
-                  && strncmp (&sf[2], "ORIGIN}", 7) == 0 && (len = 9) != 0)
-                 || (strncmp (&sf[2], "PLATFORM}", 9) == 0
+                  && strncmp (&name[2], "ORIGIN}", 7) == 0 && (len = 9) != 0)
+                 || (strncmp (&name[2], "PLATFORM}", 9) == 0
                      && (len = 11) != 0))))
        ++cnt;
 
-      sf = strchr (sf + len, '$');
+      name = strchr (name + len, '$');
     }
+  while (name != NULL);
 
-  /* If we do not have to replace anything simply copy the string.  */
-  if (cnt == 0)
-    return local_strdup (s);
-
-  /* Now we make a guess how many extra characters on top of the length
-     of S we need to represent the result.  We know that we have CNT
-     replacements.  Each at most can use
-       MAX (strlen (ORIGIN), strlen (_dl_platform))
-     minus 7 (which is the length of "$ORIGIN").
+  return cnt;
+}
 
-     First get the origin string if it is not available yet.  This can
-     only happen for the map of the executable.  */
-  if (l->l_origin == NULL)
-    {
-      assert (l->l_name[0] == '\0');
-      l->l_origin = get_origin ();
-      origin_len = (l->l_origin && l->l_origin != (char *) -1
-                   ? strlen (l->l_origin) : 0);
-    }
-  else
-    origin_len = l->l_origin == (char *) -1 ? 0 : strlen (l->l_origin);
 
-  total = strlen (s) + cnt * (MAX (origin_len, _dl_platformlen) - 7);
-  result = (char *) malloc (total + 1);
-  if (result == NULL)
-    return NULL;
+char *
+_dl_dst_substitute (struct link_map *l, const char *name, char *result,
+                   int is_path)
+{
+  char *last_elem, *wp;
 
   /* Now fill the result path.  While copying over the string we keep
      track of the start of the last path element.  When we come accross
      a DST we copy over the value or (if the value is not available)
      leave the entire path element out.  */
   last_elem = wp = result;
+
   do
     {
-      if (*s == '$')
+      if (*name == '$')
        {
          const char *repl;
          size_t len;
 
-         if ((((strncmp (&s[1], "ORIGIN", 6) == 0 && (len = 7) != 0)
-               || (strncmp (&s[1], "PLATFORM", 8) == 0 && (len = 9) != 0))
-              && (s[len] == '\0' || s[len] == '/' || s[len] == ':'))
-             || (s[1] == '{'
-                 && ((strncmp (&s[2], "ORIGIN}", 7) == 0 && (len = 9) != 0)
-                     || (strncmp (&s[2], "PLATFORM}", 9) == 0
+         if ((((strncmp (&name[1], "ORIGIN", 6) == 0 && (len = 7) != 0)
+               || (strncmp (&name[1], "PLATFORM", 8) == 0 && (len = 9) != 0))
+              && (name[len] == '\0' || name[len] == '/'
+                  || (is_path && name[len] == ':')))
+             || (name[1] == '{'
+                 && ((strncmp (&name[2], "ORIGIN}", 7) == 0 && (len = 9) != 0)
+                     || (strncmp (&name[2], "PLATFORM}", 9) == 0
                          && (len = 11) != 0))))
            {
-             repl = ((len == 7 || s[2] == 'O')
+             repl = ((len == 7 || name[2] == 'O')
                      ? (__libc_enable_secure ? NULL : l->l_origin)
                      : _dl_platform);
 
              if (repl != NULL && repl != (const char *) -1)
                {
                  wp = __stpcpy (wp, repl);
-                 s += len;
+                 name += len;
                }
              else
                {
                  /* We cannot use this path element, the value of the
                     replacement is unknown.  */
                  wp = last_elem;
-                 s += len;
-                 while (*s != '\0' && *s != ':')
-                   ++s;
+                 name += len;
+                 while (*name != '\0' && (!is_path || *name != ':'))
+                   ++name;
                }
            }
          else
            /* No DST we recognize.  */
-           *wp++ = *s++;
+           *wp++ = *name++;
        }
-      else if (*s == ':')
+      else if (is_path && *name == ':')
        {
-         *wp++ = *s++;
+         *wp++ = *name++;
          last_elem = wp;
        }
       else
-       *wp++ = *s++;
+       *wp++ = *name++;
     }
-  while (*s != '\0');
+  while (*name != '\0');
 
   *wp = '\0';
 
   return result;
 }
 
+
+/* Return copy of argument with all recognized dynamic string tokens
+   ($ORIGIN and $PLATFORM for now) replaced.  On some platforms it
+   might not be possible to determine the path from which the object
+   belonging to the map is loaded.  In this case the path element
+   containing $ORIGIN is left out.  */
+static char *
+expand_dynamic_string_token (struct link_map *l, const char *s)
+{
+  /* We make two runs over the string.  First we determine how large the
+     resulting string is and then we copy it over.  Since this is now
+     frequently executed operation we are looking here not for performance
+     but rather for code size.  */
+  size_t cnt;
+  size_t total;
+  char *result;
+
+  /* Determine the nubmer of DST elements.  */
+  cnt = DL_DST_COUNT (s, 1);
+
+  /* If we do not have to replace anything simply copy the string.  */
+  if (cnt == 0)
+    return local_strdup (s);
+
+  /* Determine the length of the substituted string.  */
+  total = DL_DST_REQUIRED (l, s, strlen (s), cnt);
+
+  /* Allocate the necessary memory.  */
+  result = (char *) malloc (total + 1);
+  if (result == NULL)
+    return NULL;
+
+  return DL_DST_SUBSTITUTE (l, s, result, 1);
+}
+
+
 /* Add `name' to the list of names for a particular shared object.
    `name' is expected to have been allocated with malloc and will
    be freed if the shared object already has this name.
index 2b3352b..9a3c093 100644 (file)
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <assert.h>
 #include <dlfcn.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/mman.h>          /* Check whether MAP_COPY is defined.  */
+#include <sys/param.h>
 #include <bits/libc-lock.h>
 #include <elf/ldsodefs.h>
 
+#include <dl-dst.h>
+
 
 extern ElfW(Addr) _dl_sysdep_start (void **start_argptr,
                                    void (*dl_main) (const ElfW(Phdr) *phdr,
@@ -57,6 +61,7 @@ static void show_scope (struct link_map *new);
    At this time it is not anymore a problem to modify the tables.  */
 __libc_lock_define_initialized_recursive (, _dl_load_lock)
 
+extern size_t _dl_platformlen;
 
 /* We must be carefull not to leave us in an inconsistent state.  Thus we
    catch any error and re-raise it after cleaning up.  */
@@ -65,6 +70,7 @@ struct dl_open_args
 {
   const char *file;
   int mode;
+  const void *caller;
   struct link_map *map;
 };
 
@@ -78,6 +84,50 @@ dl_open_worker (void *a)
   ElfW(Addr) init;
   struct r_debug *r;
   unsigned int global_add;
+  const char *dst;
+
+  /* Maybe we have to expand a DST.  */
+  dst = strchr (file, '$');
+  if (dst != NULL)
+    {
+      const void *caller = args->caller;
+      size_t len = strlen (file);
+      size_t required;
+      struct link_map *call_map;
+      char *new_file;
+
+      /* We have to find out from which object the caller is calling.
+        Find the highest-addressed object that ADDRESS is not below.  */
+      call_map = NULL;
+      for (l = _dl_loaded; l; l = l->l_next)
+       if (l->l_addr != 0 /* Make sure we do not currently set this map up
+                             in this moment.  */
+           && caller >= (const void *) l->l_addr
+           && (call_map == NULL || call_map->l_addr < l->l_addr))
+         call_map = l;
+
+      if (call_map == NULL)
+       /* In this case we assume this is the main application.  */
+       call_map = _dl_loaded;
+
+      /* Determine how much space we need.  We have to allocate the
+        memory locally.  */
+      required = DL_DST_REQUIRED (call_map, file, len, _dl_dst_count (dst, 0));
+
+      /* Get space for the new file name.  */
+      new_file = (char *) alloca (required + 1);
+
+      /* Generate the new file name.  */
+      DL_DST_SUBSTITUTE (call_map, file, new_file, 0);
+
+      /* If the substitution failed don't try to load.  */
+      if (*new_file == '\0')
+       _dl_signal_error (0, "dlopen",
+                         "empty dynamics string token substitution");
+
+      /* Now we have a new file name.  */
+      file = new_file;
+    }
 
   /* Load the named object.  */
   args->map = new = _dl_map_object (NULL, file, 0, lt_loaded, 0);
@@ -157,7 +207,7 @@ dl_open_worker (void *a)
 
 struct link_map *
 internal_function
-_dl_open (const char *file, int mode)
+_dl_open (const char *file, int mode, const void *caller)
 {
   struct dl_open_args args;
   char *errstring;
@@ -172,6 +222,7 @@ _dl_open (const char *file, int mode)
 
   args.file = file;
   args.mode = mode;
+  args.caller = caller;
   args.map = NULL;
   errcode = _dl_catch_error (&errstring, dl_open_worker, &args);
 
index 496fc7d..b72300d 100644 (file)
@@ -1,5 +1,5 @@
 /* Load a shared object at run time.
-   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1995, 1996, 1997, 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,6 +28,8 @@ struct dlopen_args
   int mode;
   /* The return value of dlopen_doit.  */
   struct link_map *new;
+  /* Address of the caller.  */
+  const void *caller;
 };
 
 
@@ -36,7 +38,7 @@ dlopen_doit (void *a)
 {
   struct dlopen_args *args = (struct dlopen_args *) a;
 
-  args->new = _dl_open (args->file ?: "", args->mode);
+  args->new = _dl_open (args->file ?: "", args->mode, args->caller);
 }
 
 
@@ -46,6 +48,7 @@ __dlopen_check (const char *file, int mode)
   struct dlopen_args args;
   args.file = file;
   args.mode = mode;
+  args.caller = __builtin_return_address (0);
 
   return _dlerror_run (dlopen_doit, &args) ? NULL : args.new;
 }
index 7e7b462..661a405 100644 (file)
@@ -32,6 +32,8 @@ struct dlopen_args
   int mode;
   /* The return value of dlopen_doit.  */
   struct link_map *new;
+  /* Address of the caller.  */
+  const void *caller;
 };
 
 
@@ -40,7 +42,7 @@ dlopen_doit (void *a)
 {
   struct dlopen_args *args = (struct dlopen_args *) a;
 
-  args->new = _dl_open (args->file ?: "", args->mode);
+  args->new = _dl_open (args->file ?: "", args->mode, args->caller);
 }
 
 
@@ -49,6 +51,7 @@ __dlopen_nocheck (const char *file, int mode)
 {
   struct dlopen_args args;
   args.file = file;
+  args.caller = __builtin_return_address (0);
 
   if ((mode & RTLD_BINDING_MASK) == 0)
     /* By default assume RTLD_LAZY.  */
index 392ea17..f8db76c 100644 (file)
@@ -270,7 +270,8 @@ extern void _dl_setup_hash (struct link_map *map) internal_function;
 /* Open the shared object NAME, relocate it, and run its initializer if it
    hasn't already been run.  MODE is as for `dlopen' (see <dlfcn.h>).  If
    the object is already opened, returns its existing map.  */
-extern struct link_map *_dl_open (const char *name, int mode)
+extern struct link_map *_dl_open (const char *name, int mode,
+                                 const void *caller)
      internal_function;
 
 /* Close an object previously opened by _dl_open.  */
diff --git a/elf/origtest.c b/elf/origtest.c
new file mode 100644 (file)
index 0000000..11bd0f7
--- /dev/null
@@ -0,0 +1,38 @@
+#include <dlfcn.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+  void *h;
+  int (*fp) (int);
+  int res;
+
+  h = dlopen ("${ORIGIN}/testobj1.so", RTLD_LAZY);
+  if (h == NULL)
+    error (EXIT_FAILURE, 0, "while loading `%s': %s", "testobj1.so",
+          dlerror ());
+
+  fp = dlsym (h, "obj1func1");
+  if (fp == NULL)
+    error (EXIT_FAILURE, 0, "getting `obj1func1' in `%s': %s",
+          "testobj1.so", dlerror ());
+
+  res = fp (10);
+  printf ("fp(10) = %d\n", res);
+
+  if (dlclose (h) != 0)
+    error (EXIT_FAILURE, 0, "while close `%s': %s",
+          "testobj1.so", dlerror ());
+
+  return res != 42;
+}
+
+
+int
+foo (int a)
+{
+  return a + 10;
+}
index 33f0efe..52cf9d3 100644 (file)
@@ -64,7 +64,7 @@ do_open (void *a)
 {
   struct gconv_loaded_object *args = (struct gconv_loaded_object *) a;
   /* Open and relocate the shared object.  */
-  args->handle = _dl_open (args->name, RTLD_LAZY);
+  args->handle = _dl_open (args->name, RTLD_LAZY, NULL);
 }
 
 
index 1a6c16e..241fa2c 100644 (file)
@@ -285,7 +285,7 @@ do_open (void *a)
 {
   struct do_open_args *args = (struct do_open_args *) a;
   /* Open and relocate the shared object.  */
-  args->ni->library->lib_handle = _dl_open (args->shlib_name, RTLD_LAZY);
+  args->ni->library->lib_handle = _dl_open (args->shlib_name, RTLD_LAZY, NULL);
 }
 
 static void
similarity index 88%
rename from sysdeps/generic/dl-origin.h
rename to sysdeps/generic/dl-origin.c
index 495df60..b10fee2 100644 (file)
@@ -1,5 +1,5 @@
 /* Find path of executable.
-   Copyright (C) 1998 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
 
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <elf/ldsodefs.h>
+
+#include <dl-dst.h>
+
 /* Generally it is not possible to implement this.  We have to fall
    back on a solution where the user provides the information.  */
 extern const char *_dl_origin_path;
 
-static inline const char *
-get_origin (void)
+const char *
+_dl_get_origin (void)
 {
   char *result = (char *) -1;
   /* We use the environment variable LD_ORIGIN_PATH.  If it is set make
similarity index 90%
rename from sysdeps/unix/sysv/linux/dl-origin.h
rename to sysdeps/unix/sysv/linux/dl-origin.c
index 5654b42..a69684d 100644 (file)
@@ -1,5 +1,5 @@
 /* Find path of executable.
-   Copyright (C) 1998 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
 
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <elf/ldsodefs.h>
+
+#include <dl-dst.h>
+
 /* On Linux >= 2.1 systems which have the dcache implementation we can get
    the path of the application from the /proc/self/exe symlink.  Try this
    first and fall back on the generic method if necessary.  */
 extern const char *_dl_origin_path;
 
-static inline const char *
-get_origin (void)
+const char *
+_dl_get_origin (void)
 {
   char linkval[PATH_MAX];
   char *result;