root/libltdl/loaders/dyld.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_vtable
  2. vl_exit
  3. vl_init
  4. vm_open
  5. vm_close
  6. vm_sym
  7. dylderror
  8. lt__nsmodule_get_header
  9. lt__header_get_instnam
  10. lt__match_loadedlib
  11. lt__linkedlib_symbol

   1 /* loader-dyld.c -- dynamic linking on darwin and OS X
   2 
   3    Copyright (C) 1998, 1999, 2000, 2004, 2006,
   4                  2007, 2008 Free Software Foundation, Inc.
   5    Written by Peter O'Gorman, 1998
   6 
   7    NOTE: The canonical source of this file is maintained with the
   8    GNU Libtool package.  Report bugs to bug-libtool@gnu.org.
   9 
  10 GNU Libltdl is free software; you can redistribute it and/or
  11 modify it under the terms of the GNU Lesser General Public
  12 License as published by the Free Software Foundation; either
  13 version 2 of the License, or (at your option) any later version.
  14 
  15 As a special exception to the GNU Lesser General Public License,
  16 if you distribute this file as part of a program or library that
  17 is built using GNU Libtool, you may include this file under the
  18 same distribution terms that you use for the rest of that program.
  19 
  20 GNU Libltdl is distributed in the hope that it will be useful,
  21 but WITHOUT ANY WARRANTY; without even the implied warranty of
  22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23 GNU Lesser General Public License for more details.
  24 
  25 You should have received a copy of the GNU Lesser General Public
  26 License along with GNU Libltdl; see the file COPYING.LIB.  If not, a
  27 copy can be downloaded from  http://www.gnu.org/licenses/lgpl.html,
  28 or obtained by writing to the Free Software Foundation, Inc.,
  29 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  30 */
  31 
  32 #include "lt__private.h"
  33 #include "lt_dlloader.h"
  34 
  35 /* Use the preprocessor to rename non-static symbols to avoid namespace
  36    collisions when the loader code is statically linked into libltdl.
  37    Use the "<module_name>_LTX_" prefix so that the symbol addresses can
  38    be fetched from the preloaded symbol list by lt_dlsym():  */
  39 #define get_vtable      dyld_LTX_get_vtable
  40 
  41 LT_BEGIN_C_DECLS
  42 LT_SCOPE lt_dlvtable *get_vtable (lt_user_data loader_data);
  43 LT_END_C_DECLS
  44 
  45 
  46 /* Boilerplate code to set up the vtable for hooking this loader into
  47    libltdl's loader list:  */
  48 static int       vl_init  (lt_user_data loader_data);
  49 static int       vl_exit  (lt_user_data loader_data);
  50 static lt_module vm_open  (lt_user_data loader_data, const char *filename,
  51                            lt_dladvise advise);
  52 static int       vm_close (lt_user_data loader_data, lt_module module);
  53 static void *    vm_sym   (lt_user_data loader_data, lt_module module,
  54                           const char *symbolname);
  55 
  56 static lt_dlvtable *vtable = 0;
  57 
  58 /* Return the vtable for this loader, only the name and sym_prefix
  59    attributes (plus the virtual function implementations, obviously)
  60    change between loaders.  */
  61 lt_dlvtable *
  62 get_vtable (lt_user_data loader_data)
     /* [previous][next][first][last][top][bottom][index][help] */
  63 {
  64   if (!vtable)
  65     {
  66       vtable = lt__zalloc (sizeof *vtable);
  67     }
  68 
  69   if (vtable && !vtable->name)
  70     {
  71       vtable->name              = "lt_dyld";
  72       vtable->sym_prefix        = "_";
  73       vtable->dlloader_init     = vl_init;
  74       vtable->module_open       = vm_open;
  75       vtable->module_close      = vm_close;
  76       vtable->find_sym          = vm_sym;
  77       vtable->dlloader_exit     = vl_exit;
  78       vtable->dlloader_data     = loader_data;
  79       vtable->priority          = LT_DLLOADER_APPEND;
  80     }
  81 
  82   if (vtable && (vtable->dlloader_data != loader_data))
  83     {
  84       LT__SETERROR (INIT_LOADER);
  85       return 0;
  86     }
  87 
  88   return vtable;
  89 }
  90 
  91 
  92 
  93 /* --- IMPLEMENTATION --- */
  94 
  95 
  96 #if defined(HAVE_MACH_O_DYLD_H)
  97 #  if !defined(__APPLE_CC__) && !defined(__MWERKS__) && !defined(__private_extern__)
  98   /* Is this correct? Does it still function properly? */
  99 #    define __private_extern__ extern
 100 #  endif
 101 #  include <mach-o/dyld.h>
 102 #endif
 103 
 104 #include <mach-o/getsect.h>
 105 
 106 /* We have to put some stuff here that isn't in older dyld.h files */
 107 #if !defined(ENUM_DYLD_BOOL)
 108 # define ENUM_DYLD_BOOL
 109 # undef FALSE
 110 # undef TRUE
 111  enum DYLD_BOOL {
 112     FALSE,
 113     TRUE
 114  };
 115 #endif
 116 #if !defined(LC_REQ_DYLD)
 117 # define LC_REQ_DYLD 0x80000000
 118 #endif
 119 #if !defined(LC_LOAD_WEAK_DYLIB)
 120 # define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD)
 121 #endif
 122 
 123 #if !defined(NSADDIMAGE_OPTION_NONE)
 124 #  define NSADDIMAGE_OPTION_NONE                          0x0
 125 #endif
 126 #if !defined(NSADDIMAGE_OPTION_RETURN_ON_ERROR)
 127 #  define NSADDIMAGE_OPTION_RETURN_ON_ERROR               0x1
 128 #endif
 129 #if !defined(NSADDIMAGE_OPTION_WITH_SEARCHING)
 130 #  define NSADDIMAGE_OPTION_WITH_SEARCHING                0x2
 131 #endif
 132 #if !defined(NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED)
 133 #  define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED         0x4
 134 #endif
 135 #if !defined(NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME)
 136 #  define NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME 0x8
 137 #endif
 138 
 139 #if !defined(NSLOOKUPSYMBOLINIMAGE_OPTION_BIND)
 140 #  define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND               0x0
 141 #endif
 142 #if !defined(NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW)
 143 #  define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW           0x1
 144 #endif
 145 #if !defined(NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY)
 146 #  define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY         0x2
 147 #endif
 148 #if !defined(NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR)
 149 #  define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR    0x4
 150 #endif
 151 
 152 #define LT__SYMLOOKUP_OPTS      (NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW \
 153                                 | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR)
 154 
 155 #if defined(__BIG_ENDIAN__)
 156 #  define LT__MAGIC     MH_MAGIC
 157 #else
 158 #  define LT__MAGIC     MH_CIGAM
 159 #endif
 160 
 161 #define DYLD__SETMYERROR(errmsg)    LT__SETERRORSTR (dylderror (errmsg))
 162 #define DYLD__SETERROR(errcode)     DYLD__SETMYERROR (LT__STRERROR (errcode))
 163 
 164 typedef struct mach_header mach_header;
 165 typedef struct dylib_command dylib_command;
 166 
 167 static const char *dylderror (const char *errmsg);
 168 static const mach_header *lt__nsmodule_get_header (NSModule module);
 169 static const char *lt__header_get_instnam (const mach_header *mh);
 170 static const mach_header *lt__match_loadedlib (const char *name);
 171 static NSSymbol lt__linkedlib_symbol (const char *symname, const mach_header *mh);
 172 
 173 static const mach_header *(*lt__addimage)       (const char *image_name,
 174                                                  unsigned long options) = 0;
 175 static NSSymbol (*lt__image_symbol)             (const mach_header *image,
 176                                                  const char *symbolName,
 177                                                  unsigned long options) = 0;
 178 static enum DYLD_BOOL (*lt__image_symbol_p)     (const mach_header *image,
 179                                                  const char *symbolName) = 0;
 180 static enum DYLD_BOOL (*lt__module_export)      (NSModule module) = 0;
 181 
 182 static int dyld_cannot_close                              = 0;
 183 
 184 
 185 /* A function called through the vtable when this loader is no
 186    longer needed by the application.  */
 187 static int
 188 vl_exit (lt_user_data LT__UNUSED loader_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 189 {
 190   vtable = NULL;
 191   return 0;
 192 }
 193 
 194 /* A function called through the vtable to initialise this loader.  */
 195 static int
 196 vl_init (lt_user_data loader_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 197 {
 198   int errors = 0;
 199 
 200   if (! dyld_cannot_close)
 201     {
 202       if (!_dyld_present ())
 203         {
 204           ++errors;
 205         }
 206       else
 207         {
 208           (void) _dyld_func_lookup ("__dyld_NSAddImage",
 209                                     (unsigned long*) &lt__addimage);
 210           (void) _dyld_func_lookup ("__dyld_NSLookupSymbolInImage",
 211                                     (unsigned long*)&lt__image_symbol);
 212           (void) _dyld_func_lookup ("__dyld_NSIsSymbolNameDefinedInImage",
 213                                     (unsigned long*) &lt__image_symbol_p);
 214           (void) _dyld_func_lookup ("__dyld_NSMakePrivateModulePublic",
 215                                     (unsigned long*) &lt__module_export);
 216           dyld_cannot_close = lt_dladderror ("can't close a dylib");
 217         }
 218     }
 219 
 220   return errors;
 221 }
 222 
 223 
 224 /* A function called through the vtable to open a module with this
 225    loader.  Returns an opaque representation of the newly opened
 226    module for processing with this loader's other vtable functions.  */
 227 static lt_module
 228 vm_open (lt_user_data loader_data, const char *filename,
     /* [previous][next][first][last][top][bottom][index][help] */
 229          lt_dladvise LT__UNUSED advise)
 230 {
 231   lt_module module = 0;
 232   NSObjectFileImage ofi = 0;
 233 
 234   if (!filename)
 235     {
 236       return (lt_module) -1;
 237     }
 238 
 239   switch (NSCreateObjectFileImageFromFile (filename, &ofi))
 240     {
 241     case NSObjectFileImageSuccess:
 242       module = NSLinkModule (ofi, filename, NSLINKMODULE_OPTION_RETURN_ON_ERROR
 243                                             | NSLINKMODULE_OPTION_PRIVATE
 244                                             | NSLINKMODULE_OPTION_BINDNOW);
 245       NSDestroyObjectFileImage (ofi);
 246 
 247       if (module)
 248         {
 249           lt__module_export (module);
 250         }
 251       break;
 252 
 253     case NSObjectFileImageInappropriateFile:
 254       if (lt__image_symbol_p && lt__image_symbol)
 255         {
 256           module = (lt_module) lt__addimage(filename,
 257                                             NSADDIMAGE_OPTION_RETURN_ON_ERROR);
 258         }
 259       break;
 260 
 261     case NSObjectFileImageFailure:
 262     case NSObjectFileImageArch:
 263     case NSObjectFileImageFormat:
 264     case NSObjectFileImageAccess:
 265       /*NOWORK*/
 266       break;
 267     }
 268 
 269   if (!module)
 270     {
 271       DYLD__SETERROR (CANNOT_OPEN);
 272     }
 273 
 274   return module;
 275 }
 276 
 277 
 278 /* A function called through the vtable when a particular module
 279    should be unloaded.  */
 280 static int
 281 vm_close (lt_user_data loader_data, lt_module module)
     /* [previous][next][first][last][top][bottom][index][help] */
 282 {
 283   int errors = 0;
 284 
 285   if (module != (lt_module) -1)
 286     {
 287       const mach_header *mh = (const mach_header *) module;
 288       int flags = 0;
 289       if (mh->magic == LT__MAGIC)
 290         {
 291           lt_dlseterror (dyld_cannot_close);
 292           ++errors;
 293         }
 294       else
 295         {
 296           /* Currently, if a module contains c++ static destructors and it
 297              is unloaded, we get a segfault in atexit(), due to compiler and
 298              dynamic loader differences of opinion, this works around that.  */
 299           if ((const struct section *) NULL !=
 300               getsectbynamefromheader (lt__nsmodule_get_header (module),
 301                                        "__DATA", "__mod_term_func"))
 302             {
 303               flags |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
 304             }
 305 #if defined(__ppc__)
 306           flags |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;
 307 #endif
 308           if (!NSUnLinkModule (module, flags))
 309             {
 310               DYLD__SETERROR (CANNOT_CLOSE);
 311               ++errors;
 312             }
 313         }
 314     }
 315 
 316   return errors;
 317 }
 318 
 319 /* A function called through the vtable to get the address of
 320    a symbol loaded from a particular module.  */
 321 static void *
 322 vm_sym (lt_user_data loader_data, lt_module module, const char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
 323 {
 324   NSSymbol *nssym = 0;
 325   const mach_header *mh = (const mach_header *) module;
 326   char saveError[256] = "Symbol not found";
 327 
 328   if (module == (lt_module) -1)
 329     {
 330       void *address, *unused;
 331       _dyld_lookup_and_bind (name, (unsigned long*) &address, &unused);
 332       return address;
 333     }
 334 
 335   if (mh->magic == LT__MAGIC)
 336     {
 337       if (lt__image_symbol_p && lt__image_symbol)
 338         {
 339           if (lt__image_symbol_p (mh, name))
 340             {
 341               nssym = lt__image_symbol (mh, name, LT__SYMLOOKUP_OPTS);
 342             }
 343         }
 344 
 345     }
 346   else
 347     {
 348       nssym = NSLookupSymbolInModule (module, name);
 349     }
 350 
 351   if (!nssym)
 352     {
 353       strncpy (saveError, dylderror (LT__STRERROR (SYMBOL_NOT_FOUND)), 255);
 354       saveError[255] = 0;
 355       if (!mh)
 356         {
 357           mh = (mach_header *)lt__nsmodule_get_header (module);
 358         }
 359       nssym = lt__linkedlib_symbol (name, mh);
 360     }
 361 
 362   if (!nssym)
 363     {
 364       LT__SETERRORSTR (saveError);
 365     }
 366 
 367   return nssym ? NSAddressOfSymbol (nssym) : 0;
 368 }
 369 
 370 
 371 
 372 
 373 /* --- HELPER FUNCTIONS --- */
 374 
 375 
 376 /* Return the dyld error string, or the passed in error string if none. */
 377 static const char *
 378 dylderror (const char *errmsg)
     /* [previous][next][first][last][top][bottom][index][help] */
 379 {
 380   NSLinkEditErrors ler;
 381   int lerno;
 382   const char *file;
 383   const char *errstr;
 384 
 385   NSLinkEditError (&ler, &lerno, &file, &errstr);
 386 
 387   if (! (errstr && *errstr))
 388     {
 389       errstr = errmsg;
 390     }
 391 
 392   return errstr;
 393 }
 394 
 395 /* There should probably be an apple dyld api for this. */
 396 static const mach_header *
 397 lt__nsmodule_get_header (NSModule module)
     /* [previous][next][first][last][top][bottom][index][help] */
 398 {
 399   int i = _dyld_image_count();
 400   const char *modname = NSNameOfModule (module);
 401   const mach_header *mh = 0;
 402 
 403   if (!modname)
 404     return NULL;
 405 
 406   while (i > 0)
 407     {
 408       --i;
 409       if (strneq (_dyld_get_image_name (i), modname))
 410         {
 411           mh = _dyld_get_image_header (i);
 412           break;
 413         }
 414     }
 415 
 416   return mh;
 417 }
 418 
 419 /* NSAddImage is also used to get the loaded image, but it only works if
 420    the lib is installed, for uninstalled libs we need to check the
 421    install_names against each other.  Note that this is still broken if
 422    DYLD_IMAGE_SUFFIX is set and a different lib was loaded as a result.  */
 423 static const char *
 424 lt__header_get_instnam (const mach_header *mh)
     /* [previous][next][first][last][top][bottom][index][help] */
 425 {
 426   unsigned long offset = sizeof(mach_header);
 427   const char* result   = 0;
 428   int j;
 429 
 430   for (j = 0; j < mh->ncmds; j++)
 431     {
 432       struct load_command *lc;
 433 
 434       lc = (struct load_command*) (((unsigned long) mh) + offset);
 435       if (LC_ID_DYLIB == lc->cmd)
 436         {
 437           result=(char*)(((dylib_command*) lc)->dylib.name.offset +
 438                          (unsigned long) lc);
 439         }
 440       offset += lc->cmdsize;
 441     }
 442 
 443   return result;
 444 }
 445 
 446 static const mach_header *
 447 lt__match_loadedlib (const char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
 448 {
 449   const mach_header *mh = 0;
 450   int i = _dyld_image_count();
 451 
 452   while (i > 0)
 453     {
 454       const char *id;
 455 
 456       --i;
 457       id = lt__header_get_instnam (_dyld_get_image_header (i));
 458       if (id && strneq (id, name))
 459         {
 460           mh = _dyld_get_image_header (i);
 461           break;
 462         }
 463     }
 464 
 465   return mh;
 466 }
 467 
 468 /* Safe to assume our mh is good. */
 469 static NSSymbol
 470 lt__linkedlib_symbol (const char *symname, const mach_header *mh)
     /* [previous][next][first][last][top][bottom][index][help] */
 471 {
 472   NSSymbol symbol = 0;
 473 
 474   if (lt__image_symbol && NSIsSymbolNameDefined (symname))
 475     {
 476       unsigned long offset = sizeof(mach_header);
 477       struct load_command *lc;
 478       int j;
 479 
 480       for (j = 0; j < mh->ncmds; j++)
 481         {
 482           lc = (struct load_command*) (((unsigned long) mh) + offset);
 483           if ((LC_LOAD_DYLIB == lc->cmd) || (LC_LOAD_WEAK_DYLIB == lc->cmd))
 484             {
 485               unsigned long base = ((dylib_command *) lc)->dylib.name.offset;
 486               char *name = (char *) (base + (unsigned long) lc);
 487               const mach_header *mh1 = lt__match_loadedlib (name);
 488 
 489               if (!mh1)
 490                 {
 491                   /* Maybe NSAddImage can find it */
 492                   mh1 = lt__addimage (name,
 493                                       NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
 494                                       | NSADDIMAGE_OPTION_WITH_SEARCHING
 495                                       | NSADDIMAGE_OPTION_RETURN_ON_ERROR);
 496                 }
 497 
 498               if (mh1)
 499                 {
 500                   symbol = lt__image_symbol (mh1, symname, LT__SYMLOOKUP_OPTS);
 501                   if (symbol)
 502                     break;
 503                 }
 504             }
 505 
 506           offset += lc->cmdsize;
 507         }
 508     }
 509 
 510   return symbol;
 511 }

/* [previous][next][first][last][top][bottom][index][help] */