This is the mail archive of the libc-hacker@sources.redhat.com mailing list for the glibc project.

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Handle dlopen from statically linked apps via hooks


Hi!

This patch makes some dlopen calls from e.g. NSS modules loaded from
statically linked programs work.
The usual restrictions still apply, i.e. one should only run statically
linked programs that use NSS/dlopen/iconv against the glibc they were
compiled/linked against, otherwise there are no guarantees plus even
then one can't assume everything works as with dynamic linking
(e.g. when writing tststatic2 test, I have noticed that doing
printf in the dlopened module in between printf's in statically linked
program will result in the text from module not being printed (there
are 2 different stdout's); I have changed it so that FILE * is passed
around).

2004-10-18  Jakub Jelinek  <jakub@redhat.com>

	* elf/dl-libc.c (__libc_dlsym_private, __libc_register_dl_open_hook):
	New functions.
	(__libc_dlopen_mode): Call __libc_register_dl_open_hook and
	__libc_register_dlfcn_hook.
	* dlfcn/Makefile (routines, elide-routines.os): Set.
	Add rules to build and test tststatic2.
	* dlfcn/tststatic2.c: New test.
	* dlfcn/modstatic2.c: New test module.
	* dlfcn/dladdr.c: Call _dlfcn_hook from libdl.so if not NULL.
	Define __ prefixed routine in libc.a and in libdl.a just call it.
	* dlfcn/dladdr1.c: Likewise.
	* dlfcn/dlclose.c: Likewise.
	* dlfcn/dlerror.c: Likewise.
	* dlfcn/dlinfo.c: Likewise.
	* dlfcn/dlmopen.c: Likewise.
	* dlfcn/dlopen.c: Likewise.
	* dlfcn/dlopenold.c: Likewise.
	* dlfcn/dlsym.c: Likewise.
	* dlfcn/dlvsym.c: Likewise.
	* dlfcn/sdladdr.c: New file.
	* dlfcn/sdladdr1.c: New file.
	* dlfcn/sdlclose.c: New file.
	* dlfcn/sdlerror.c: New file.
	* dlfcn/sdlinfo.c: New file.
	* dlfcn/sdlopen.c: New file.
	* dlfcn/sdlsym.c: New file.
	* dlfcn/sdlvsym.c: New file.
	* dlfcn/Versions (libdl): Export _dlfcn_hook@GLIBC_PRIVATE.
	* include/dlfcn.h (DL_CALLER_DECL, DL_CALLER RETURN_ADDRESS): Define.
	(struct dlfcn_hook): New type.
	(_dlfcn_hook): New extern decl.
	(__dlopen, __dlclose, __dlsym, __dlerror, __dladdr, __dladdr1,
	__dlinfo, __dlmopen, __libc_dlsym_private,
	__libc_register_dl_open_hook, __libc_register_dlfcn_hook): New
	prototypes.
	(__dlvsym): Use DL_CALLER_DECL.
	* include/libc-symbols.h: Define libdl_hidden_proto and friends.

	* malloc/arena.c (_dl_open_hook): Extern decl.
	(ptmalloc_init): Don't call _dl_addr when dlopened from statically
	linked programs but don't use brk for them either.

--- libc/malloc/arena.c.jj	2004-10-15 23:08:34.000000000 +0200
+++ libc/malloc/arena.c	2004-10-18 16:52:30.765485691 +0200
@@ -347,6 +347,9 @@ __failing_morecore (ptrdiff_t d)
 {
   return (void *) MORECORE_FAILURE;
 }
+
+extern struct dl_open_hook *_dl_open_hook;
+libc_hidden_proto (_dl_open_hook);
 # endif
 
 # if defined SHARED && defined USE_TLS && !USE___THREAD
@@ -429,10 +432,14 @@ ptmalloc_init (void)
   main_arena.next = &main_arena;
 
 #if defined _LIBC && defined SHARED
-  /* In case this libc copy is in a non-default namespace, never use brk.  */
+  /* In case this libc copy is in a non-default namespace, never use brk.
+     Likewise if dlopened from statically linked program.  */
   Dl_info di;
   struct link_map *l;
-  if (_dl_addr (ptmalloc_init, &di, &l, NULL) != 0 && l->l_ns != LM_ID_BASE)
+
+  if (_dl_open_hook != NULL
+      || (_dl_addr (ptmalloc_init, &di, &l, NULL) != 0
+	  && l->l_ns != LM_ID_BASE))
     __morecore = __failing_morecore;
 #endif
 
--- libc/dlfcn/sdlopen.c.jj	2004-10-18 21:20:12.848098233 +0200
+++ libc/dlfcn/sdlopen.c	2004-10-18 21:20:12.848098233 +0200
@@ -0,0 +1 @@
+#include "dlopen.c"
--- libc/dlfcn/sdlinfo.c.jj	2004-10-18 21:20:12.847098412 +0200
+++ libc/dlfcn/sdlinfo.c	2004-10-18 21:20:12.848098233 +0200
@@ -0,0 +1 @@
+#include "dlinfo.c"
--- libc/dlfcn/dlopen.c.jj	2004-10-15 23:08:32.000000000 +0200
+++ libc/dlfcn/dlopen.c	2004-10-18 22:09:50.189932973 +0200
@@ -20,6 +20,17 @@
 #include <dlfcn.h>
 #include <stddef.h>
 
+#if !defined SHARED && defined IS_IN_libdl
+
+void *
+dlopen (const char *file, int mode)
+{
+  return __dlopen (file, mode, RETURN_ADDRESS (0));
+}
+static_link_warning (dlopen)
+
+#else
+
 struct dlopen_args
 {
   /* The arguments for dlopen_doit.  */
@@ -33,11 +44,11 @@ struct dlopen_args
 
 
 /* Non-shared code has no support for multiple namespaces.  */
-#ifdef SHARED
-# define NS __LM_ID_CALLER
-#else
-# define NS LM_ID_BASE
-#endif
+# ifdef SHARED
+#  define NS __LM_ID_CALLER
+# else
+#  define NS LM_ID_BASE
+# endif
 
 
 static void
@@ -50,17 +61,34 @@ dlopen_doit (void *a)
 }
 
 
-extern void *__dlopen_check (const char *file, int mode);
 void *
-__dlopen_check (const char *file, int mode)
+__dlopen (const char *file, int mode DL_CALLER_DECL)
 {
+# ifdef SHARED
+  if (__builtin_expect (_dlfcn_hook != NULL, 0))
+    return _dlfcn_hook->dlopen (file, mode, DL_CALLER);
+# endif
+
   struct dlopen_args args;
   args.file = file;
   args.mode = mode;
-  args.caller = RETURN_ADDRESS (0);
+  args.caller = DL_CALLER;
 
+# ifdef SHARED
   return _dlerror_run (dlopen_doit, &args) ? NULL : args.new;
+# else
+  if (_dlerror_run (dlopen_doit, &args))
+    return NULL;
+
+  __libc_register_dl_open_hook ((struct link_map *) args.new);
+  __libc_register_dlfcn_hook ((struct link_map *) args.new);
+
+  return args.new;
+# endif
 }
-#include <shlib-compat.h>
+# ifdef SHARED
+#  include <shlib-compat.h>
+strong_alias (__dlopen, __dlopen_check)
 versioned_symbol (libdl, __dlopen_check, dlopen, GLIBC_2_1);
-static_link_warning (dlopen)
+# endif
+#endif
--- libc/dlfcn/dladdr.c.jj	2003-03-10 10:12:11.000000000 +0100
+++ libc/dlfcn/dladdr.c	2004-10-18 20:57:04.564415633 +0200
@@ -1,5 +1,6 @@
 /* Locate the shared object symbol nearest a given address.
-   Copyright (C) 1996, 1997, 1998, 1999, 2003 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 1998, 1999, 2003, 2004
+   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
@@ -19,8 +20,26 @@
 
 #include <dlfcn.h>
 
+#if !defined SHARED && defined IS_IN_libdl
+
 int
 dladdr (const void *address, Dl_info *info)
 {
+  return __dladdr (address, info);
+}
+
+#else
+
+int
+__dladdr (const void *address, Dl_info *info)
+{
+# ifdef SHARED
+  if (__builtin_expect (_dlfcn_hook != NULL, 0))
+    return _dlfcn_hook->dladdr (address, info);
+# endif
   return _dl_addr (address, info, NULL, NULL);
 }
+# ifdef SHARED
+strong_alias (__dladdr, dladdr)
+# endif
+#endif
--- libc/dlfcn/tststatic2.c.jj	2004-10-18 22:32:17.698823901 +0200
+++ libc/dlfcn/tststatic2.c	2004-10-18 23:57:14.970024860 +0200
@@ -0,0 +1,166 @@
+#include <dlfcn.h>
+#include <link.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gnu/lib-names.h>
+
+int
+main (void)
+{
+  void *handle = dlopen ("modstatic2-nonexistent.so", RTLD_LAZY);
+  if (handle == NULL)
+    printf ("nonexistent: %s\n", dlerror ());
+  else
+    exit (1);
+
+  handle = dlopen ("modstatic2.so", RTLD_LAZY);
+  if (handle == NULL)
+    {
+      printf ("%s\n", dlerror ());
+      exit (1);
+    }
+
+  int (*test) (FILE *, int);
+  test = dlsym (handle, "test");
+  if (test == NULL)
+    {
+      printf ("%s\n", dlerror ());
+      exit (1);
+    }
+
+  Dl_info info;
+  int res = dladdr (test, &info);
+  if (res == 0)
+    {
+      puts ("dladdr returned 0");
+      exit (1);
+    }
+  else
+    {
+      if (strstr (info.dli_fname, "modstatic2.so") == NULL
+	  || strcmp (info.dli_sname, "test") != 0)
+	{
+	  printf ("fname %s sname %s\n", info.dli_fname, info.dli_sname);
+	  exit (1);
+	}
+      if (info.dli_saddr != (void *) test)
+	{
+	  printf ("saddr %p != test %p\n", info.dli_saddr, test);
+	  exit (1);
+	}
+    }
+
+  ElfW(Sym) *sym;
+  void *symp;
+  res = dladdr1 (test, &info, &symp, RTLD_DL_SYMENT);
+  if (res == 0)
+    {
+      puts ("dladdr1 returned 0");
+      exit (1);
+    }
+  else
+    {
+      if (strstr (info.dli_fname, "modstatic2.so") == NULL
+	  || strcmp (info.dli_sname, "test") != 0)
+	{
+	  printf ("fname %s sname %s\n", info.dli_fname, info.dli_sname);
+	  exit (1);
+	}
+      if (info.dli_saddr != (void *) test)
+	{
+	  printf ("saddr %p != test %p\n", info.dli_saddr, test);
+	  exit (1);
+	}
+      sym = symp;
+      if (sym == NULL)
+	{
+	  puts ("sym == NULL\n");
+	  exit (1);
+	}
+      if (ELF32_ST_BIND (sym->st_info) != STB_GLOBAL
+	  || ELF32_ST_VISIBILITY (sym->st_other) != STV_DEFAULT)
+	{
+	  printf ("bind %d visibility %d\n",
+		  (int) ELF32_ST_BIND (sym->st_info),
+		  (int) ELF32_ST_VISIBILITY (sym->st_other));
+	  exit (1);
+	}
+    }
+
+  Lmid_t lmid;
+  res = dlinfo (handle, RTLD_DI_LMID, &lmid);
+  if (res != 0)
+    {
+      printf ("dlinfo returned %d %s\n", res, dlerror ());
+      exit (1);
+    }
+  else if (lmid != LM_ID_BASE)
+    {
+      printf ("lmid %d != %d\n", (int) lmid, (int) LM_ID_BASE);
+      exit (1);
+    }
+
+  res = test (stdout, 2);
+  if (res != 4)
+    {
+      printf ("Got %i, expected 4\n", res);
+      exit (1);
+    }
+
+  void *handle2 = dlopen (LIBDL_SO, RTLD_LAZY);
+  if (handle2 == NULL)
+    {
+      printf ("libdl.so: %s\n", dlerror ());
+      exit (1);
+    }
+
+#ifdef DO_VERSIONING
+  if (dlvsym (handle2, "_dlfcn_hook", "GLIBC_PRIVATE") == NULL)
+    {
+      printf ("dlvsym: %s\n", dlerror ());
+      exit (1);
+    }
+#endif
+
+  void *(*dlsymfn) (void *, const char *);
+  dlsymfn = dlsym (handle2, "dlsym");
+  if (dlsymfn == NULL)
+    {
+      printf ("dlsym \"dlsym\": %s\n", dlerror ());
+      exit (1);
+    }
+  void *test2 = dlsymfn (handle, "test");
+  if (test2 == NULL)
+    {
+      printf ("%s\n", dlerror ());
+      exit (1);
+    }
+  else if (test2 != (void *) test)
+    {
+      printf ("test %p != test2 %p\n", test, test2);
+      exit (1);
+    }
+
+  dlclose (handle2);
+  dlclose (handle);
+
+  handle = dlmopen (LM_ID_BASE, "modstatic2.so", RTLD_LAZY);
+  if (handle == NULL)
+    {
+      printf ("%s\n", dlerror ());
+      exit (1);
+    }
+  dlclose (handle);
+
+  handle = dlmopen (LM_ID_NEWLM, "modstatic2.so", RTLD_LAZY);
+  if (handle == NULL)
+    printf ("LM_ID_NEWLM: %s\n", dlerror ());
+  else
+    {
+      puts ("LM_ID_NEWLM unexpectedly succeeded");
+      exit (1);
+    }
+
+  return 0;
+}
--- libc/dlfcn/dlinfo.c.jj	2004-10-15 23:08:32.000000000 +0200
+++ libc/dlfcn/dlinfo.c	2004-10-18 21:03:38.718828131 +0200
@@ -22,6 +22,16 @@
 #include <ldsodefs.h>
 #include <libintl.h>
 
+#if !defined SHARED && defined IS_IN_libdl
+
+int
+dlinfo (void *handle, int request, void *arg)
+{
+  return __dlinfo (handle, request, arg, RETURN_ADDRESS (0));
+}
+
+#else
+
 struct dlinfo_args
 {
   ElfW(Addr) caller;
@@ -36,7 +46,7 @@ dlinfo_doit (void *argsblock)
   struct dlinfo_args *const args = argsblock;
   struct link_map *l = args->handle;
 
-#if 0
+# if 0
   if (args->handle == RTLD_SELF)
     {
       Lmid_t nsid;
@@ -53,7 +63,7 @@ dlinfo_doit (void *argsblock)
 	GLRO(dl_signal_error) (0, NULL, NULL, N_("\
 RTLD_SELF used in code not dynamically loaded"));
     }
-#endif
+# endif
 
   switch (args->request)
     {
@@ -84,9 +94,19 @@ RTLD_SELF used in code not dynamically l
 }
 
 int
-dlinfo (void *handle, int request, void *arg)
+__dlinfo (void *handle, int request, void *arg DL_CALLER_DECL)
 {
-  struct dlinfo_args args = { (ElfW(Addr)) RETURN_ADDRESS (0),
+# ifdef SHARED
+  if (__builtin_expect (_dlfcn_hook != NULL, 0))
+    return _dlfcn_hook->dlinfo (handle, request, arg,
+				DL_CALLER);
+# endif
+
+  struct dlinfo_args args = { (ElfW(Addr)) DL_CALLER,
 			      handle, request, arg };
   return _dlerror_run (&dlinfo_doit, &args) ? -1 : 0;
 }
+# ifdef SHARED
+strong_alias (__dlinfo, dlinfo)
+# endif
+#endif
--- libc/dlfcn/sdladdr.c.jj	2004-10-18 21:20:12.844098948 +0200
+++ libc/dlfcn/sdladdr.c	2004-10-18 21:20:12.844098948 +0200
@@ -0,0 +1 @@
+#include "dladdr.c"
--- libc/dlfcn/dlerror.c.jj	2004-03-08 12:01:41.000000000 +0100
+++ libc/dlfcn/dlerror.c	2004-10-18 23:48:45.113480259 +0200
@@ -25,6 +25,16 @@
 #include <bits/libc-lock.h>
 #include <ldsodefs.h>
 
+#if !defined SHARED && defined IS_IN_libdl
+
+char *
+dlerror (void)
+{
+  return __dlerror ();
+}
+
+#else
+
 /* Type for storing results of dynamic loading actions.  */
 struct dl_action_result
   {
@@ -46,11 +56,16 @@ static void free_key_mem (void *mem);
 
 
 char *
-dlerror (void)
+__dlerror (void)
 {
   char *buf = NULL;
   struct dl_action_result *result;
 
+# ifdef SHARED
+  if (__builtin_expect (_dlfcn_hook != NULL, 0))
+    return _dlfcn_hook->dlerror ();
+# endif
+
   /* If we have not yet initialized the buffer do it now.  */
   __libc_once (once, init);
 
@@ -99,6 +114,9 @@ dlerror (void)
 
   return buf;
 }
+# ifdef SHARED
+strong_alias (__dlerror, dlerror)
+# endif
 
 int
 internal_function
@@ -185,3 +203,35 @@ free_key_mem (void *mem)
   free (mem);
   __libc_setspecific (key, NULL);
 }
+
+# ifdef SHARED
+
+struct dlfcn_hook *_dlfcn_hook __attribute__((nocommon));
+libdl_hidden_data_def (_dlfcn_hook)
+
+# else
+
+static struct dlfcn_hook _dlfcn_hooks =
+  {
+    .dlopen = __dlopen,
+    .dlclose = __dlclose,
+    .dlsym = __dlsym,
+    .dlvsym = __dlvsym,
+    .dlerror = __dlerror,
+    .dladdr = __dladdr,
+    .dladdr1 = __dladdr1,
+    .dlinfo = __dlinfo,
+    .dlmopen = __dlmopen
+  };
+
+void
+__libc_register_dlfcn_hook (struct link_map *map)
+{
+  struct dlfcn_hook **hook;
+
+  hook = (struct dlfcn_hook **) __libc_dlsym_private (map, "_dlfcn_hook");
+  if (hook != NULL)
+    *hook = &_dlfcn_hooks;
+}
+# endif
+#endif
--- libc/dlfcn/dlvsym.c.jj	2004-02-23 09:46:13.000000000 +0100
+++ libc/dlfcn/dlvsym.c	2004-10-18 21:46:33.954859714 +0200
@@ -22,6 +22,17 @@
 
 #include <ldsodefs.h>
 
+#if !defined SHARED && defined IS_IN_libdl
+
+void *
+weak_function
+dlvsym (void *handle, const char *name, const char *version_str)
+{
+  return __dlvsym (handle, name, version_str, RETURN_ADDRESS (0));
+}
+
+#else
+
 struct dlvsym_args
 {
   /* The arguments to dlvsym_doit.  */
@@ -44,13 +55,18 @@ dlvsym_doit (void *a)
 }
 
 void *
-__dlvsym (void *handle, const char *name, const char *version_str)
+__dlvsym (void *handle, const char *name, const char *version_str
+	  DL_CALLER_DECL)
 {
-  struct dlvsym_args args;
+# ifdef SHARED
+  if (__builtin_expect (_dlfcn_hook != NULL, 0))
+    return _dlfcn_hook->dlvsym (handle, name, version_str, DL_CALLER);
+# endif
 
+  struct dlvsym_args args;
   args.handle = handle;
   args.name = name;
-  args.who = RETURN_ADDRESS (0);
+  args.who = DL_CALLER;
   args.version = version_str;
 
   /* Protect against concurrent loads and unloads.  */
@@ -62,4 +78,7 @@ __dlvsym (void *handle, const char *name
 
   return result;
 }
+# ifdef SHARED
 weak_alias (__dlvsym, dlvsym)
+# endif
+#endif
--- libc/dlfcn/modstatic2.c.jj	2004-10-18 22:42:28.741800567 +0200
+++ libc/dlfcn/modstatic2.c	2004-10-18 23:57:24.869271016 +0200
@@ -0,0 +1,228 @@
+#include <dlfcn.h>
+#include <link.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gnu/lib-names.h>
+
+int test (FILE *out, int a);
+
+int
+test (FILE *out, int a)
+{
+  fputs ("in modstatic2.c (test)\n", out);
+
+  void *handle = dlopen ("modstatic2-nonexistent.so", RTLD_LAZY);
+  if (handle == NULL)
+    fprintf (out, "nonexistent: %s\n", dlerror ());
+  else
+    exit (1);
+
+  handle = dlopen ("modstatic2.so", RTLD_LAZY);
+  if (handle == NULL)
+    {
+      fprintf (out, "%s\n", dlerror ());
+      exit (1);
+    }
+
+  int (*test2) (FILE *, int);
+  test2 = dlsym (handle, "test");
+  if (test2 == NULL)
+    {
+      fprintf (out, "%s\n", dlerror ());
+      exit (1);
+    }
+  if (test2 != test)
+    {
+      fprintf (out, "test %p != test2 %p\n", test, test2);
+      exit (1);
+    }
+
+  Dl_info info;
+  int res = dladdr (test2, &info);
+  if (res == 0)
+    {
+      fputs ("dladdr returned 0\n", out);
+      exit (1);
+    }
+  else
+    {
+      if (strstr (info.dli_fname, "modstatic2.so") == NULL
+	  || strcmp (info.dli_sname, "test") != 0)
+	{
+	  fprintf (out, "fname %s sname %s\n", info.dli_fname, info.dli_sname);
+	  exit (1);
+	}
+      if (info.dli_saddr != (void *) test2)
+	{
+	  fprintf (out, "saddr %p != test %p\n", info.dli_saddr, test2);
+	  exit (1);
+	}
+    }
+
+  ElfW(Sym) *sym;
+  void *symp;
+  res = dladdr1 (test2, &info, &symp, RTLD_DL_SYMENT);
+  if (res == 0)
+    {
+      fputs ("dladdr1 returned 0\n", out);
+      exit (1);
+    }
+  else
+    {
+      if (strstr (info.dli_fname, "modstatic2.so") == NULL
+	  || strcmp (info.dli_sname, "test") != 0)
+	{
+	  fprintf (out, "fname %s sname %s\n", info.dli_fname, info.dli_sname);
+	  exit (1);
+	}
+      if (info.dli_saddr != (void *) test2)
+	{
+	  fprintf (out, "saddr %p != test %p\n", info.dli_saddr, test2);
+	  exit (1);
+	}
+      sym = symp;
+      if (sym == NULL)
+	{
+	  fputs ("sym == NULL\n", out);
+	  exit (1);
+	}
+      if (ELF32_ST_BIND (sym->st_info) != STB_GLOBAL
+	  || ELF32_ST_VISIBILITY (sym->st_other) != STV_DEFAULT)
+	{
+	  fprintf (out, "bind %d visibility %d\n",
+		   (int) ELF32_ST_BIND (sym->st_info),
+		   (int) ELF32_ST_VISIBILITY (sym->st_other));
+	  exit (1);
+	}
+    }
+
+  Lmid_t lmid;
+  res = dlinfo (handle, RTLD_DI_LMID, &lmid);
+  if (res != 0)
+    {
+      fprintf (out, "dlinfo returned %d %s\n", res, dlerror ());
+      exit (1);
+    }
+  else if (lmid != LM_ID_BASE)
+    {
+      fprintf (out, "lmid %d != %d\n", (int) lmid, (int) LM_ID_BASE);
+      exit (1);
+    }
+
+  void *handle2 = dlopen (LIBDL_SO, RTLD_LAZY);
+  if (handle2 == NULL)
+    {
+      fprintf (out, "libdl.so: %s\n", dlerror ());
+      exit (1);
+    }
+
+#ifdef DO_VERSIONING
+  if (dlvsym (handle2, "_dlfcn_hook", "GLIBC_PRIVATE") == NULL)
+    {
+      fprintf (out, "dlvsym: %s\n", dlerror ());
+      exit (1);
+    }
+#endif
+
+  void *(*dlsymfn) (void *, const char *);
+  dlsymfn = dlsym (handle2, "dlsym");
+  if (dlsymfn == NULL)
+    {
+      fprintf (out, "dlsym \"dlsym\": %s\n", dlerror ());
+      exit (1);
+    }
+  void *test3 = dlsymfn (handle, "test");
+  if (test3 == NULL)
+    {
+      fprintf (out, "%s\n", dlerror ());
+      exit (1);
+    }
+  else if (test3 != (void *) test2)
+    {
+      fprintf (out, "test2 %p != test3 %p\n", test2, test3);
+      exit (1);
+    }
+
+  dlclose (handle2);
+  dlclose (handle);
+
+  handle = dlmopen (LM_ID_BASE, "modstatic2.so", RTLD_LAZY);
+  if (handle == NULL)
+    {
+      fprintf (out, "%s\n", dlerror ());
+      exit (1);
+    }
+  dlclose (handle);
+
+  handle = dlmopen (LM_ID_NEWLM, "modstatic2.so", RTLD_LAZY);
+  if (handle == NULL)
+    fprintf (out, "LM_ID_NEWLM: %s\n", dlerror ());
+  else
+    {
+      fputs ("LM_ID_NEWLM unexpectedly succeeded\n", out);
+      exit (1);
+    }
+
+  handle = dlopen ("modstatic.so", RTLD_LAZY);
+  if (handle == NULL)
+    {
+      fprintf (out, "%s\n", dlerror ());
+      exit (1);
+    }
+
+  int (*test4) (int);
+  test4 = dlsym (handle, "test");
+  if (test4 == NULL)
+    {
+      fprintf (out, "%s\n", dlerror ());
+      exit (1);
+    }
+
+  res = test4 (16);
+  if (res != 16 + 16)
+    {
+      fprintf (out, "modstatic.so (test) returned %d\n", res);
+      exit (1);
+    }
+
+  res = dladdr1 (test4, &info, &symp, RTLD_DL_SYMENT);
+  if (res == 0)
+    {
+      fputs ("dladdr1 returned 0\n", out);
+      exit (1);
+    }
+  else
+    {
+      if (strstr (info.dli_fname, "modstatic.so") == NULL
+	  || strcmp (info.dli_sname, "test") != 0)
+	{
+	  fprintf (out, "fname %s sname %s\n", info.dli_fname, info.dli_sname);
+	  exit (1);
+	}
+      if (info.dli_saddr != (void *) test4)
+	{
+	  fprintf (out, "saddr %p != test %p\n", info.dli_saddr, test4);
+	  exit (1);
+	}
+      sym = symp;
+      if (sym == NULL)
+	{
+	  fputs ("sym == NULL\n", out);
+	  exit (1);
+	}
+      if (ELF32_ST_BIND (sym->st_info) != STB_GLOBAL
+	  || ELF32_ST_VISIBILITY (sym->st_other) != STV_DEFAULT)
+	{
+	  fprintf (out, "bind %d visibility %d\n",
+		   (int) ELF32_ST_BIND (sym->st_info),
+		   (int) ELF32_ST_VISIBILITY (sym->st_other));
+	  exit (1);
+	}
+    }
+
+  dlclose (handle);
+
+  fputs ("leaving modstatic2.c (test)\n", out);
+  return a + a;
+}
--- libc/dlfcn/dlsym.c.jj	2004-02-23 09:46:13.000000000 +0100
+++ libc/dlfcn/dlsym.c	2004-10-18 21:15:49.789861927 +0200
@@ -22,6 +22,16 @@
 
 #include <ldsodefs.h>
 
+#if !defined SHARED && defined IS_IN_libdl
+
+void *
+dlsym (void *handle, const char *name)
+{
+  return __dlsym (handle, name, RETURN_ADDRESS (0));
+}
+
+#else
+
 struct dlsym_args
 {
   /* The arguments to dlsym_doit.  */
@@ -43,10 +53,15 @@ dlsym_doit (void *a)
 
 
 void *
-dlsym (void *handle, const char *name)
+__dlsym (void *handle, const char *name DL_CALLER_DECL)
 {
+# ifdef SHARED
+  if (__builtin_expect (_dlfcn_hook != NULL, 0))
+    return _dlfcn_hook->dlsym (handle, name, DL_CALLER);
+# endif
+
   struct dlsym_args args;
-  args.who = RETURN_ADDRESS (0);
+  args.who = DL_CALLER;
   args.handle = handle;
   args.name = name;
 
@@ -59,3 +74,7 @@ dlsym (void *handle, const char *name)
 
   return result;
 }
+# ifdef SHARED
+strong_alias (__dlsym, dlsym)
+# endif
+#endif
--- libc/dlfcn/Makefile.jj	2004-10-15 23:08:32.000000000 +0200
+++ libc/dlfcn/Makefile	2004-10-18 23:47:11.232148304 +0200
@@ -21,9 +21,11 @@ headers		:= bits/dlfcn.h dlfcn.h
 extra-libs	:= libdl
 libdl-routines	:= dlopen dlclose dlsym dlvsym dlerror dladdr dladdr1 dlinfo \
 		   dlmopen
+routines	:= $(patsubst %,s%,$(libdl-routines))
+elide-routines.os := $(routines)
 distribute	:= dlopenold.c glreflib1.c glreflib2.c failtestmod.c \
 		   defaultmod1.c defaultmod2.c errmsg1mod.c modatexit.c \
-		   modcxaatexit.c modstatic.c \
+		   modcxaatexit.c modstatic.c modstatic2.c \
 		   bug-dlsym1-lib1.c bug-dlsym1-lib2.c
 
 extra-libs-others := libdl
@@ -51,10 +53,11 @@ glreflib2.so-no-z-defs = yes
 errmsg1mod.so-no-z-defs = yes
 
 ifeq (yesyesyes,$(build-static)$(build-shared)$(elf))
-tests += tststatic
-tests-static += tststatic
-modules-names += modstatic
+tests += tststatic tststatic2
+tests-static += tststatic tststatic2
+modules-names += modstatic modstatic2
 tststatic-ENV = LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)elf
+tststatic2-ENV = LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)elf
 endif
 
 extra-objs += $(modules-names:=.os)
@@ -106,7 +109,12 @@ $(objpfx)modatexit.so: $(common-objpfx)l
 $(objpfx)tststatic: $(objpfx)libdl.a
 $(objpfx)tststatic.out: $(objpfx)tststatic $(objpfx)modstatic.so
 
-$(objpfx)modstatic.so: $(common-objpfx)libc.so $(common-objpfx)libc_nonshared.a
+$(objpfx)tststatic2: $(objpfx)libdl.a
+$(objpfx)tststatic2.out: $(objpfx)tststatic2 $(objpfx)modstatic.so \
+			 $(objpfx)modstatic2.so
+
+$(objpfx)modstatic2.so: $(libdl) $(common-objpfx)libc.so \
+			$(common-objpfx)libc_nonshared.a
 
 $(objpfx)bug-dlopen1: $(libdl)
 
--- libc/dlfcn/dlopenold.c.jj	2004-10-15 23:08:32.000000000 +0200
+++ libc/dlfcn/dlopenold.c	2004-10-18 19:10:12.833804663 +0200
@@ -67,6 +67,9 @@ __dlopen_nocheck (const char *file, int 
     mode |= RTLD_LAZY;
   args.mode = mode;
 
+  if (__builtin_expect (_dlfcn_hook != NULL, 0))
+    return _dlfcn_hook->dlopen (file, mode, RETURN_ADDRESS (0));
+
   return _dlerror_run (dlopen_doit, &args) ? NULL : args.new;
 }
 compat_symbol (libdl, __dlopen_nocheck, dlopen, GLIBC_2_0);
--- libc/dlfcn/sdlvsym.c.jj	2004-10-18 21:20:12.850097876 +0200
+++ libc/dlfcn/sdlvsym.c	2004-10-18 21:20:12.850097876 +0200
@@ -0,0 +1 @@
+#include "dlvsym.c"
--- libc/dlfcn/dladdr1.c.jj	2003-03-10 10:12:11.000000000 +0100
+++ libc/dlfcn/dladdr1.c	2004-10-18 20:58:19.241275042 +0200
@@ -1,5 +1,5 @@
 /* Locate the shared object symbol nearest a given address.
-   Copyright (C) 2003 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004 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
@@ -19,9 +19,24 @@
 
 #include <dlfcn.h>
 
+#if !defined SHARED && defined IS_IN_libdl
+
 int
 dladdr1 (const void *address, Dl_info *info, void **extra, int flags)
 {
+  return __dladdr1 (address, info, extra, flags);
+}
+
+#else
+
+int
+__dladdr1 (const void *address, Dl_info *info, void **extra, int flags)
+{
+# ifdef SHARED
+  if (__builtin_expect (_dlfcn_hook != NULL, 0))
+    return _dlfcn_hook->dladdr1 (address, info, extra, flags);
+# endif
+
   switch (flags)
     {
     default:			/* Make this an error?  */
@@ -33,3 +48,7 @@ dladdr1 (const void *address, Dl_info *i
       return _dl_addr (address, info, (struct link_map **) extra, NULL);
     }
 }
