Back to index

glibc  2.9
dl-libc.c
Go to the documentation of this file.
00001 /* Handle loading and unloading shared objects for internal libc purposes.
00002    Copyright (C) 1999-2002,2004,2005,2006 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Zack Weinberg <zack@rabi.columbia.edu>, 1999.
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 <dlfcn.h>
00022 #include <stdlib.h>
00023 #include <ldsodefs.h>
00024 
00025 extern int __libc_argc attribute_hidden;
00026 extern char **__libc_argv attribute_hidden;
00027 
00028 extern char **__environ;
00029 
00030 /* The purpose of this file is to provide wrappers around the dynamic
00031    linker error mechanism (similar to dlopen() et al in libdl) which
00032    are usable from within libc.  Generally we want to throw away the
00033    string that dlerror() would return and just pass back a null pointer
00034    for errors.  This also lets the rest of libc not know about the error
00035    handling mechanism.
00036 
00037    Much of this code came from gconv_dl.c with slight modifications. */
00038 
00039 static int
00040 internal_function
00041 dlerror_run (void (*operate) (void *), void *args)
00042 {
00043   const char *objname;
00044   const char *last_errstring = NULL;
00045   bool malloced;
00046 
00047   (void) GLRO(dl_catch_error) (&objname, &last_errstring, &malloced,
00048                             operate, args);
00049 
00050   int result = last_errstring != NULL;
00051   if (result && malloced)
00052     free ((char *) last_errstring);
00053 
00054   return result;
00055 }
00056 
00057 /* These functions are called by dlerror_run... */
00058 
00059 struct do_dlopen_args
00060 {
00061   /* Argument to do_dlopen.  */
00062   const char *name;
00063   /* Opening mode.  */
00064   int mode;
00065 
00066   /* Return from do_dlopen.  */
00067   struct link_map *map;
00068 };
00069 
00070 struct do_dlsym_args
00071 {
00072   /* Arguments to do_dlsym.  */
00073   struct link_map *map;
00074   const char *name;
00075 
00076   /* Return values of do_dlsym.  */
00077   lookup_t loadbase;
00078   const ElfW(Sym) *ref;
00079 };
00080 
00081 static void
00082 do_dlopen (void *ptr)
00083 {
00084   struct do_dlopen_args *args = (struct do_dlopen_args *) ptr;
00085   /* Open and relocate the shared object.  */
00086   args->map = GLRO(dl_open) (args->name, args->mode, NULL, __LM_ID_CALLER,
00087                           __libc_argc, __libc_argv, __environ);
00088 }
00089 
00090 static void
00091 do_dlsym (void *ptr)
00092 {
00093   struct do_dlsym_args *args = (struct do_dlsym_args *) ptr;
00094   args->ref = NULL;
00095   args->loadbase = GLRO(dl_lookup_symbol_x) (args->name, args->map, &args->ref,
00096                                         args->map->l_local_scope, NULL, 0,
00097                                         DL_LOOKUP_RETURN_NEWEST, NULL);
00098 }
00099 
00100 static void
00101 do_dlclose (void *ptr)
00102 {
00103   GLRO(dl_close) ((struct link_map *) ptr);
00104 }
00105 
00106 /* This code is to support __libc_dlopen from __libc_dlopen'ed shared
00107    libraries.  We need to ensure the statically linked __libc_dlopen
00108    etc. functions are used instead of the dynamically loaded.  */
00109 struct dl_open_hook
00110 {
00111   void *(*dlopen_mode) (const char *name, int mode);
00112   void *(*dlsym) (void *map, const char *name);
00113   int (*dlclose) (void *map);
00114 };
00115 
00116 #ifdef SHARED
00117 extern struct dl_open_hook *_dl_open_hook;
00118 libc_hidden_proto (_dl_open_hook);
00119 struct dl_open_hook *_dl_open_hook __attribute__ ((nocommon));
00120 libc_hidden_data_def (_dl_open_hook);
00121 #else
00122 static void
00123 do_dlsym_private (void *ptr)
00124 {
00125   lookup_t l;
00126   struct r_found_version vers;
00127   vers.name = "GLIBC_PRIVATE";
00128   vers.hidden = 1;
00129   /* vers.hash = _dl_elf_hash (vers.name);  */
00130   vers.hash = 0x0963cf85;
00131   vers.filename = NULL;
00132 
00133   struct do_dlsym_args *args = (struct do_dlsym_args *) ptr;
00134   args->ref = NULL;
00135   l = GLRO(dl_lookup_symbol_x) (args->name, args->map, &args->ref,
00136                             args->map->l_scope, &vers, 0, 0, NULL);
00137   args->loadbase = l;
00138 }
00139 
00140 static struct dl_open_hook _dl_open_hook =
00141   {
00142     .dlopen_mode = __libc_dlopen_mode,
00143     .dlsym = __libc_dlsym,
00144     .dlclose = __libc_dlclose
00145   };
00146 #endif
00147 
00148 /* ... and these functions call dlerror_run. */
00149 
00150 void *
00151 __libc_dlopen_mode (const char *name, int mode)
00152 {
00153   struct do_dlopen_args args;
00154   args.name = name;
00155   args.mode = mode;
00156 
00157 #ifdef SHARED
00158   if (__builtin_expect (_dl_open_hook != NULL, 0))
00159     return _dl_open_hook->dlopen_mode (name, mode);
00160   return (dlerror_run (do_dlopen, &args) ? NULL : (void *) args.map);
00161 #else
00162   if (dlerror_run (do_dlopen, &args))
00163     return NULL;
00164 
00165   __libc_register_dl_open_hook (args.map);
00166   __libc_register_dlfcn_hook (args.map);
00167   return (void *) args.map;
00168 #endif
00169 }
00170 libc_hidden_def (__libc_dlopen_mode)
00171 
00172 #ifndef SHARED
00173 void *
00174 __libc_dlsym_private (struct link_map *map, const char *name)
00175 {
00176   struct do_dlsym_args sargs;
00177   sargs.map = map;
00178   sargs.name = name;
00179 
00180   if (! dlerror_run (do_dlsym_private, &sargs))
00181     return DL_SYMBOL_ADDRESS (sargs.loadbase, sargs.ref);
00182   return NULL;
00183 }
00184 
00185 void
00186 __libc_register_dl_open_hook (struct link_map *map)
00187 {
00188   struct dl_open_hook **hook;
00189 
00190   hook = (struct dl_open_hook **) __libc_dlsym_private (map, "_dl_open_hook");
00191   if (hook != NULL)
00192     *hook = &_dl_open_hook;
00193 }
00194 #endif
00195 
00196 void *
00197 __libc_dlsym (void *map, const char *name)
00198 {
00199   struct do_dlsym_args args;
00200   args.map = map;
00201   args.name = name;
00202 
00203 #ifdef SHARED
00204   if (__builtin_expect (_dl_open_hook != NULL, 0))
00205     return _dl_open_hook->dlsym (map, name);
00206 #endif
00207   return (dlerror_run (do_dlsym, &args) ? NULL
00208          : (void *) (DL_SYMBOL_ADDRESS (args.loadbase, args.ref)));
00209 }
00210 libc_hidden_def (__libc_dlsym)
00211 
00212 int
00213 __libc_dlclose (void *map)
00214 {
00215 #ifdef SHARED
00216   if (__builtin_expect (_dl_open_hook != NULL, 0))
00217     return _dl_open_hook->dlclose (map);
00218 #endif
00219   return dlerror_run (do_dlclose, map);
00220 }
00221 libc_hidden_def (__libc_dlclose)
00222 
00223 
00224 libc_freeres_fn (free_mem)
00225 {
00226   struct link_map *l;
00227   struct r_search_path_elem *d;
00228 
00229   /* Remove all search directories.  */
00230   d = GL(dl_all_dirs);
00231   while (d != GLRO(dl_init_all_dirs))
00232     {
00233       struct r_search_path_elem *old = d;
00234       d = d->next;
00235       free (old);
00236     }
00237 
00238   /* Remove all additional names added to the objects.  */
00239   for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
00240     for (l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next)
00241       {
00242        struct libname_list *lnp = l->l_libname->next;
00243 
00244        l->l_libname->next = NULL;
00245 
00246        while (lnp != NULL)
00247          {
00248            struct libname_list *old = lnp;
00249            lnp = lnp->next;
00250            if (! old->dont_free)
00251            free (old);
00252          }
00253       }
00254 }