2 * This file was modified by Christoph Pfisterer <cp@chrisp.de>
3 * on Tue, Jan 23 2001. See the file "ChangeLog" for details of what
7 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
9 * @APPLE_LICENSE_HEADER_START@
11 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
12 * Reserved. This file contains Original Code and/or Modifications of
13 * Original Code as defined in and that are subject to the Apple Public
14 * Source License Version 1.1 (the "License"). You may not use this file
15 * except in compliance with the License. Please obtain a copy of the
16 * License at http://www.apple.com/publicsource and read it before using
19 * The Original Code and all software distributed under the License are
20 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
21 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
22 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
24 * License for the specific language governing rights and limitations
27 * @APPLE_LICENSE_HEADER_END@
33 #include <sys/types.h>
36 #include "mach-o/dyld.h"
43 #define DEBUG_PRINT(format) fprintf(stderr,(format));fflush(stderr)
44 #define DEBUG_PRINT1(format,arg1) fprintf(stderr,(format),(arg1));\
46 #define DEBUG_PRINT2(format,arg1,arg2) fprintf(stderr,(format),\
47 (arg1),(arg2));fflush(stderr)
48 #define DEBUG_PRINT3(format,arg1,arg2,arg3) fprintf(stderr,(format),\
49 (arg1),(arg2),(arg3));fflush(stderr)
51 #define DEBUG_PRINT(format) /**/
52 #define DEBUG_PRINT1(format,arg1) /**/
53 #define DEBUG_PRINT2(format,arg1,arg2) /**/
54 #define DEBUG_PRINT3(format,arg1,arg2,arg3) /**/
59 * The structure of a dlopen() handle.
61 struct dlopen_handle {
62 dev_t dev; /* the path's device and inode number from stat(2) */
64 int dlopen_mode; /* current dlopen mode for this handle */
65 int dlopen_count; /* number of times dlopen() called on this handle */
66 NSModule module; /* the NSModule returned by NSLinkModule() */
67 struct dlopen_handle *prev;
68 struct dlopen_handle *next;
70 static struct dlopen_handle *dlopen_handles = NULL;
71 static const struct dlopen_handle main_program_handle = {NULL};
72 static char *dlerror_pointer = NULL;
75 * NSMakePrivateModulePublic() is not part of the public dyld API so we define
76 * it here. The internal dyld function pointer for
77 * __dyld_NSMakePrivateModulePublic is returned so thats all that maters to get
78 * the functionality need to implement the dlopen() interfaces.
82 NSMakePrivateModulePublic(
85 static int (*p)(NSModule module) = NULL;
88 _dyld_func_lookup("__dyld_NSMakePrivateModulePublic",
92 printf("_dyld_func_lookup of __dyld_NSMakePrivateModulePublic "
101 * helper routine: search for a named module in various locations
106 const char *filename,
108 struct stat *stat_buf)
110 const char *pathspec;
115 const char *envvars[] = {
116 "$DYLD_LIBRARY_PATH",
122 pathbuf_end = pathbuf + PATH_MAX - 8;
124 for(envvar_index = 0; envvars[envvar_index]; envvar_index++){
125 if(envvars[envvar_index][0] == '$'){
126 pathspec = getenv(envvars[envvar_index]+1);
129 pathspec = envvars[envvar_index];
132 if(pathspec != NULL){
135 /* extract path list element */
138 while(*p && *p != ':' && q < pathbuf_end)
140 if(q == pathbuf){ /* empty element */
151 element = p; /* this terminates the loop */
154 /* add slash if neccessary */
155 if(*(q-1) != '/' && q < pathbuf_end){
159 /* append module name */
161 while(*p && q < pathbuf_end) *q++ = *p++;
164 if(q >= pathbuf_end){
165 /* maybe add an error message here */
169 if(stat(pathbuf, stat_buf) == 0){
176 /* we have searched everywhere, now we give up */
181 * dlopen() the MacOS X version of the FreeBSD dlopen() interface.
188 const char *module_path;
190 struct stat stat_buf;
191 NSObjectFileImage objectFileImage;
192 NSObjectFileImageReturnCode ofile_result_code;
194 struct dlopen_handle *p;
195 unsigned long options;
198 char pathbuf[PATH_MAX];
200 DEBUG_PRINT2("libdl: dlopen(%s,0x%x) -> ", path, (unsigned int)mode);
202 dlerror_pointer = NULL;
204 * A NULL path is to indicate the caller wants a handle for the
208 retval = (void *)&main_program_handle;
209 DEBUG_PRINT1("main / %p\n", retval);
213 /* see if the path exists and if so get the device and inode number */
214 if(stat(path, &stat_buf) == -1){
215 dlerror_pointer = strerror(errno);
218 DEBUG_PRINT1("ERROR (stat): %s\n", dlerror_pointer);
222 /* search for the module in various places */
223 if(_dl_search_paths(path, pathbuf, &stat_buf)){
224 /* dlerror_pointer is unmodified */
225 DEBUG_PRINT1("ERROR (stat): %s\n", dlerror_pointer);
228 DEBUG_PRINT1("found %s -> ", pathbuf);
229 module_path = pathbuf;
230 dlerror_pointer = NULL;
237 * If we don't want an unshared handle see if we already have a handle
240 if((mode & RTLD_UNSHARED) != RTLD_UNSHARED){
243 if(p->dev == stat_buf.st_dev && p->ino == stat_buf.st_ino){
244 /* skip unshared handles */
245 if((p->dlopen_mode & RTLD_UNSHARED) == RTLD_UNSHARED)
248 * We have already created a handle for this path. The
249 * caller might be trying to promote an RTLD_LOCAL handle
250 * to a RTLD_GLOBAL. Or just looking it up with
253 if((p->dlopen_mode & RTLD_LOCAL) == RTLD_LOCAL &&
254 (mode & RTLD_GLOBAL) == RTLD_GLOBAL){
255 /* promote the handle */
256 if(NSMakePrivateModulePublic(p->module) == TRUE){
257 p->dlopen_mode &= ~RTLD_LOCAL;
258 p->dlopen_mode |= RTLD_GLOBAL;
260 DEBUG_PRINT1("%p\n", p);
264 dlerror_pointer = "can't promote handle from "
265 "RTLD_LOCAL to RTLD_GLOBAL";
266 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
271 DEBUG_PRINT1("%p\n", p);
279 * We do not have a handle for this path if we were just trying to
280 * look it up return NULL to indicate we don't have it.
282 if((mode & RTLD_NOLOAD) == RTLD_NOLOAD){
283 dlerror_pointer = "no existing handle for path RTLD_NOLOAD test";
284 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
288 /* try to create an object file image from this path */
289 ofile_result_code = NSCreateObjectFileImageFromFile(module_path,
291 if(ofile_result_code != NSObjectFileImageSuccess){
292 switch(ofile_result_code){
293 case NSObjectFileImageFailure:
294 dlerror_pointer = "object file setup failure";
295 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
297 case NSObjectFileImageInappropriateFile:
298 dlerror_pointer = "not a Mach-O MH_BUNDLE file type";
299 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
301 case NSObjectFileImageArch:
302 dlerror_pointer = "no object for this architecture";
303 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
305 case NSObjectFileImageFormat:
306 dlerror_pointer = "bad object file format";
307 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
309 case NSObjectFileImageAccess:
310 dlerror_pointer = "can't read object file";
311 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
314 dlerror_pointer = "unknown error from "
315 "NSCreateObjectFileImageFromFile()";
316 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
321 /* try to link in this object file image */
322 options = NSLINKMODULE_OPTION_PRIVATE;
323 if((mode & RTLD_NOW) == RTLD_NOW)
324 options |= NSLINKMODULE_OPTION_BINDNOW;
325 module = NSLinkModule(objectFileImage, module_path, options);
326 NSDestroyObjectFileImage(objectFileImage) ;
328 dlerror_pointer = "NSLinkModule() failed for dlopen()";
329 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
334 * If the handle is to be global promote the handle. It is done this
335 * way to avoid multiply defined symbols.
337 if((mode & RTLD_GLOBAL) == RTLD_GLOBAL){
338 if(NSMakePrivateModulePublic(module) == FALSE){
339 dlerror_pointer = "can't promote handle from RTLD_LOCAL to "
341 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
346 p = malloc(sizeof(struct dlopen_handle));
348 dlerror_pointer = "can't allocate memory for the dlopen handle";
349 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
353 /* fill in the handle */
354 p->dev = stat_buf.st_dev;
355 p->ino = stat_buf.st_ino;
356 if(mode & RTLD_GLOBAL)
357 p->dlopen_mode = RTLD_GLOBAL;
359 p->dlopen_mode = RTLD_LOCAL;
360 p->dlopen_mode |= (mode & RTLD_UNSHARED) |
361 (mode & RTLD_NODELETE) |
362 (mode & RTLD_LAZY_UNDEF);
366 p->next = dlopen_handles;
367 if(dlopen_handles != NULL)
368 dlopen_handles->prev = p;
371 /* call the init function if one exists */
372 NSSymbol = NSLookupSymbolInModule(p->module, "__init");
373 if(NSSymbol != NULL){
374 init = NSAddressOfSymbol(NSSymbol);
378 DEBUG_PRINT1("%p\n", p);
383 * dlsym() the MacOS X version of the FreeBSD dlopen() interface.
390 struct dlopen_handle *dlopen_handle, *p;
394 DEBUG_PRINT2("libdl: dlsym(%p,%s) -> ", handle, symbol);
396 dlopen_handle = (struct dlopen_handle *)handle;
399 * If this is the handle for the main program do a global lookup.
401 if(dlopen_handle == (struct dlopen_handle *)&main_program_handle){
402 if(NSIsSymbolNameDefined(symbol) == TRUE){
403 NSSymbol = NSLookupAndBindSymbol(symbol);
404 address = NSAddressOfSymbol(NSSymbol);
405 dlerror_pointer = NULL;
406 DEBUG_PRINT1("%p\n", address);
410 dlerror_pointer = "symbol not found";
411 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
417 * Find this handle and do a lookup in just this module.
421 if(dlopen_handle == p){
422 NSSymbol = NSLookupSymbolInModule(p->module, symbol);
423 if(NSSymbol != NULL){
424 address = NSAddressOfSymbol(NSSymbol);
425 dlerror_pointer = NULL;
426 DEBUG_PRINT1("%p\n", address);
430 dlerror_pointer = "symbol not found";
431 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
438 dlerror_pointer = "bad handle passed to dlsym()";
439 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
444 * dlerror() the MacOS X version of the FreeBSD dlopen() interface.
452 p = (const char *)dlerror_pointer;
453 dlerror_pointer = NULL;
458 * dlclose() the MacOS X version of the FreeBSD dlopen() interface.
464 struct dlopen_handle *p, *q;
465 unsigned long options;
469 DEBUG_PRINT1("libdl: dlclose(%p) -> ", handle);
471 dlerror_pointer = NULL;
472 q = (struct dlopen_handle *)handle;
476 /* if the dlopen() count is not zero we are done */
478 if(p->dlopen_count != 0){
483 /* call the fini function if one exists */
484 NSSymbol = NSLookupSymbolInModule(p->module, "__fini");
485 if(NSSymbol != NULL){
486 fini = NSAddressOfSymbol(NSSymbol);
490 /* unlink the module for this handle */
492 if(p->dlopen_mode & RTLD_NODELETE)
493 options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
494 if(p->dlopen_mode & RTLD_LAZY_UNDEF)
495 options |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;
496 if(NSUnLinkModule(p->module, options) == FALSE){
497 dlerror_pointer = "NSUnLinkModule() failed for dlclose()";
498 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
502 p->prev->next = p->next;
504 p->next->prev = p->prev;
505 if(dlopen_handles == p)
506 dlopen_handles = p->next;
513 dlerror_pointer = "invalid handle passed to dlclose()";
514 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);