+# ifdef SHARED
+strong_alias (__dladdr1, dladdr1)
+# endif
+#endif
--- libc/dlfcn/Versions.jj	2004-10-15 23:08:32.000000000 +0200
+++ libc/dlfcn/Versions	2004-10-18 21:40:34.580972066 +0200
@@ -11,4 +11,7 @@ libdl {
   GLIBC_2.3.4 {
     dlmopen;
   }
+  GLIBC_PRIVATE {
+    _dlfcn_hook;
+  }
 }
--- libc/dlfcn/sdlmopen.c.jj	2004-10-18 21:20:12.000000000 +0200
+++ libc/dlfcn/sdlmopen.c	2004-10-18 23:47:35.610820109 +0200
@@ -0,0 +1 @@
+#include "dlmopen.c"
--- libc/dlfcn/sdlsym.c.jj	2004-10-18 21:20:12.849098055 +0200
+++ libc/dlfcn/sdlsym.c	2004-10-18 21:20:12.849098055 +0200
@@ -0,0 +1 @@
+#include "dlsym.c"
--- libc/dlfcn/sdlerror.c.jj	2004-10-18 21:20:12.847098412 +0200
+++ libc/dlfcn/sdlerror.c	2004-10-18 21:20:12.847098412 +0200
@@ -0,0 +1 @@
+#include "dlerror.c"
--- libc/dlfcn/dlmopen.c.jj	2004-10-14 03:46:27.000000000 +0200
+++ libc/dlfcn/dlmopen.c	2004-10-18 23:42:29.348188934 +0200
@@ -23,6 +23,17 @@
 #include <stddef.h>
 #include <ldsodefs.h>
 
