1
/* loader-dyld.c -- dynamic linking on darwin and OS X
3
Copyright (C) 1998, 1999, 2000, 2004, 2006,
4
2007, 2008 Free Software Foundation, Inc.
5
Written by Peter O'Gorman, 1998
7
NOTE: The canonical source of this file is maintained with the
8
GNU Libtool package. Report bugs to bug-libtool@gnu.org.
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.
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.
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.
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.
32
#include "lt__private.h"
33
#include "lt_dlloader.h"
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
42
LT_SCOPE lt_dlvtable *get_vtable (lt_user_data loader_data);
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,
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);
56
static lt_dlvtable *vtable = 0;
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. */
62
get_vtable (lt_user_data loader_data)
66
vtable = lt__zalloc (sizeof *vtable);
69
if (vtable && !vtable->name)
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;
82
if (vtable && (vtable->dlloader_data != loader_data))
84
LT__SETERROR (INIT_LOADER);
93
/* --- IMPLEMENTATION --- */
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
101
# include <mach-o/dyld.h>
104
#include <mach-o/getsect.h>
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
116
#if !defined(LC_REQ_DYLD)
117
# define LC_REQ_DYLD 0x80000000
119
#if !defined(LC_LOAD_WEAK_DYLIB)
120
# define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD)
123
#if !defined(NSADDIMAGE_OPTION_NONE)
124
# define NSADDIMAGE_OPTION_NONE 0x0
126
#if !defined(NSADDIMAGE_OPTION_RETURN_ON_ERROR)
127
# define NSADDIMAGE_OPTION_RETURN_ON_ERROR 0x1
129
#if !defined(NSADDIMAGE_OPTION_WITH_SEARCHING)
130
# define NSADDIMAGE_OPTION_WITH_SEARCHING 0x2
132
#if !defined(NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED)
133
# define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 0x4
135
#if !defined(NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME)
136
# define NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME 0x8
139
#if !defined(NSLOOKUPSYMBOLINIMAGE_OPTION_BIND)
140
# define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND 0x0
142
#if !defined(NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW)
143
# define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW 0x1
145
#if !defined(NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY)
146
# define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY 0x2
148
#if !defined(NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR)
149
# define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4
152
#define LT__SYMLOOKUP_OPTS (NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW \
153
| NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR)
155
#if defined(__BIG_ENDIAN__)
156
# define LT__MAGIC MH_MAGIC
158
# define LT__MAGIC MH_CIGAM
161
#define DYLD__SETMYERROR(errmsg) LT__SETERRORSTR (dylderror (errmsg))
162
#define DYLD__SETERROR(errcode) DYLD__SETMYERROR (LT__STRERROR (errcode))
164
typedef struct mach_header mach_header;
165
typedef struct dylib_command dylib_command;
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);
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;
182
static int dyld_cannot_close = 0;
185
/* A function called through the vtable when this loader is no
186
longer needed by the application. */
188
vl_exit (lt_user_data LT__UNUSED loader_data)
194
/* A function called through the vtable to initialise this loader. */
196
vl_init (lt_user_data loader_data)
200
if (! dyld_cannot_close)
202
if (!_dyld_present ())
208
(void) _dyld_func_lookup ("__dyld_NSAddImage",
209
(unsigned long*) <__addimage);
210
(void) _dyld_func_lookup ("__dyld_NSLookupSymbolInImage",
211
(unsigned long*)<__image_symbol);
212
(void) _dyld_func_lookup ("__dyld_NSIsSymbolNameDefinedInImage",
213
(unsigned long*) <__image_symbol_p);
214
(void) _dyld_func_lookup ("__dyld_NSMakePrivateModulePublic",
215
(unsigned long*) <__module_export);
216
dyld_cannot_close = lt_dladderror ("can't close a dylib");
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. */
228
vm_open (lt_user_data loader_data, const char *filename,
229
lt_dladvise LT__UNUSED advise)
231
lt_module module = 0;
232
NSObjectFileImage ofi = 0;
236
return (lt_module) -1;
239
switch (NSCreateObjectFileImageFromFile (filename, &ofi))
241
case NSObjectFileImageSuccess:
242
module = NSLinkModule (ofi, filename, NSLINKMODULE_OPTION_RETURN_ON_ERROR
243
| NSLINKMODULE_OPTION_PRIVATE
244
| NSLINKMODULE_OPTION_BINDNOW);
245
NSDestroyObjectFileImage (ofi);
249
lt__module_export (module);
253
case NSObjectFileImageInappropriateFile:
254
if (lt__image_symbol_p && lt__image_symbol)
256
module = (lt_module) lt__addimage(filename,
257
NSADDIMAGE_OPTION_RETURN_ON_ERROR);
261
case NSObjectFileImageFailure:
262
case NSObjectFileImageArch:
263
case NSObjectFileImageFormat:
264
case NSObjectFileImageAccess:
271
DYLD__SETERROR (CANNOT_OPEN);
278
/* A function called through the vtable when a particular module
279
should be unloaded. */
281
vm_close (lt_user_data loader_data, lt_module module)
285
if (module != (lt_module) -1)
287
const mach_header *mh = (const mach_header *) module;
289
if (mh->magic == LT__MAGIC)
291
lt_dlseterror (dyld_cannot_close);
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"))
303
flags |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
306
flags |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;
308
if (!NSUnLinkModule (module, flags))
310
DYLD__SETERROR (CANNOT_CLOSE);
319
/* A function called through the vtable to get the address of
320
a symbol loaded from a particular module. */
322
vm_sym (lt_user_data loader_data, lt_module module, const char *name)
325
const mach_header *mh = (const mach_header *) module;
326
char saveError[256] = "Symbol not found";
328
if (module == (lt_module) -1)
330
void *address, *unused;
331
_dyld_lookup_and_bind (name, (unsigned long*) &address, &unused);
335
if (mh->magic == LT__MAGIC)
337
if (lt__image_symbol_p && lt__image_symbol)
339
if (lt__image_symbol_p (mh, name))
341
nssym = lt__image_symbol (mh, name, LT__SYMLOOKUP_OPTS);
348
nssym = NSLookupSymbolInModule (module, name);
353
strncpy (saveError, dylderror (LT__STRERROR (SYMBOL_NOT_FOUND)), 255);
357
mh = (mach_header *)lt__nsmodule_get_header (module);
359
nssym = lt__linkedlib_symbol (name, mh);
364
LT__SETERRORSTR (saveError);
367
return nssym ? NSAddressOfSymbol (nssym) : 0;
373
/* --- HELPER FUNCTIONS --- */
376
/* Return the dyld error string, or the passed in error string if none. */
378
dylderror (const char *errmsg)
380
NSLinkEditErrors ler;
385
NSLinkEditError (&ler, &lerno, &file, &errstr);
387
if (! (errstr && *errstr))
395
/* There should probably be an apple dyld api for this. */
396
static const mach_header *
397
lt__nsmodule_get_header (NSModule module)
399
int i = _dyld_image_count();
400
const char *modname = NSNameOfModule (module);
401
const mach_header *mh = 0;
409
if (strneq (_dyld_get_image_name (i), modname))
411
mh = _dyld_get_image_header (i);
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. */
424
lt__header_get_instnam (const mach_header *mh)
426
unsigned long offset = sizeof(mach_header);
427
const char* result = 0;
430
for (j = 0; j < mh->ncmds; j++)
432
struct load_command *lc;
434
lc = (struct load_command*) (((unsigned long) mh) + offset);
435
if (LC_ID_DYLIB == lc->cmd)
437
result=(char*)(((dylib_command*) lc)->dylib.name.offset +
440
offset += lc->cmdsize;
446
static const mach_header *
447
lt__match_loadedlib (const char *name)
449
const mach_header *mh = 0;
450
int i = _dyld_image_count();
457
id = lt__header_get_instnam (_dyld_get_image_header (i));
458
if (id && strneq (id, name))
460
mh = _dyld_get_image_header (i);
468
/* Safe to assume our mh is good. */
470
lt__linkedlib_symbol (const char *symname, const mach_header *mh)
474
if (lt__image_symbol && NSIsSymbolNameDefined (symname))
476
unsigned long offset = sizeof(mach_header);
477
struct load_command *lc;
480
for (j = 0; j < mh->ncmds; j++)
482
lc = (struct load_command*) (((unsigned long) mh) + offset);
483
if ((LC_LOAD_DYLIB == lc->cmd) || (LC_LOAD_WEAK_DYLIB == lc->cmd))
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);
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);
500
symbol = lt__image_symbol (mh1, symname, LT__SYMLOOKUP_OPTS);
506
offset += lc->cmdsize;