Imported Upstream version 0.63.0
[hcoop/debian/courier-authlib.git] / libltdl / loaders / dyld.c
CommitLineData
8d138742
CE
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
10GNU Libltdl is free software; you can redistribute it and/or
11modify it under the terms of the GNU Lesser General Public
12License as published by the Free Software Foundation; either
13version 2 of the License, or (at your option) any later version.
14
15As a special exception to the GNU Lesser General Public License,
16if you distribute this file as part of a program or library that
17is built using GNU Libtool, you may include this file under the
18same distribution terms that you use for the rest of that program.
19
20GNU Libltdl is distributed in the hope that it will be useful,
21but WITHOUT ANY WARRANTY; without even the implied warranty of
22MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23GNU Lesser General Public License for more details.
24
25You should have received a copy of the GNU Lesser General Public
26License along with GNU Libltdl; see the file COPYING.LIB. If not, a
27copy can be downloaded from http://www.gnu.org/licenses/lgpl.html,
28or obtained by writing to the Free Software Foundation, Inc.,
2951 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
41LT_BEGIN_C_DECLS
42LT_SCOPE lt_dlvtable *get_vtable (lt_user_data loader_data);
43LT_END_C_DECLS
44
45
46/* Boilerplate code to set up the vtable for hooking this loader into
47 libltdl's loader list: */
48static int vl_init (lt_user_data loader_data);
49static int vl_exit (lt_user_data loader_data);
50static lt_module vm_open (lt_user_data loader_data, const char *filename,
51 lt_dladvise advise);
52static int vm_close (lt_user_data loader_data, lt_module module);
53static void * vm_sym (lt_user_data loader_data, lt_module module,
54 const char *symbolname);
55
56static 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. */
61lt_dlvtable *
62get_vtable (lt_user_data loader_data)
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
164typedef struct mach_header mach_header;
165typedef struct dylib_command dylib_command;
166
167static const char *dylderror (const char *errmsg);
168static const mach_header *lt__nsmodule_get_header (NSModule module);
169static const char *lt__header_get_instnam (const mach_header *mh);
170static const mach_header *lt__match_loadedlib (const char *name);
171static NSSymbol lt__linkedlib_symbol (const char *symname, const mach_header *mh);
172
173static const mach_header *(*lt__addimage) (const char *image_name,
174 unsigned long options) = 0;
175static NSSymbol (*lt__image_symbol) (const mach_header *image,
176 const char *symbolName,
177 unsigned long options) = 0;
178static enum DYLD_BOOL (*lt__image_symbol_p) (const mach_header *image,
179 const char *symbolName) = 0;
180static enum DYLD_BOOL (*lt__module_export) (NSModule module) = 0;
181
182static 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. */
187static int
188vl_exit (lt_user_data LT__UNUSED loader_data)
189{
190 vtable = NULL;
191 return 0;
192}
193
194/* A function called through the vtable to initialise this loader. */
195static int
196vl_init (lt_user_data loader_data)
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. */
227static lt_module
228vm_open (lt_user_data loader_data, const char *filename,
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. */
280static int
281vm_close (lt_user_data loader_data, lt_module module)
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. */
321static void *
322vm_sym (lt_user_data loader_data, lt_module module, const char *name)
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. */
377static const char *
378dylderror (const char *errmsg)
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. */
396static const mach_header *
397lt__nsmodule_get_header (NSModule module)
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. */
423static const char *
424lt__header_get_instnam (const mach_header *mh)
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
446static const mach_header *
447lt__match_loadedlib (const char *name)
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. */
469static NSSymbol
470lt__linkedlib_symbol (const char *symname, const mach_header *mh)
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}