2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2009 Sam Lantinga
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "SDL_config.h"
24 #ifdef SDL_LOADSO_DLCOMPAT
26 /* Please note that dlcompat apparently ships in current Mac OS X versions
27 * as a system library that provides compatibility with the Unix "dlopen"
28 * interface. In order to allow SDL to work on older OS X releases and also
29 * not conflict with the system lib on newer versions, we include dlcompat
30 * in SDL and change the symbols to prevent symbol clash with any existing
31 * system libraries. --ryan.
34 /* here is the dlcompat license: */
37 Copyright (c) 2002 Jorge Acereda <jacereda@users.sourceforge.net> &
38 Peter O'Gorman <ogorman@users.sourceforge.net>
40 Portions may be copyright others, see the AUTHORS file included with this
43 Maintained by Peter O'Gorman <ogorman@users.sourceforge.net>
45 Bug Reports and other queries should go to <ogorman@users.sourceforge.net>
47 Permission is hereby granted, free of charge, to any person obtaining
48 a copy of this software and associated documentation files (the
49 "Software"), to deal in the Software without restriction, including
50 without limitation the rights to use, copy, modify, merge, publish,
51 distribute, sublicense, and/or sell copies of the Software, and to
52 permit persons to whom the Software is furnished to do so, subject to
53 the following conditions:
55 The above copyright notice and this permission notice shall be
56 included in all copies or substantial portions of the Software.
58 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
59 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
60 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
61 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
62 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
63 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
64 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
68 #include <sys/types.h>
72 #include <mach-o/dyld.h>
73 #include <mach-o/nlist.h>
74 #include <mach-o/getsect.h>
76 #include "SDL_stdinc.h"
78 /* Just playing to see if it would compile with the freebsd headers, it does,
79 * but because of the different values for RTLD_LOCAL etc, it would break binary
83 #define __BSD_VISIBLE 1
91 #if defined (__GNUC__) && __GNUC__ > 3
92 #define dl_restrict __restrict
100 * Structure filled in by dladdr().
102 typedef struct SDL_OSX_dl_info {
103 const char *dli_fname; /* Pathname of shared object */
104 void *dli_fbase; /* Base address of shared object */
105 const char *dli_sname; /* Name of nearest symbol */
106 void *dli_saddr; /* Address of nearest symbol */
109 static int SDL_OSX_dladdr(const void * dl_restrict, SDL_OSX_Dl_info * dl_restrict);
110 #endif /* ! _POSIX_SOURCE */
113 static int SDL_OSX_dlclose(void * handle);
114 static const char * SDL_OSX_dlerror(void);
115 static void * SDL_OSX_dlopen(const char *path, int mode);
116 static void * SDL_OSX_dlsym(void * dl_restrict handle, const char * dl_restrict symbol);
118 #define RTLD_LAZY 0x1
120 #define RTLD_LOCAL 0x4
121 #define RTLD_GLOBAL 0x8
123 #ifndef _POSIX_SOURCE
124 #define RTLD_NOLOAD 0x10
125 #define RTLD_NODELETE 0x80
128 * Special handle arguments for SDL_OSX_dlsym().
130 #define RTLD_NEXT ((void *) -1) /* Search subsequent objects. */
131 #define RTLD_DEFAULT ((void *) -2) /* Use default search algorithm. */
132 #endif /* ! _POSIX_SOURCE */
139 #define dl_restrict __restrict
141 /* This is not available on 10.1 */
142 #ifndef LC_LOAD_WEAK_DYLIB
143 #define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD)
146 /* With this stuff here, this thing may actually compile/run on 10.0 systems
147 * Not that I have a 10.0 system to test it on anylonger
150 #define LC_REQ_DYLD 0x80000000
152 #ifndef NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
153 #define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 0x4
155 #ifndef NSADDIMAGE_OPTION_RETURN_ON_ERROR
156 #define NSADDIMAGE_OPTION_RETURN_ON_ERROR 0x1
158 #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
159 #define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND 0x0
161 #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
162 #define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4
164 /* These symbols will be looked for in dyld */
165 static const struct mach_header *(*dyld_NSAddImage) (const char *, unsigned long) = 0;
166 static int (*dyld_NSIsSymbolNameDefinedInImage) (const struct mach_header *, const char *) = 0;
167 static NSSymbol(*dyld_NSLookupSymbolInImage)
168 (const struct mach_header *, const char *, unsigned long) = 0;
170 /* Define this to make dlcompat reuse data block. This way in theory we save
171 * a little bit of overhead. However we then couldn't correctly catch excess
172 * calls to SDL_OSX_dlclose(). Hence we don't use this feature
176 /* Size of the internal error message buffer (used by dlerror()) */
177 #define ERR_STR_LEN 251
179 /* Maximum number of search paths supported by getSearchPath */
180 #define MAX_SEARCH_PATHS 32
183 #define MAGIC_DYLIB_OFI ((NSObjectFileImage) 'DYOF')
184 #define MAGIC_DYLIB_MOD ((NSModule) 'DYMO')
187 #define DL_IN_LIST 0x01
190 static pthread_mutex_t dlcompat_mutex;
191 /* Our thread specific storage
193 static pthread_key_t dlerror_key;
198 unsigned char errset;
199 char errstr[ERR_STR_LEN];
202 /* This is our central data structure. Whenever a module is loaded via
203 * SDL_OSX_dlopen(), we create such a struct.
207 struct dlstatus *next; /* pointer to next element in the linked list */
209 const struct mach_header *lib;
210 int refs; /* reference count */
211 int mode; /* mode in which this module was loaded */
214 int flags; /* Any internal flags we may need */
217 /* Head node of the dlstatus list */
218 static struct dlstatus mainStatus = { 0, MAGIC_DYLIB_MOD, NULL, -1, RTLD_GLOBAL, 0, 0, 0 };
219 static struct dlstatus *stqueue = &mainStatus;
222 /* Storage for the last error message (used by dlerror()) */
223 /* static char err_str[ERR_STR_LEN]; */
224 /* static int err_filled = 0; */
226 /* Prototypes to internal functions */
227 static void debug(const char *fmt, ...);
228 static void error(const char *str, ...);
229 static const char *safegetenv(const char *s);
230 static const char *searchList(void);
231 static const char *getSearchPath(int i);
232 static const char *getFullPath(int i, const char *file);
233 static const struct stat *findFile(const char *file, const char **fullPath);
234 static int isValidStatus(struct dlstatus *status);
235 static inline int isFlagSet(int mode, int flag);
236 static struct dlstatus *lookupStatus(const struct stat *sbuf);
237 static void insertStatus(struct dlstatus *dls, const struct stat *sbuf);
238 static int promoteLocalToGlobal(struct dlstatus *dls);
239 static void *reference(struct dlstatus *dls, int mode);
240 static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError);
241 static struct dlstatus *allocStatus(void);
242 static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode);
243 static NSSymbol search_linked_libs(const struct mach_header *mh, const char *symbol);
244 static const char *get_lib_name(const struct mach_header *mh);
245 static const struct mach_header *get_mach_header_from_NSModule(NSModule mod);
246 static void dlcompat_init_func(void);
247 static inline void dlcompat_init_check(void);
248 static inline void dolock(void);
249 static inline void dounlock(void);
250 static void dlerrorfree(void *data);
251 static void resetdlerror(void);
252 static const struct mach_header *my_find_image(const char *name);
253 static const struct mach_header *image_for_address(const void *address);
254 static inline char *dyld_error_str(void);
257 /* Two Global Functions */
258 static void *dlsym_prepend_underscore(void *handle, const char *symbol);
259 static void *dlsym_auto_underscore(void *handle, const char *symbol);
261 /* And their _intern counterparts */
262 static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol);
263 static void *dlsym_auto_underscore_intern(void *handle, const char *symbol);
268 static void debug(const char *fmt, ...)
273 fprintf(stderr, "DLDEBUG: ");
274 vfprintf(stderr, fmt, arg);
275 fprintf(stderr, "\n");
281 static void error(const char *str, ...)
284 struct dlthread *tss;
287 tss = pthread_getspecific(dlerror_key);
288 err_str = tss->errstr;
289 SDL_strlcpy(err_str, "dlcompat: ", ERR_STR_LEN);
290 vsnprintf(err_str + 10, ERR_STR_LEN - 10, str, arg);
292 debug("ERROR: %s\n", err_str);
296 static void warning(const char *str)
299 fprintf(stderr, "WARNING: dlcompat: %s\n", str);
303 static const char *safegetenv(const char *s)
305 const char *ss = SDL_getenv(s);
309 /* because this is only used for debugging and error reporting functions, we
310 * don't really care about how elegant it is... it could use the load
311 * commands to find the install name of the library, but...
313 static const char *get_lib_name(const struct mach_header *mh)
315 unsigned long count = _dyld_image_count();
317 const char *val = NULL;
320 for (i = 0; i < count; i++)
322 if (mh == _dyld_get_image_header(i))
324 val = _dyld_get_image_name(i);
332 /* Returns the mach_header for the module bu going through all the loaded images
333 * and finding the one with the same name as the module. There really ought to be
334 * an api for doing this, would be faster, but there isn't one right now
336 static const struct mach_header *get_mach_header_from_NSModule(NSModule mod)
338 const char *mod_name = NSNameOfModule(mod);
339 const struct mach_header *mh = NULL;
340 unsigned long count = _dyld_image_count();
342 debug("Module name: %s", mod_name);
343 for (i = 0; i < count; i++)
345 if (!SDL_strcmp(mod_name, _dyld_get_image_name(i)))
347 mh = _dyld_get_image_header(i);
355 /* Compute and return a list of all directories that we should search when
356 * trying to locate a module. We first look at the values of LD_LIBRARY_PATH
357 * and DYLD_LIBRARY_PATH, and then finally fall back to looking into
358 * /usr/lib and /lib. Since both of the environments variables can contain a
359 * list of colon seperated paths, we simply concat them and the two other paths
360 * into one big string, which we then can easily parse.
361 * Splitting this string into the actual path list is done by getSearchPath()
363 static const char *searchList()
366 static char *buf=NULL;
367 const char *ldlp = safegetenv("LD_LIBRARY_PATH");
368 const char *dyldlp = safegetenv("DYLD_LIBRARY_PATH");
369 const char *stdpath = SDL_getenv("DYLD_FALLBACK_LIBRARY_PATH");
371 stdpath = "/usr/local/lib:/lib:/usr/lib";
374 buf_size = SDL_strlen(ldlp) + SDL_strlen(dyldlp) + SDL_strlen(stdpath) + 4;
375 buf = SDL_malloc(buf_size);
376 SDL_snprintf(buf, buf_size, "%s%s%s%s%s%c", dyldlp, (dyldlp[0] ? ":" : ""), ldlp, (ldlp[0] ? ":" : ""),
382 /* Returns the ith search path from the list as computed by searchList() */
383 static const char *getSearchPath(int i)
385 static const char *list = 0;
386 static char **path = (char **)0;
388 static int numsize = MAX_SEARCH_PATHS;
390 /* So we can call SDL_free() in the "destructor" we use i=-1 to return the alloc'd array */
393 return (const char*)path;
397 path = (char **)SDL_calloc(MAX_SEARCH_PATHS, sizeof(char **));
403 debug("Increasing size for long PATH");
404 tmp = (char **)SDL_calloc((MAX_SEARCH_PATHS + numsize), sizeof(char **));
407 SDL_memcpy(tmp, path, sizeof(char **) * numsize);
410 numsize += MAX_SEARCH_PATHS;
418 while (!path[i] && !end)
420 path[i] = strsep((char **)&list, ":");
429 static const char *getFullPath(int i, const char *file)
431 static char buf[PATH_MAX];
432 const char *path = getSearchPath(i);
435 SDL_snprintf(buf, PATH_MAX, "%s/%s", path, file);
437 return path ? buf : 0;
440 /* Given a file name, try to determine the full path for that file. Starts
441 * its search in the current directory, and then tries all paths in the
442 * search list in the order they are specified there.
444 static const struct stat *findFile(const char *file, const char **fullPath)
447 static struct stat sbuf;
449 debug("finding file %s", file);
451 if (0 == stat(file, &sbuf))
453 if (SDL_strchr(file, '/'))
454 return 0; /* If the path had a / we don't look in env var places */
457 fileName = (char *)file;
458 while ((*fullPath = getFullPath(i++, fileName)))
460 if (0 == stat(*fullPath, &sbuf))
467 /* Determine whether a given dlstatus is valid or not */
468 static int isValidStatus(struct dlstatus *status)
470 /* Walk the list to verify status is contained in it */
471 struct dlstatus *dls = stqueue;
472 while (dls && status != dls)
475 error("invalid handle");
476 else if ((dls->module == 0) || (dls->refs == 0))
477 error("handle to closed library");
483 static inline int isFlagSet(int mode, int flag)
485 return (mode & flag) == flag;
488 static struct dlstatus *lookupStatus(const struct stat *sbuf)
490 struct dlstatus *dls = stqueue;
491 debug("looking for status");
492 while (dls && ( /* isFlagSet(dls->mode, RTLD_UNSHARED) */ 0
493 || sbuf->st_dev != dls->device || sbuf->st_ino != dls->inode))
498 static void insertStatus(struct dlstatus *dls, const struct stat *sbuf)
500 debug("inserting status");
501 dls->inode = sbuf->st_ino;
502 dls->device = sbuf->st_dev;
505 if ((dls->flags & DL_IN_LIST) == 0)
509 dls->flags |= DL_IN_LIST;
513 static struct dlstatus *allocStatus()
515 struct dlstatus *dls;
518 while (dls && dls->module)
522 dls = SDL_calloc(sizeof(*dls),1);
526 static int promoteLocalToGlobal(struct dlstatus *dls)
528 static int (*p) (NSModule module) = 0;
531 _dyld_func_lookup("__dyld_NSMakePrivateModulePublic", (void **)&p);
532 return (dls->module == MAGIC_DYLIB_MOD) || (p && p(dls->module));
535 static void *reference(struct dlstatus *dls, int mode)
539 if (dls->module == MAGIC_DYLIB_MOD && isFlagSet(mode, RTLD_LOCAL))
541 warning("trying to open a .dylib with RTLD_LOCAL");
542 error("unable to open a .dylib with RTLD_LOCAL");
545 if (isFlagSet(mode, RTLD_GLOBAL) &&
546 !isFlagSet(dls->mode, RTLD_GLOBAL) && !promoteLocalToGlobal(dls))
548 error("unable to promote local module to global");
555 debug("reference called with NULL argument");
560 static const struct mach_header *my_find_image(const char *name)
562 const struct mach_header *mh = 0;
563 const char *id = NULL;
564 int i = _dyld_image_count();
566 mh = (struct mach_header *)
567 dyld_NSAddImage(name, NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED |
568 NSADDIMAGE_OPTION_RETURN_ON_ERROR);
571 for (j = 0; j < i; j++)
573 id = _dyld_get_image_name(j);
574 if (!SDL_strcmp(id, name))
576 mh = _dyld_get_image_header(j);
585 * dyld adds libraries by first adding the directly dependant libraries in link order, and
586 * then adding the dependencies for those libraries, so we should do the same... but we don't
587 * bother adding the extra dependencies, if the symbols are neither in the loaded image nor
588 * any of it's direct dependencies, then it probably isn't there.
590 static NSSymbol search_linked_libs(const struct mach_header * mh, const char *symbol)
593 struct load_command *lc = 0;
594 struct mach_header *wh;
596 if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
598 lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
599 for (n = 0; n < mh->ncmds; n++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
601 if ((LC_LOAD_DYLIB == lc->cmd) || (LC_LOAD_WEAK_DYLIB == lc->cmd))
603 if ((wh = (struct mach_header *)
604 my_find_image((char *)(((struct dylib_command *)lc)->dylib.name.offset +
607 if (dyld_NSIsSymbolNameDefinedInImage(wh, symbol))
609 nssym = dyld_NSLookupSymbolInImage(wh,
611 NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
612 NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
618 if ((!nssym) && NSIsSymbolNameDefined(symbol))
620 /* I've never seen this debug message...*/
621 debug("Symbol \"%s\" is defined but was not found", symbol);
627 /* Up to the caller to SDL_free() returned string */
628 static inline char *dyld_error_str()
630 NSLinkEditErrors dylder;
632 const char *dylderrstr;
633 const char *dyldfile;
635 NSLinkEditError(&dylder, &dylderno, &dyldfile, &dylderrstr);
636 if (dylderrstr && *dylderrstr)
638 retStr = SDL_strdup(dylderrstr);
643 static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError)
647 void *caller = __builtin_return_address(1); /* Be *very* careful about inlining */
651 const struct mach_header *caller_mh = 0;
652 char *savedErrorStr = NULL;
655 #define RTLD_SELF ((void *) -3)
659 if ((RTLD_NEXT == dls) || (RTLD_SELF == dls))
661 if (dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage && caller)
663 caller_mh = image_for_address(caller);
664 if (RTLD_SELF == dls)
666 /* FIXME: We should be using the NSModule api, if SELF is an MH_BUNDLE
667 * But it appears to work anyway, and looking at the code in dyld_libfuncs.c
668 * this is acceptable.
670 if (dyld_NSIsSymbolNameDefinedInImage(caller_mh, symbol))
672 nssym = dyld_NSLookupSymbolInImage(caller_mh,
674 NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
675 NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
680 if (RTLD_SELF == dls)
681 savedErrorStr = dyld_error_str();
682 nssym = search_linked_libs(caller_mh, symbol);
688 error("RTLD_SELF and RTLD_NEXT are not supported");
695 if (RTLD_DEFAULT == dls)
699 if (!isValidStatus(dls))
702 if (dls->module != MAGIC_DYLIB_MOD)
704 nssym = NSLookupSymbolInModule(dls->module, symbol);
705 if (!nssym && NSIsSymbolNameDefined(symbol))
707 debug("Searching dependencies");
708 savedErrorStr = dyld_error_str();
709 nssym = search_linked_libs(get_mach_header_from_NSModule(dls->module), symbol);
712 else if (dls->lib && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
714 if (dyld_NSIsSymbolNameDefinedInImage(dls->lib, symbol))
716 nssym = dyld_NSLookupSymbolInImage(dls->lib,
718 NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
719 NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
721 else if (NSIsSymbolNameDefined(symbol))
723 debug("Searching dependencies");
724 savedErrorStr = dyld_error_str();
725 nssym = search_linked_libs(dls->lib, symbol);
728 else if (dls->module == MAGIC_DYLIB_MOD)
730 /* Global context, use NSLookupAndBindSymbol */
731 if (NSIsSymbolNameDefined(symbol))
733 /* There doesn't seem to be a return on error option for this call???
734 this is potentially broken, if binding fails, it will improperly
735 exit the application. */
736 nssym = NSLookupAndBindSymbol(symbol);
741 SDL_free(savedErrorStr);
742 savedErrorStr = SDL_malloc(256);
743 SDL_snprintf(savedErrorStr, 256, "Symbol \"%s\" not in global context",symbol);
747 /* Error reporting */
750 if (!savedErrorStr || !SDL_strlen(savedErrorStr))
753 SDL_free(savedErrorStr);
754 savedErrorStr = SDL_malloc(256);
755 SDL_snprintf(savedErrorStr, 256,"Symbol \"%s\" not found",symbol);
759 error(savedErrorStr);
763 debug(savedErrorStr);
766 SDL_free(savedErrorStr);
769 return NSAddressOfSymbol(nssym);
772 static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode)
774 NSObjectFileImage ofi = 0;
775 NSObjectFileImageReturnCode ofirc;
776 struct dlstatus *dls;
777 NSLinkEditErrors ler;
783 ofirc = NSCreateObjectFileImageFromFile(path, &ofi);
786 case NSObjectFileImageSuccess:
788 case NSObjectFileImageInappropriateFile:
789 if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
791 if (isFlagSet(mode, RTLD_LOCAL))
793 warning("trying to open a .dylib with RTLD_LOCAL");
794 error("unable to open this file with RTLD_LOCAL");
800 error("opening this file is unsupported on this system");
804 case NSObjectFileImageFailure:
805 error("object file setup failure");
807 case NSObjectFileImageArch:
808 error("no object for this architecture");
810 case NSObjectFileImageFormat:
811 error("bad object file format");
813 case NSObjectFileImageAccess:
814 error("can't read object file");
817 error("unknown error from NSCreateObjectFileImageFromFile()");
820 dls = lookupStatus(sbuf);
827 error("unable to allocate memory");
831 if (ofirc == NSObjectFileImageInappropriateFile)
833 if ((dls->lib = dyld_NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR)))
835 debug("Dynamic lib loaded at %ld", dls->lib);
836 ofi = MAGIC_DYLIB_OFI;
837 dls->module = MAGIC_DYLIB_MOD;
838 ofirc = NSObjectFileImageSuccess;
839 /* Although it is possible with a bit of work to modify this so it works and
840 functions with RTLD_NOW, I don't deem it necessary at the moment */
844 NSLinkEditError(&ler, &lerno, &file, &errstr);
845 if (!errstr || (!SDL_strlen(errstr)))
846 error("Can't open this file type");
849 if ((dls->flags & DL_IN_LIST) == 0)
858 dls->module = NSLinkModule(ofi, path,
859 NSLINKMODULE_OPTION_RETURN_ON_ERROR |
860 NSLINKMODULE_OPTION_PRIVATE |
861 (isFlagSet(mode, RTLD_NOW) ? NSLINKMODULE_OPTION_BINDNOW : 0));
862 NSDestroyObjectFileImage(ofi);
865 dls->lib = get_mach_header_from_NSModule(dls->module);
870 NSLinkEditError(&ler, &lerno, &file, &errstr);
871 if ((dls->flags & DL_IN_LIST) == 0)
879 insertStatus(dls, sbuf);
880 dls = reference(dls, mode);
881 if ((init = dlsymIntern(dls, "__init", 0)))
883 debug("calling _init()");
889 inline static void dlcompat_init_check(void)
891 static pthread_mutex_t l = PTHREAD_MUTEX_INITIALIZER;
892 static int init_done = 0;
894 pthread_mutex_lock(&l);
896 dlcompat_init_func();
899 pthread_mutex_unlock(&l);
902 static void dlcompat_init_func(void)
904 _dyld_func_lookup("__dyld_NSAddImage", (void **)&dyld_NSAddImage);
905 _dyld_func_lookup("__dyld_NSIsSymbolNameDefinedInImage",
906 (void **)&dyld_NSIsSymbolNameDefinedInImage);
907 _dyld_func_lookup("__dyld_NSLookupSymbolInImage", (void **)&dyld_NSLookupSymbolInImage);
908 if (pthread_mutex_init(&dlcompat_mutex, NULL))
910 if (pthread_key_create(&dlerror_key, &dlerrorfree))
914 static void resetdlerror()
916 struct dlthread *tss;
917 tss = pthread_getspecific(dlerror_key);
921 static void dlerrorfree(void *data)
926 /* We kind of want a recursive lock here, but meet a little trouble
927 * because they are not available pre OS X 10.2, so we fake it
928 * using thread specific storage to keep a lock count
930 static inline void dolock(void)
933 struct dlthread *tss;
934 dlcompat_init_check();
935 tss = pthread_getspecific(dlerror_key);
938 tss = SDL_malloc(sizeof(struct dlthread));
941 if (pthread_setspecific(dlerror_key, tss))
943 fprintf(stderr,"dlcompat: pthread_setspecific failed\n");
948 err = pthread_mutex_lock(&dlcompat_mutex);
949 tss->lockcnt = tss->lockcnt +1;
954 static inline void dounlock(void)
957 struct dlthread *tss;
958 tss = pthread_getspecific(dlerror_key);
959 tss->lockcnt = tss->lockcnt -1;
961 err = pthread_mutex_unlock(&dlcompat_mutex);
966 static void *SDL_OSX_dlopen(const char *path, int mode)
968 const struct stat *sbuf;
969 struct dlstatus *dls;
970 const char *fullPath;
979 if (!(sbuf = findFile(path, &fullPath)))
981 error("file \"%s\" not found", path);
984 /* Now checks that it hasn't been closed already */
985 if ((dls = lookupStatus(sbuf)) && (dls->refs > 0))
987 /* debug("status found"); */
988 dls = reference(dls, mode);
992 if (isFlagSet(mode, RTLD_NOLOAD))
994 error("no existing handle and RTLD_NOLOAD specified");
998 if (isFlagSet(mode, RTLD_LAZY) && isFlagSet(mode, RTLD_NOW))
1000 error("how can I load something both RTLD_LAZY and RTLD_NOW?");
1003 dls = loadModule(fullPath, sbuf, mode);
1014 static void *SDL_OSX_dlsym(void * dl_restrict handle, const char * dl_restrict symbol)
1016 int sym_len = SDL_strlen(symbol);
1018 char *malloc_sym = NULL;
1020 malloc_sym = SDL_malloc(sym_len + 2);
1023 SDL_snprintf(malloc_sym, sym_len+2, "_%s", symbol);
1024 value = dlsymIntern(handle, malloc_sym, 1);
1025 SDL_free(malloc_sym);
1029 error("Unable to allocate memory");
1042 static void *dlsym_prepend_underscore(void *handle, const char *symbol)
1046 answer = dlsym_prepend_underscore_intern(handle, symbol);
1051 static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol)
1054 * A quick and easy way for porting packages which call dlsym(handle,"sym")
1055 * If the porter adds -Ddlsym=dlsym_prepend_underscore to the CFLAGS then
1056 * this function will be called, and will add the required underscore.
1058 * Note that I haven't figured out yet which should be "standard", prepend
1059 * the underscore always, or not at all. These global functions need to go away
1062 int sym_len = SDL_strlen(symbol);
1064 char *malloc_sym = NULL;
1065 malloc_sym = SDL_malloc(sym_len + 2);
1068 SDL_snprintf(malloc_sym, sym_len+2, "_%s", symbol);
1069 value = dlsymIntern(handle, malloc_sym, 1);
1070 SDL_free(malloc_sym);
1074 error("Unable to allocate memory");
1079 static void *dlsym_auto_underscore(void *handle, const char *symbol)
1083 answer = dlsym_auto_underscore_intern(handle, symbol);
1088 static void *dlsym_auto_underscore_intern(void *handle, const char *symbol)
1090 struct dlstatus *dls = handle;
1092 addr = dlsymIntern(dls, symbol, 0);
1094 addr = dlsym_prepend_underscore_intern(handle, symbol);
1099 static void *SDL_OSX_dlsym(void * dl_restrict handle, const char * dl_restrict symbol)
1101 struct dlstatus *dls = handle;
1104 addr = dlsymIntern(dls, symbol, 1);
1110 static int SDL_OSX_dlclose(void *handle)
1112 struct dlstatus *dls = handle;
1115 if (!isValidStatus(dls))
1119 if (dls->module == MAGIC_DYLIB_MOD)
1124 name = "global context";
1128 name = get_lib_name(dls->lib);
1130 warning("trying to close a .dylib!");
1131 error("Not closing \"%s\" - dynamic libraries cannot be closed", name);
1136 error("module already closed");
1142 unsigned long options = 0;
1143 void (*fini) (void);
1144 if ((fini = dlsymIntern(dls, "__fini", 0)))
1146 debug("calling _fini()");
1149 options |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;
1150 #ifdef RTLD_NODELETE
1151 if (isFlagSet(dls->mode, RTLD_NODELETE))
1152 options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
1154 if (!NSUnLinkModule(dls->module, options))
1156 error("unable to unlink module");
1161 /* Note: the dlstatus struct dls is neither removed from the list
1162 * nor is the memory it occupies freed. This shouldn't pose a
1163 * problem in mostly all cases, though.
1173 static const char *SDL_OSX_dlerror(void)
1175 struct dlthread *tss;
1176 const char * err_str = NULL;
1177 dlcompat_init_check();
1178 tss = pthread_getspecific(dlerror_key);
1179 if (tss != NULL && tss->errset != 0) {
1181 err_str = tss->errstr;
1186 /* Given an address, return the mach_header for the image containing it
1187 * or zero if the given address is not contained in any loaded images.
1189 static const struct mach_header *image_for_address(const void *address)
1193 unsigned long count = _dyld_image_count();
1194 const struct mach_header *mh = 0;
1195 struct load_command *lc = 0;
1196 unsigned long addr = 0;
1197 for (i = 0; i < count; i++)
1199 addr = (unsigned long)address - _dyld_get_image_vmaddr_slide(i);
1200 mh = _dyld_get_image_header(i);
1203 lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
1204 for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
1206 if (LC_SEGMENT == lc->cmd &&
1207 addr >= ((struct segment_command *)lc)->vmaddr &&
1209 ((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize)
1222 static int SDL_OSX_dladdr(const void * dl_restrict p, SDL_OSX_Dl_info * dl_restrict info)
1225 FIXME: USe the routine image_for_address.
1229 unsigned long count = _dyld_image_count();
1230 struct mach_header *mh = 0;
1231 struct load_command *lc = 0;
1232 unsigned long addr = NULL;
1233 unsigned long table_off = (unsigned long)0;
1239 info->dli_fname = 0;
1240 info->dli_fbase = 0;
1241 info->dli_sname = 0;
1242 info->dli_saddr = 0;
1243 /* Some of this was swiped from code posted by Douglas Davidson <ddavidso AT apple DOT com>
1244 * to darwin-development AT lists DOT apple DOT com and slightly modified
1246 for (i = 0; i < count; i++)
1248 addr = (unsigned long)p - _dyld_get_image_vmaddr_slide(i);
1249 mh = _dyld_get_image_header(i);
1252 lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
1253 for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
1255 if (LC_SEGMENT == lc->cmd &&
1256 addr >= ((struct segment_command *)lc)->vmaddr &&
1258 ((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize)
1260 info->dli_fname = _dyld_get_image_name(i);
1261 info->dli_fbase = (void *)mh;
1275 lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
1276 for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
1278 if (LC_SEGMENT == lc->cmd)
1280 if (!SDL_strcmp(((struct segment_command *)lc)->segname, "__LINKEDIT"))
1285 ((unsigned long)((struct segment_command *)lc)->vmaddr) -
1286 ((unsigned long)((struct segment_command *)lc)->fileoff) + _dyld_get_image_vmaddr_slide(i);
1287 debug("table off %x", table_off);
1289 lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
1290 for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
1292 if (LC_SYMTAB == lc->cmd)
1295 struct nlist *symtable = (struct nlist *)(((struct symtab_command *)lc)->symoff + table_off);
1296 unsigned long numsyms = ((struct symtab_command *)lc)->nsyms;
1297 struct nlist *nearest = NULL;
1298 unsigned long diff = 0xffffffff;
1299 unsigned long strtable = (unsigned long)(((struct symtab_command *)lc)->stroff + table_off);
1300 debug("symtable %x", symtable);
1301 for (i = 0; i < numsyms; i++)
1303 /* Ignore the following kinds of Symbols */
1304 if ((!symtable->n_value) /* Undefined */
1305 || (symtable->n_type >= N_PEXT) /* Debug symbol */
1306 || (!(symtable->n_type & N_EXT)) /* Local Symbol */
1312 if ((addr >= symtable->n_value) && (diff >= (symtable->n_value - addr)))
1314 diff = (unsigned long)symtable->n_value - addr;
1321 info->dli_saddr = nearest->n_value + ((void *)p - addr);
1322 info->dli_sname = (char *)(strtable + nearest->n_un.n_strx);
1332 * Implement the dlfunc() interface, which behaves exactly the same as
1333 * dlsym() except that it returns a function pointer instead of a data
1334 * pointer. This can be used by applications to avoid compiler warnings
1335 * about undefined behavior, and is intended as prior art for future
1336 * POSIX standardization. This function requires that all pointer types
1337 * have the same representation, which is true on all platforms FreeBSD
1338 * runs on, but is not guaranteed by the C standard.
1341 static dlfunc_t SDL_OSX_dlfunc(void * dl_restrict handle, const char * dl_restrict symbol)
1348 int sym_len = SDL_strlen(symbol);
1349 char *malloc_sym = NULL;
1351 malloc_sym = SDL_malloc(sym_len + 2);
1354 SDL_snprintf(malloc_sym, sym_len+2, "_%s", symbol);
1355 rv.d = dlsymIntern(handle, malloc_sym, 1);
1356 SDL_free(malloc_sym);
1360 error("Unable to allocate memory");
1373 /* dlcompat ends, here's the SDL interface... --ryan. */
1376 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1377 /* System dependent library loading routines */
1379 #include "SDL_loadso.h"
1381 void *SDL_LoadObject(const char *sofile)
1383 void *handle = SDL_OSX_dlopen(sofile, RTLD_NOW);
1384 const char *loaderror = SDL_OSX_dlerror();
1385 if ( handle == NULL ) {
1386 SDL_SetError("Failed loading %s: %s", sofile, loaderror);
1391 void *SDL_LoadFunction(void *handle, const char *name)
1393 void *symbol = SDL_OSX_dlsym(handle, name);
1394 if ( symbol == NULL ) {
1395 SDL_SetError("Failed loading %s: %s", name, SDL_OSX_dlerror());
1400 void SDL_UnloadObject(void *handle)
1402 if ( handle != NULL ) {
1403 SDL_OSX_dlclose(handle);
1407 #endif /* SDL_LOADSO_DLCOMPAT */