+#if !defined SHARED && defined IS_IN_libdl
+
+void *
+dlmopen (Lmid_t nsid, const char *file, int mode)
+{
+  return __dlmopen (nsid, file, mode, RETURN_ADDRESS (0));
+}
+static_link_warning (dlmopen)
+
+#else
+
 struct dlmopen_args
 {
   /* Namespace ID.  */
@@ -43,11 +54,11 @@ dlmopen_doit (void *a)
 
   /* Non-shared code has no support for multiple namespaces.  */
   if (args->nsid != LM_ID_BASE)
-#ifdef SHARED
+# ifdef SHARED
     /* If trying to open the link map for the main executable the namespace
        must be the main one.  */
     if (args->file == NULL)
-#endif
+# endif
       GLRO(dl_signal_error) (EINVAL, NULL, NULL, N_("invalid namespace"));
 
   args->new = _dl_open (args->file ?: "", args->mode | __RTLD_DLOPEN,
@@ -56,14 +67,32 @@ dlmopen_doit (void *a)
 
 
 void *
-dlmopen (Lmid_t nsid, const char *file, int mode)
+__dlmopen (Lmid_t nsid, const char *file, int mode DL_CALLER_DECL)
 {
+# ifdef SHARED
+  if (__builtin_expect (_dlfcn_hook != NULL, 0))
+    return _dlfcn_hook->dlmopen (nsid, file, mode, RETURN_ADDRESS (0));
+# endif
+
   struct dlmopen_args args;
   args.nsid = nsid;
   args.file = file;
   args.mode = mode;
-  args.caller = RETURN_ADDRESS (0);
+  args.caller = DL_CALLER;
 
+# ifdef SHARED
   return _dlerror_run (dlmopen_doit, &args) ? NULL : args.new;
+# else
+  if (_dlerror_run (dlmopen_doit, &args))
+    return NULL;
+
+  __libc_register_dl_open_hook ((struct link_map *) args.new);
+  __libc_register_dlfcn_hook ((struct link_map *) args.new);
+
+  return args.new;
+# endif
 }
-static_link_warning (dlmopen)
+# ifdef SHARED
+strong_alias (__dlmopen, dlmopen)
+# endif
+#endif
--- libc/dlfcn/sdlclose.c.jj	2004-10-18 21:20:12.846098591 +0200
+++ libc/dlfcn/sdlclose.c	2004-10-18 21:20:12.846098591 +0200
@@ -0,0 +1 @@
+#include "dlclose.c"
--- libc/dlfcn/dlclose.c.jj	2001-07-06 06:54:45.000000000 +0200
+++ libc/dlfcn/dlclose.c	2004-10-18 20:59:07.666740989 +0200
@@ -1,5 +1,6 @@
 /* Close a handle opened by `dlopen'.
-   Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1995, 1996, 1997, 1998, 1999, 2004
+   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
@@ -19,6 +20,16 @@
 
 #include <dlfcn.h>
 
+#if !defined SHARED && defined IS_IN_libdl
+
+int
+dlclose (void *handle)
+{
+  return __dlclose (handle);
+}
+
+#else
+
 static void
 dlclose_doit (void *handle)
 {
@@ -26,7 +37,16 @@ dlclose_doit (void *handle)
 }
 
 int
-dlclose (void *handle)
+__dlclose (void *handle)
 {
+# ifdef SHARED
+  if (__builtin_expect (_dlfcn_hook != NULL, 0))
+    return _dlfcn_hook->dlclose (handle);
+# endif
+
   return _dlerror_run (dlclose_doit, handle) ? -1 : 0;
 }
+# ifdef SHARED
+strong_alias (__dlclose, dlclose)
+# endif
+#endif
--- libc/dlfcn/sdladdr1.c.jj	2004-10-18 21:20:12.845098770 +0200
+++ libc/dlfcn/sdladdr1.c	2004-10-18 21:20:12.845098770 +0200
@@ -0,0 +1 @@
+#include "dladdr1.c"
--- libc/elf/dl-libc.c.jj	2004-10-15 23:08:33.000000000 +0200
+++ libc/elf/dl-libc.c	2004-10-18 19:00:55.139108595 +0200
@@ -121,7 +121,6 @@ do_dlsym_private (void *ptr)
   vers.hidden = 1;
   /* vers.hash = _dl_elf_hash (version);  */
   vers.hash = 0x0963cf85;
-  /* FIXME: Shouldn't we use libc.so.6* here?  */
   vers.filename = NULL;
 
   struct do_dlsym_args *args = (struct do_dlsym_args *) ptr;
@@ -156,23 +155,36 @@ __libc_dlopen_mode (const char *name, in
   if (dlerror_run (do_dlopen, &args))
     return NULL;
 
+  __libc_register_dl_open_hook (args.map);
+  __libc_register_dlfcn_hook (args.map);
+  return (void *) args.map;
+#endif
+}
+libc_hidden_def (__libc_dlopen_mode)
+
+#ifndef SHARED
+void *
+__libc_dlsym_private (struct link_map *map, const char *name)
+{
   struct do_dlsym_args sargs;
-  sargs.map = args.map;
-  sargs.name = "_dl_open_hook";
+  sargs.map = map;
+  sargs.name = name;
 
   if (! dlerror_run (do_dlsym_private, &sargs))
-    {
-      struct dl_open_hook **hook
-	= (struct dl_open_hook **)
-	  (DL_SYMBOL_ADDRESS (sargs.loadbase, sargs.ref));
-      if (hook != NULL)
-	*hook = &_dl_open_hook;
-    }
+    return DL_SYMBOL_ADDRESS (sargs.loadbase, sargs.ref);
+  return NULL;
+}
 
-  return (void *) args.map;
-#endif
+void
+__libc_register_dl_open_hook (struct link_map *map)
+{
+  struct dl_open_hook **hook;
+
+  hook = (struct dl_open_hook **) __libc_dlsym_private (map, "_dl_open_hook");
+  if (hook != NULL)
+    *hook = &_dl_open_hook;
 }
-libc_hidden_def (__libc_dlopen_mode)
+#endif
 
 void *
 __libc_dlsym (void *map, const char *name)
--- libc/include/libc-symbols.h.jj	2004-10-18 10:20:44.000000000 +0200
+++ libc/include/libc-symbols.h	2004-10-18 18:16:08.989695011 +0200
@@ -762,6 +762,24 @@ for linking")
 # define libresolv_hidden_data_ver(local, name)
 #endif
 
+#if defined NOT_IN_libc && defined IS_IN_libdl
+# define libdl_hidden_proto(name, attrs...) hidden_proto (name, ##attrs)
+# define libdl_hidden_def(name) hidden_def (name)
+# define libdl_hidden_weak(name) hidden_weak (name)
+# define libdl_hidden_ver(local, name) hidden_ver (local, name)
+# define libdl_hidden_data_def(name) hidden_data_def (name)
+# define libdl_hidden_data_weak(name) hidden_data_weak (name)
+# define libdl_hidden_data_ver(local, name) hidden_data_ver (local, name)
+#else
+# define libdl_hidden_proto(name, attrs...)
+# define libdl_hidden_def(name)
+# define libdl_hidden_weak(name)
+# define libdl_hidden_ver(local, name)
+# define libdl_hidden_data_def(name)
+# define libdl_hidden_data_weak(name)
+# define libdl_hidden_data_ver(local, name)
+#endif
+
 #ifdef HAVE_BUILTIN_REDIRECTION
 # define libc_hidden_builtin_proto(name, attrs...) libc_hidden_proto (name, ##attrs)
 # define libc_hidden_builtin_def(name) libc_hidden_def (name)
--- libc/include/dlfcn.h.jj	2004-10-15 23:08:33.000000000 +0200
+++ libc/include/dlfcn.h	2004-10-18 21:33:45.000000000 +0200
@@ -11,8 +11,6 @@
 #define __LM_ID_CALLER	-2
 
 /* Now define the internal interfaces.  */
-extern void *__dlvsym (void *__handle, __const char *__name,
-		       __const char *__version);
 
 #define __libc_dlopen(name) __libc_dlopen_mode (name, RTLD_LAZY)
 extern void *__libc_dlopen_mode  (__const char *__name, int __mode);
@@ -76,4 +74,62 @@ extern int _dl_catch_error (const char *
 extern int _dlerror_run (void (*operate) (void *), void *args)
      internal_function;
 
+#ifdef SHARED
+# define DL_CALLER_DECL /* Nothing */
+# define DL_CALLER RETURN_ADDRESS (0)
+#else
+# define DL_CALLER_DECL , void *dl_caller
+# define DL_CALLER dl_caller
+#endif
+
+struct dlfcn_hook
+{
+  void *(*dlopen) (const char *file, int mode, void *dl_caller);
+  int (*dlclose) (void *handle);
+  void *(*dlsym) (void *handle, const char *name, void *dl_caller);
+  void *(*dlvsym) (void *handle, const char *name, const char *version,
+		   void *dl_caller);
+  char *(*dlerror) (void);
+  int (*dladdr) (const void *address, Dl_info *info);
+  int (*dladdr1) (const void *address, Dl_info *info,
+		  void **extra_info, int flags);
+  int (*dlinfo) (void *handle, int request, void *arg, void *dl_caller);
+  void *(*dlmopen) (Lmid_t nsid, const char *file, int mode, void *dl_caller);
+  void *pad[4];
+};
+
+extern struct dlfcn_hook *_dlfcn_hook;
+libdl_hidden_proto (_dlfcn_hook)
+
+extern void *__dlopen (const char *file, int mode DL_CALLER_DECL)
+     attribute_hidden;
+extern void *__dlmopen (Lmid_t nsid, const char *file, int mode DL_CALLER_DECL)
+     attribute_hidden;
+extern int __dlclose (void *handle)
+     attribute_hidden;
+extern void *__dlsym (void *handle, const char *name DL_CALLER_DECL)
+     attribute_hidden;
+extern void *__dlvsym (void *handle, const char *name, const char *version
+		       DL_CALLER_DECL)
+     attribute_hidden;
+extern char *__dlerror (void)
+     attribute_hidden;
+extern int __dladdr (const void *address, Dl_info *info)
+     attribute_hidden;
+extern int __dladdr1 (const void *address, Dl_info *info,
+		      void **extra_info, int flags)
+     attribute_hidden;
+extern int __dlinfo (void *handle, int request, void *arg DL_CALLER_DECL)
+     attribute_hidden;
+
+#ifndef SHARED
+struct link_map;
+extern void * __libc_dlsym_private (struct link_map *map, const char *name)
+     attribute_hidden;
+extern void __libc_register_dl_open_hook (struct link_map *map)
+     attribute_hidden;
+extern void __libc_register_dlfcn_hook (struct link_map *map)
+     attribute_hidden;
+#endif
+
 #endif

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]