src/loadso/macosx/SDL_loadso.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 17 Nov 2005 03:15:05 +0000
changeset 1173 e9cf8c1b4590
child 1190 173c063d4f55
permissions -rw-r--r--
Split up src/SDL_loadso.c into platform directories.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2004 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 of the License, or (at your option) any later version.
     9 
    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     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 
    23 #ifdef SAVE_RCSID
    24 static char rcsid =
    25  "@(#) $Id$";
    26 #endif
    27 
    28 /* Please note that dlcompat apparently ships in current Mac OS X versions
    29  *  as a system library that provides compatibility with the Unix "dlopen"
    30  *  interface. In order to allow SDL to work on older OS X releases and also
    31  *  not conflict with the system lib on newer versions, we include dlcompat
    32  *  in SDL and change the symbols to prevent symbol clash with any existing
    33  *  system libraries.  --ryan.
    34  */
    35 
    36 /* here is the dlcompat license: */
    37 
    38 /*
    39 Copyright (c) 2002 Jorge Acereda  <jacereda@users.sourceforge.net> &
    40                    Peter O'Gorman <ogorman@users.sourceforge.net>
    41                    
    42 Portions may be copyright others, see the AUTHORS file included with this
    43 distribution.
    44 
    45 Maintained by Peter O'Gorman <ogorman@users.sourceforge.net>
    46 
    47 Bug Reports and other queries should go to <ogorman@users.sourceforge.net>
    48 
    49 Permission is hereby granted, free of charge, to any person obtaining
    50 a copy of this software and associated documentation files (the
    51 "Software"), to deal in the Software without restriction, including
    52 without limitation the rights to use, copy, modify, merge, publish,
    53 distribute, sublicense, and/or sell copies of the Software, and to
    54 permit persons to whom the Software is furnished to do so, subject to
    55 the following conditions:
    56 
    57 The above copyright notice and this permission notice shall be
    58 included in all copies or substantial portions of the Software.
    59 
    60 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    61 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    62 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    63 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    64 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    65 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    66 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    67 */
    68 
    69 #include <pthread.h>
    70 #include <stdio.h>
    71 #include <stdlib.h>
    72 #include <string.h>
    73 #include <sys/types.h>
    74 #include <sys/stat.h>
    75 #include <stdarg.h>
    76 #include <limits.h>
    77 #include <mach-o/dyld.h>
    78 #include <mach-o/nlist.h>
    79 #include <mach-o/getsect.h>
    80 
    81 /* Just playing to see if it would compile with the freebsd headers, it does,
    82  * but because of the different values for RTLD_LOCAL etc, it would break binary
    83  * compat... oh well
    84  */
    85 #ifndef __BSD_VISIBLE
    86 #define __BSD_VISIBLE 1
    87 #endif
    88 
    89 /*include "dlfcn.h"*/
    90 #ifdef __cplusplus
    91 extern "C" {
    92 #endif
    93 
    94 #if defined (__GNUC__) && __GNUC__ > 3
    95 #define dl_restrict __restrict
    96 #else
    97 #define dl_restrict
    98 #endif
    99 
   100 #ifndef _POSIX_SOURCE
   101 /*
   102  * Structure filled in by dladdr().
   103  */
   104 typedef struct SDL_OSX_dl_info {
   105         const char      *dli_fname;     /* Pathname of shared object */
   106         void            *dli_fbase;     /* Base address of shared object */
   107         const char      *dli_sname;     /* Name of nearest symbol */
   108         void            *dli_saddr;     /* Address of nearest symbol */
   109 } SDL_OSX_Dl_info;
   110 
   111 static int SDL_OSX_dladdr(const void * dl_restrict, SDL_OSX_Dl_info * dl_restrict);
   112 #endif /* ! _POSIX_SOURCE */
   113 
   114 static int SDL_OSX_dlclose(void * handle);
   115 static char * SDL_OSX_dlerror(void);
   116 static void * SDL_OSX_dlopen(const char *path, int mode);
   117 static void * SDL_OSX_dlsym(void * dl_restrict handle, const char * dl_restrict symbol);
   118 
   119 #define RTLD_LAZY	0x1
   120 #define RTLD_NOW	0x2
   121 #define RTLD_LOCAL	0x4
   122 #define RTLD_GLOBAL	0x8
   123 
   124 #ifndef _POSIX_SOURCE
   125 #define RTLD_NOLOAD	0x10
   126 #define RTLD_NODELETE	0x80
   127 
   128 /*
   129  * Special handle arguments for SDL_OSX_dlsym().
   130  */
   131 #define	RTLD_NEXT		((void *) -1)	/* Search subsequent objects. */
   132 #define	RTLD_DEFAULT	((void *) -2)	/* Use default search algorithm. */
   133 #endif /* ! _POSIX_SOURCE */
   134 
   135 #ifdef __cplusplus
   136 }
   137 #endif
   138 
   139 #ifndef dl_restrict
   140 #define dl_restrict __restrict
   141 #endif
   142 /* This is not available on 10.1 */
   143 #ifndef LC_LOAD_WEAK_DYLIB
   144 #define	LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD)
   145 #endif
   146 
   147 /* With this stuff here, this thing may actually compile/run on 10.0 systems
   148  * Not that I have a 10.0 system to test it on anylonger
   149  */
   150 #ifndef LC_REQ_DYLD
   151 #define LC_REQ_DYLD 0x80000000
   152 #endif
   153 #ifndef NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
   154 #define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 0x4
   155 #endif
   156 #ifndef NSADDIMAGE_OPTION_RETURN_ON_ERROR
   157 #define NSADDIMAGE_OPTION_RETURN_ON_ERROR 0x1
   158 #endif
   159 #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
   160 #define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND 0x0
   161 #endif
   162 #ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
   163 #define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4
   164 #endif
   165 /* These symbols will be looked for in dyld */
   166 static const struct mach_header *(*dyld_NSAddImage) (const char *, unsigned long) = 0;
   167 static int (*dyld_NSIsSymbolNameDefinedInImage) (const struct mach_header *, const char *) = 0;
   168 static NSSymbol(*dyld_NSLookupSymbolInImage)
   169 	(const struct mach_header *, const char *, unsigned long) = 0;
   170 
   171 /* Define this to make dlcompat reuse data block. This way in theory we save
   172  * a little bit of overhead. However we then couldn't correctly catch excess
   173  * calls to SDL_OSX_dlclose(). Hence we don't use this feature
   174  */
   175 #undef REUSE_STATUS
   176 
   177 /* Size of the internal error message buffer (used by dlerror()) */
   178 #define ERR_STR_LEN			251
   179 
   180 /* Maximum number of search paths supported by getSearchPath */
   181 #define MAX_SEARCH_PATHS	32
   182 
   183 
   184 #define MAGIC_DYLIB_OFI ((NSObjectFileImage) 'DYOF')
   185 #define MAGIC_DYLIB_MOD ((NSModule) 'DYMO')
   186 
   187 /* internal flags */
   188 #define DL_IN_LIST 0x01
   189 
   190 /* our mutex */
   191 static pthread_mutex_t dlcompat_mutex;
   192 /* Our thread specific storage
   193  */
   194 static pthread_key_t dlerror_key;
   195 
   196 struct dlthread
   197 {
   198 	int lockcnt;
   199 	unsigned char errset;
   200 	char errstr[ERR_STR_LEN];
   201 };
   202 
   203 /* This is our central data structure. Whenever a module is loaded via
   204  * SDL_OSX_dlopen(), we create such a struct.
   205  */
   206 struct dlstatus
   207 {
   208 	struct dlstatus *next;		/* pointer to next element in the linked list */
   209 	NSModule module;
   210 	const struct mach_header *lib;
   211 	int refs;					/* reference count */
   212 	int mode;					/* mode in which this module was loaded */
   213 	dev_t device;
   214 	ino_t inode;
   215 	int flags;					/* Any internal flags we may need */
   216 };
   217 
   218 /* Head node of the dlstatus list */
   219 static struct dlstatus mainStatus = { 0, MAGIC_DYLIB_MOD, NULL, -1, RTLD_GLOBAL, 0, 0, 0 };
   220 static struct dlstatus *stqueue = &mainStatus;
   221 
   222 
   223 /* Storage for the last error message (used by dlerror()) */
   224 /* static char err_str[ERR_STR_LEN]; */
   225 /* static int err_filled = 0; */
   226 
   227 /* Prototypes to internal functions */
   228 static void debug(const char *fmt, ...);
   229 static void error(const char *str, ...);
   230 static const char *safegetenv(const char *s);
   231 static const char *searchList(void);
   232 static const char *getSearchPath(int i);
   233 static const char *getFullPath(int i, const char *file);
   234 static const struct stat *findFile(const char *file, const char **fullPath);
   235 static int isValidStatus(struct dlstatus *status);
   236 static inline int isFlagSet(int mode, int flag);
   237 static struct dlstatus *lookupStatus(const struct stat *sbuf);
   238 static void insertStatus(struct dlstatus *dls, const struct stat *sbuf);
   239 static int promoteLocalToGlobal(struct dlstatus *dls);
   240 static void *reference(struct dlstatus *dls, int mode);
   241 static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError);
   242 static struct dlstatus *allocStatus(void);
   243 static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode);
   244 static NSSymbol *search_linked_libs(const struct mach_header *mh, const char *symbol);
   245 static const char *get_lib_name(const struct mach_header *mh);
   246 static const struct mach_header *get_mach_header_from_NSModule(NSModule * mod);
   247 static void dlcompat_init_func(void);
   248 static inline void dlcompat_init_check(void);
   249 static inline void dolock(void);
   250 static inline void dounlock(void);
   251 static void dlerrorfree(void *data);
   252 static void resetdlerror(void);
   253 static const struct mach_header *my_find_image(const char *name);
   254 static const struct mach_header *image_for_address(const void *address);
   255 static inline const char *dyld_error_str(void);
   256 
   257 #if FINK_BUILD
   258 /* Two Global Functions */
   259 static void *dlsym_prepend_underscore(void *handle, const char *symbol);
   260 static void *dlsym_auto_underscore(void *handle, const char *symbol);
   261 
   262 /* And their _intern counterparts */
   263 static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol);
   264 static void *dlsym_auto_underscore_intern(void *handle, const char *symbol);
   265 #endif
   266 
   267 /* Functions */
   268 
   269 static void debug(const char *fmt, ...)
   270 {
   271 #if DEBUG > 1
   272 	va_list arg;
   273 	va_start(arg, fmt);
   274 	fprintf(stderr, "DLDEBUG: ");
   275 	vfprintf(stderr, fmt, arg);
   276 	fprintf(stderr, "\n");
   277 	fflush(stderr);
   278 	va_end(arg);
   279 #endif
   280 }
   281 
   282 static void error(const char *str, ...)
   283 {
   284 	va_list arg;
   285 	struct dlthread  *tss;
   286 	char * err_str;
   287 	va_start(arg, str);
   288 	tss = pthread_getspecific(dlerror_key);
   289 	err_str = tss->errstr;
   290 	strncpy(err_str, "dlcompat: ", ERR_STR_LEN);
   291 	vsnprintf(err_str + 10, ERR_STR_LEN - 10, str, arg);
   292 	va_end(arg);
   293 	debug("ERROR: %s\n", err_str);
   294 	tss->errset = 1;
   295 }
   296 
   297 static void warning(const char *str)
   298 {
   299 #if DEBUG > 0
   300 	fprintf(stderr, "WARNING: dlcompat: %s\n", str);
   301 #endif
   302 }
   303 
   304 static const char *safegetenv(const char *s)
   305 {
   306 	const char *ss = getenv(s);
   307 	return ss ? ss : "";
   308 }
   309 
   310 /* because this is only used for debugging and error reporting functions, we
   311  * don't really care about how elegant it is... it could use the load
   312  * commands to find the install name of the library, but...
   313  */
   314 static const char *get_lib_name(const struct mach_header *mh)
   315 {
   316 	unsigned long count = _dyld_image_count();
   317 	unsigned long i;
   318 	const char *val = NULL;
   319 	if (mh)
   320 	{
   321 		for (i = 0; i < count; i++)
   322 		{
   323 			if (mh == _dyld_get_image_header(i))
   324 			{
   325 				val = _dyld_get_image_name(i);
   326 				break;
   327 			}
   328 		}
   329 	}
   330 	return val;
   331 }
   332 
   333 /* Returns the mach_header for the module bu going through all the loaded images
   334  * and finding the one with the same name as the module. There really ought to be
   335  * an api for doing this, would be faster, but there isn't one right now
   336  */
   337 static const struct mach_header *get_mach_header_from_NSModule(NSModule * mod)
   338 {
   339 	const char *mod_name = NSNameOfModule(mod);
   340 	struct mach_header *mh = NULL;
   341 	unsigned long count = _dyld_image_count();
   342 	unsigned long i;
   343 	debug("Module name: %s", mod_name);
   344 	for (i = 0; i < count; i++)
   345 	{
   346 		if (!strcmp(mod_name, _dyld_get_image_name(i)))
   347 		{
   348 			mh = _dyld_get_image_header(i);
   349 			break;
   350 		}
   351 	}
   352 	return mh;
   353 }
   354 
   355 
   356 /* Compute and return a list of all directories that we should search when
   357  * trying to locate a module. We first look at the values of LD_LIBRARY_PATH
   358  * and DYLD_LIBRARY_PATH, and then finally fall back to looking into
   359  * /usr/lib and /lib. Since both of the environments variables can contain a
   360  * list of colon seperated paths, we simply concat them and the two other paths
   361  * into one big string, which we then can easily parse.
   362  * Splitting this string into the actual path list is done by getSearchPath()
   363  */
   364 static const char *searchList()
   365 {
   366 	size_t buf_size;
   367 	static char *buf=NULL;
   368 	const char *ldlp = safegetenv("LD_LIBRARY_PATH");
   369 	const char *dyldlp = safegetenv("DYLD_LIBRARY_PATH");
   370 	const char *stdpath = getenv("DYLD_FALLBACK_LIBRARY_PATH");
   371 	if (!stdpath)
   372 		stdpath = "/usr/local/lib:/lib:/usr/lib";
   373 	if (!buf)
   374 	{	
   375 		buf_size = strlen(ldlp) + strlen(dyldlp) + strlen(stdpath) + 4;
   376 		buf = malloc(buf_size);
   377 		snprintf(buf, buf_size, "%s%s%s%s%s%c", dyldlp, (dyldlp[0] ? ":" : ""), ldlp, (ldlp[0] ? ":" : ""),
   378 				 stdpath, '\0');
   379 	}
   380 	return buf;
   381 }
   382 
   383 /* Returns the ith search path from the list as computed by searchList() */
   384 static const char *getSearchPath(int i)
   385 {
   386 	static const char *list = 0;
   387 	static char **path = (char **)0;
   388 	static int end = 0;
   389 	static int numsize = MAX_SEARCH_PATHS;
   390 	static char **tmp;
   391 	/* So we can call free() in the "destructor" we use i=-1 to return the alloc'd array */
   392 	if (i == -1)
   393 	{
   394 		return (const char*)path;
   395 	}
   396 	if (!path)
   397 	{
   398 		path = (char **)calloc(MAX_SEARCH_PATHS, sizeof(char **));
   399 	}
   400 	if (!list && !end)
   401 		list = searchList();
   402 	if (i >= (numsize))
   403 	{
   404 		debug("Increasing size for long PATH");
   405 		tmp = (char **)calloc((MAX_SEARCH_PATHS + numsize), sizeof(char **));
   406 		if (tmp)
   407 		{
   408 			memcpy(tmp, path, sizeof(char **) * numsize);
   409 			free(path);
   410 			path = tmp;
   411 			numsize += MAX_SEARCH_PATHS;
   412 		}
   413 		else
   414 		{
   415 			return 0;
   416 		}
   417 	}
   418 
   419 	while (!path[i] && !end)
   420 	{
   421 		path[i] = strsep((char **)&list, ":");
   422 
   423 		if (path[i][0] == 0)
   424 			path[i] = 0;
   425 		end = (list == 0);
   426 	}
   427 	return path[i];
   428 }
   429 
   430 static const char *getFullPath(int i, const char *file)
   431 {
   432 	static char buf[PATH_MAX];
   433 	const char *path = getSearchPath(i);
   434 	if (path)
   435 	{
   436 		snprintf(buf, PATH_MAX, "%s/%s", path, file);
   437 	}
   438 	return path ? buf : 0;
   439 }
   440 
   441 /* Given a file name, try to determine the full path for that file. Starts
   442  * its search in the current directory, and then tries all paths in the 
   443  * search list in the order they are specified there.
   444  */
   445 static const struct stat *findFile(const char *file, const char **fullPath)
   446 {
   447 	int i = 0;
   448 	static struct stat sbuf;
   449 	char *fileName;
   450 	debug("finding file %s", file);
   451 	*fullPath = file;
   452 	if (0 == stat(file, &sbuf))
   453 		return &sbuf;
   454 	if (strchr(file, '/'))
   455 		return 0;				/* If the path had a / we don't look in env var places */
   456 	fileName = NULL;
   457 	if (!fileName)
   458 		fileName = (char *)file;
   459 	while ((*fullPath = getFullPath(i++, fileName)))
   460 	{
   461 		if (0 == stat(*fullPath, &sbuf))
   462 			return &sbuf;
   463 	}
   464 	;
   465 	return 0;
   466 }
   467 
   468 /* Determine whether a given dlstatus is valid or not */
   469 static int isValidStatus(struct dlstatus *status)
   470 {
   471 	/* Walk the list to verify status is contained in it */
   472 	struct dlstatus *dls = stqueue;
   473 	while (dls && status != dls)
   474 		dls = dls->next;
   475 	if (dls == 0)
   476 		error("invalid handle");
   477 	else if ((dls->module == 0) || (dls->refs == 0))
   478 		error("handle to closed library");
   479 	else
   480 		return TRUE;
   481 	return FALSE;
   482 }
   483 
   484 static inline int isFlagSet(int mode, int flag)
   485 {
   486 	return (mode & flag) == flag;
   487 }
   488 
   489 static struct dlstatus *lookupStatus(const struct stat *sbuf)
   490 {
   491 	struct dlstatus *dls = stqueue;
   492 	debug("looking for status");
   493 	while (dls && ( /* isFlagSet(dls->mode, RTLD_UNSHARED) */ 0
   494 				   || sbuf->st_dev != dls->device || sbuf->st_ino != dls->inode))
   495 		dls = dls->next;
   496 	return dls;
   497 }
   498 
   499 static void insertStatus(struct dlstatus *dls, const struct stat *sbuf)
   500 {
   501 	debug("inserting status");
   502 	dls->inode = sbuf->st_ino;
   503 	dls->device = sbuf->st_dev;
   504 	dls->refs = 0;
   505 	dls->mode = 0;
   506 	if ((dls->flags & DL_IN_LIST) == 0)
   507 	{
   508 		dls->next = stqueue;
   509 		stqueue = dls;
   510 		dls->flags |= DL_IN_LIST;
   511 	}
   512 }
   513 
   514 static struct dlstatus *allocStatus()
   515 {
   516 	struct dlstatus *dls;
   517 #ifdef REUSE_STATUS
   518 	dls = stqueue;
   519 	while (dls && dls->module)
   520 		dls = dls->next;
   521 	if (!dls)
   522 #endif
   523 		dls = calloc(sizeof(*dls),1);
   524 	return dls;
   525 }
   526 
   527 static int promoteLocalToGlobal(struct dlstatus *dls)
   528 {
   529 	static int (*p) (NSModule module) = 0;
   530 	debug("promoting");
   531 	if (!p)
   532 		_dyld_func_lookup("__dyld_NSMakePrivateModulePublic", (unsigned long *)&p);
   533 	return (dls->module == MAGIC_DYLIB_MOD) || (p && p(dls->module));
   534 }
   535 
   536 static void *reference(struct dlstatus *dls, int mode)
   537 {
   538 	if (dls)
   539 	{
   540 		if (dls->module == MAGIC_DYLIB_MOD && isFlagSet(mode, RTLD_LOCAL))
   541 		{
   542 			warning("trying to open a .dylib with RTLD_LOCAL");
   543 			error("unable to open a .dylib with RTLD_LOCAL");
   544 			return NULL;
   545 		}
   546 		if (isFlagSet(mode, RTLD_GLOBAL) &&
   547 			!isFlagSet(dls->mode, RTLD_GLOBAL) && !promoteLocalToGlobal(dls))
   548 		{
   549 			error("unable to promote local module to global");
   550 			return NULL;
   551 		}
   552 		dls->mode |= mode;
   553 		dls->refs++;
   554 	}
   555 	else
   556 		debug("reference called with NULL argument");
   557 
   558 	return dls;
   559 }
   560 
   561 static const struct mach_header *my_find_image(const char *name)
   562 {
   563 	const struct mach_header *mh = 0;
   564 	const char *id = NULL;
   565 	int i = _dyld_image_count();
   566 	int j;
   567 	mh = (struct mach_header *)
   568 		dyld_NSAddImage(name, NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED |
   569 						NSADDIMAGE_OPTION_RETURN_ON_ERROR);
   570 	if (!mh)
   571 	{
   572 		for (j = 0; j < i; j++)
   573 		{
   574 			id = _dyld_get_image_name(j);
   575 			if (!strcmp(id, name))
   576 			{
   577 				mh = _dyld_get_image_header(j);
   578 				break;
   579 			}
   580 		}
   581 	}
   582 	return mh;
   583 }
   584 
   585 /*
   586  * dyld adds libraries by first adding the directly dependant libraries in link order, and
   587  * then adding the dependencies for those libraries, so we should do the same... but we don't
   588  * bother adding the extra dependencies, if the symbols are neither in the loaded image nor
   589  * any of it's direct dependencies, then it probably isn't there.
   590  */
   591 static NSSymbol *search_linked_libs(const struct mach_header * mh, const char *symbol)
   592 {
   593 	unsigned int n;
   594 	struct load_command *lc = 0;
   595 	struct mach_header *wh;
   596 	NSSymbol *nssym = 0;
   597 	if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
   598 	{
   599 		lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
   600 		for (n = 0; n < mh->ncmds; n++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
   601 		{
   602 			if ((LC_LOAD_DYLIB == lc->cmd) || (LC_LOAD_WEAK_DYLIB == lc->cmd))
   603 			{
   604 				if ((wh = (struct mach_header *)
   605 					 my_find_image((char *)(((struct dylib_command *)lc)->dylib.name.offset +
   606 											(char *)lc))))
   607 				{
   608 					if (dyld_NSIsSymbolNameDefinedInImage(wh, symbol))
   609 					{
   610 						nssym = dyld_NSLookupSymbolInImage(wh,
   611 														   symbol,
   612 														   NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
   613 														   NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
   614 						break;
   615 					}
   616 				}
   617 			}
   618 		}
   619 		if ((!nssym) && NSIsSymbolNameDefined(symbol))
   620 		{
   621 			/* I've never seen this debug message...*/
   622 			debug("Symbol \"%s\" is defined but was not found", symbol);
   623 		}
   624 	}
   625 	return nssym;
   626 }
   627 
   628 /* Up to the caller to free() returned string */
   629 static inline const char *dyld_error_str()
   630 {
   631 	NSLinkEditErrors dylder;
   632 	int dylderno;
   633 	const char *dylderrstr;
   634 	const char *dyldfile;
   635 	const char* retStr = NULL;
   636 	NSLinkEditError(&dylder, &dylderno, &dyldfile, &dylderrstr);
   637 	if (dylderrstr && strlen(dylderrstr))
   638 	{
   639 		retStr = malloc(strlen(dylderrstr) +1);
   640 		strcpy((char*)retStr,dylderrstr);
   641 	}
   642 	return retStr;
   643 }
   644 
   645 static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError)
   646 {
   647   NSSymbol *nssym = 0;
   648 #ifdef __GCC__  
   649 	void *caller = __builtin_return_address(1);	/* Be *very* careful about inlining */
   650 #else
   651 	void *caller = NULL;
   652 #endif
   653 	const struct mach_header *caller_mh = 0;
   654 	const char* savedErrorStr = NULL;
   655 	resetdlerror();
   656 #ifndef RTLD_SELF
   657 #define	RTLD_SELF		((void *) -3)
   658 #endif
   659 	if (NULL == dls)
   660 		dls = RTLD_SELF;
   661 	if ((RTLD_NEXT == dls) || (RTLD_SELF == dls))
   662 	{
   663 		if (dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage && caller)
   664 		  {
   665 			caller_mh = image_for_address(caller);
   666 			if (RTLD_SELF == dls)
   667 			{
   668 				/* FIXME: We should be using the NSModule api, if SELF is an MH_BUNDLE
   669 				 * But it appears to work anyway, and looking at the code in dyld_libfuncs.c
   670 				 * this is acceptable.
   671 				 */
   672 				if (dyld_NSIsSymbolNameDefinedInImage(caller_mh, symbol))
   673 				{
   674 					nssym = dyld_NSLookupSymbolInImage(caller_mh,
   675 													   symbol,
   676 													   NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
   677 													   NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
   678 				}
   679 			}
   680 			if (!nssym)
   681 			{
   682 				if (RTLD_SELF == dls)
   683 					savedErrorStr = dyld_error_str();
   684 				nssym = search_linked_libs(caller_mh, symbol);
   685 			}
   686 		}
   687 		else
   688 		{
   689 			if (canSetError)
   690 				error("RTLD_SELF and RTLD_NEXT are not supported");
   691 			return NULL;
   692 		}
   693 	}
   694 	if (!nssym)
   695 	{
   696 
   697 		if (RTLD_DEFAULT == dls)
   698 		{
   699 			dls = &mainStatus;
   700 		}
   701 		if (!isValidStatus(dls))
   702 			return NULL;
   703 
   704 		if (dls->module != MAGIC_DYLIB_MOD)
   705 		{
   706 			nssym = NSLookupSymbolInModule(dls->module, symbol);
   707 			if (!nssym && NSIsSymbolNameDefined(symbol))
   708 			{
   709 				debug("Searching dependencies");
   710 				savedErrorStr = dyld_error_str();
   711 				nssym = search_linked_libs(get_mach_header_from_NSModule(dls->module), symbol);
   712 			}
   713 		}
   714 		else if (dls->lib && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
   715 		{
   716 			if (dyld_NSIsSymbolNameDefinedInImage(dls->lib, symbol))
   717 			{
   718 				nssym = dyld_NSLookupSymbolInImage(dls->lib,
   719 												   symbol,
   720 												   NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
   721 												   NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
   722 			}
   723 			else if (NSIsSymbolNameDefined(symbol))
   724 			{
   725 				debug("Searching dependencies");
   726 				savedErrorStr = dyld_error_str();
   727 				nssym = search_linked_libs(dls->lib, symbol);
   728 			}
   729 		}
   730 		else if (dls->module == MAGIC_DYLIB_MOD)
   731 		{
   732 			/* Global context, use NSLookupAndBindSymbol */
   733 			if (NSIsSymbolNameDefined(symbol))
   734 			{
   735 				/* There doesn't seem to be a return on error option for this call???
   736 				   this is potentially broken, if binding fails, it will improperly
   737 				   exit the application. */
   738 				nssym = NSLookupAndBindSymbol(symbol);
   739 			}
   740 			else
   741 			{
   742 				if (savedErrorStr)
   743 					free((char*)savedErrorStr);			
   744 				savedErrorStr = malloc(256);
   745 				snprintf((char*)savedErrorStr, 256, "Symbol \"%s\" not in global context",symbol);	
   746 			}
   747 		}
   748 	}
   749 	/* Error reporting */
   750 	if (!nssym)
   751 	{
   752 		if (!savedErrorStr || !strlen(savedErrorStr))
   753 		{
   754 			if (savedErrorStr)
   755 				free((char*)savedErrorStr);
   756 			savedErrorStr = malloc(256);
   757 			snprintf((char*)savedErrorStr, 256,"Symbol \"%s\" not found",symbol);
   758 		}
   759 		if (canSetError)
   760 		{
   761 			error(savedErrorStr);
   762 		}
   763 		else
   764 		{
   765 			debug(savedErrorStr);
   766 		}
   767 		if (savedErrorStr)
   768 			free((char*)savedErrorStr);
   769 		return NULL;
   770 	}
   771 	return NSAddressOfSymbol(nssym);
   772 }
   773 
   774 static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode)
   775 {
   776 	NSObjectFileImage ofi = 0;
   777 	NSObjectFileImageReturnCode ofirc;
   778 	struct dlstatus *dls;
   779 	NSLinkEditErrors ler;
   780 	int lerno;
   781 	const char *errstr;
   782 	const char *file;
   783 	void (*init) (void);
   784 	ofirc = NSCreateObjectFileImageFromFile(path, &ofi);
   785 	switch (ofirc)
   786 	{
   787 		case NSObjectFileImageSuccess:
   788 			break;
   789 		case NSObjectFileImageInappropriateFile:
   790 			if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage)
   791 			{	
   792 				if (isFlagSet(mode, RTLD_LOCAL))
   793 				{
   794 					warning("trying to open a .dylib with RTLD_LOCAL");
   795 					error("unable to open this file with RTLD_LOCAL");
   796 					return NULL;
   797 				}
   798 			}
   799 			else
   800 			{
   801 				error("opening this file is unsupported on this system");
   802 				return NULL;
   803 			}
   804 			break;
   805 		case NSObjectFileImageFailure:
   806 			error("object file setup failure");
   807 			return NULL;
   808 		case NSObjectFileImageArch:
   809 			error("no object for this architecture");
   810 			return NULL;
   811 		case NSObjectFileImageFormat:
   812 			error("bad object file format");
   813 			return NULL;
   814 		case NSObjectFileImageAccess:
   815 			error("can't read object file");
   816 			return NULL;
   817 		default:
   818 			error("unknown error from NSCreateObjectFileImageFromFile()");
   819 			return NULL;
   820 	}
   821 	dls = lookupStatus(sbuf);
   822 	if (!dls)
   823 	{
   824 		dls = allocStatus();
   825 	}
   826 	if (!dls)
   827 	{
   828 		error("unable to allocate memory");
   829 		return NULL;
   830 	}
   831 	//	dls->lib = 0;
   832 	if (ofirc == NSObjectFileImageInappropriateFile)
   833 	{
   834 		if ((dls->lib = dyld_NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR)))
   835 		{
   836 			debug("Dynamic lib loaded at %ld", dls->lib);
   837 			ofi = MAGIC_DYLIB_OFI;
   838 			dls->module = MAGIC_DYLIB_MOD;
   839 			ofirc = NSObjectFileImageSuccess;
   840 			/* Although it is possible with a bit of work to modify this so it works and
   841 			   functions with RTLD_NOW, I don't deem it necessary at the moment */
   842 		}
   843 		if (!(dls->module))
   844 		{
   845 			NSLinkEditError(&ler, &lerno, &file, &errstr);
   846 			if (!errstr || (!strlen(errstr)))
   847 				error("Can't open this file type");
   848 			else
   849 				error(errstr);
   850 			if ((dls->flags & DL_IN_LIST) == 0)
   851 			{
   852 				free(dls);
   853 			}
   854 			return NULL;
   855 		}
   856 	}
   857 	else
   858 	{
   859 		dls->module = NSLinkModule(ofi, path,
   860 								   NSLINKMODULE_OPTION_RETURN_ON_ERROR |
   861 								   NSLINKMODULE_OPTION_PRIVATE |
   862 								   (isFlagSet(mode, RTLD_NOW) ? NSLINKMODULE_OPTION_BINDNOW : 0));
   863 		NSDestroyObjectFileImage(ofi);
   864 		if (dls->module)
   865 		{
   866 			dls->lib = get_mach_header_from_NSModule(dls->module);
   867 		}
   868 	}
   869 	if (!dls->module)
   870 	{
   871 		NSLinkEditError(&ler, &lerno, &file, &errstr);
   872 		if ((dls->flags & DL_IN_LIST) == 0)
   873 		{
   874 			free(dls);
   875 		}
   876 		error(errstr);
   877 		return NULL;
   878 	}
   879 
   880 	insertStatus(dls, sbuf);
   881 	dls = reference(dls, mode);
   882 	if ((init = dlsymIntern(dls, "__init", 0)))
   883 	{
   884 		debug("calling _init()");
   885 		init();
   886 	}
   887 	return dls;
   888 }
   889 
   890 inline static void dlcompat_init_check(void)
   891 {
   892 	static pthread_mutex_t l = PTHREAD_MUTEX_INITIALIZER;
   893 	static int init_done = 0;
   894 
   895 	pthread_mutex_lock(&l);
   896 	if (!init_done) {
   897 		dlcompat_init_func();
   898 		init_done = 1;
   899 	}
   900 	pthread_mutex_unlock(&l);
   901 }
   902 
   903 static void dlcompat_init_func(void)
   904 {
   905         _dyld_func_lookup("__dyld_NSAddImage", (unsigned long *)&dyld_NSAddImage);
   906 	_dyld_func_lookup("__dyld_NSIsSymbolNameDefinedInImage",
   907 			  (unsigned long *)&dyld_NSIsSymbolNameDefinedInImage);
   908 	_dyld_func_lookup("__dyld_NSLookupSymbolInImage", (unsigned long *)&dyld_NSLookupSymbolInImage);
   909 	if (pthread_mutex_init(&dlcompat_mutex, NULL))
   910 	    exit(1);
   911 	if (pthread_key_create(&dlerror_key, &dlerrorfree))
   912 	    exit(1);
   913 }
   914 
   915 static void resetdlerror()
   916 {
   917 	struct dlthread *tss;
   918 	tss = pthread_getspecific(dlerror_key);
   919 	tss->errset = 0;
   920 }
   921 
   922 static void dlerrorfree(void *data)
   923 {
   924 	free(data);
   925 }
   926 
   927 /* We kind of want a recursive lock here, but meet a little trouble
   928  * because they are not available pre OS X 10.2, so we fake it
   929  * using thread specific storage to keep a lock count
   930  */ 
   931 static inline void dolock(void)
   932 {
   933 	int err = 0;
   934 	struct dlthread *tss;
   935 	dlcompat_init_check();
   936 	tss = pthread_getspecific(dlerror_key);
   937 	if (!tss)
   938 	{
   939 		tss = malloc(sizeof(struct dlthread));
   940 		tss->lockcnt = 0;
   941 		tss->errset = 0;
   942 		if (pthread_setspecific(dlerror_key, tss))
   943 		{
   944 			fprintf(stderr,"dlcompat: pthread_setspecific failed\n");
   945 			exit(1);
   946 		}
   947 	}
   948 	if (!tss->lockcnt)
   949 		err = pthread_mutex_lock(&dlcompat_mutex);
   950 	tss->lockcnt = tss->lockcnt +1;	
   951 	if (err)
   952 		exit(err);
   953 }
   954 
   955 static inline void dounlock(void)
   956 {
   957 	int err = 0;
   958 	struct dlthread *tss;
   959 	tss = pthread_getspecific(dlerror_key);
   960 	tss->lockcnt = tss->lockcnt -1;
   961 	if (!tss->lockcnt)
   962 		err = pthread_mutex_unlock(&dlcompat_mutex);
   963 	if (err)
   964 		exit(err);
   965 }
   966 
   967 static void *SDL_OSX_dlopen(const char *path, int mode)
   968 {
   969 	const struct stat *sbuf;
   970 	struct dlstatus *dls;
   971 	const char *fullPath;
   972 
   973 	dolock();
   974 	resetdlerror();
   975 	if (!path)
   976 	{
   977 		dls = &mainStatus;
   978 		goto dlopenok;
   979 	}
   980 	if (!(sbuf = findFile(path, &fullPath)))
   981 	{
   982 		error("file \"%s\" not found", path);
   983 		goto dlopenerror;
   984 	}
   985 	/* Now checks that it hasn't been closed already */
   986 	if ((dls = lookupStatus(sbuf)) && (dls->refs > 0))
   987 	{
   988 		/* debug("status found"); */
   989 		dls = reference(dls, mode);
   990 		goto dlopenok;
   991 	}
   992 #ifdef 	RTLD_NOLOAD
   993 	if (isFlagSet(mode, RTLD_NOLOAD))
   994 	{
   995 		error("no existing handle and RTLD_NOLOAD specified");
   996 		goto dlopenerror;
   997 	}
   998 #endif
   999 	if (isFlagSet(mode, RTLD_LAZY) && isFlagSet(mode, RTLD_NOW))
  1000 	{
  1001 		error("how can I load something both RTLD_LAZY and RTLD_NOW?");
  1002 		goto dlopenerror;
  1003 	}
  1004 	dls = loadModule(fullPath, sbuf, mode);
  1005 	
  1006   dlopenok:
  1007 	dounlock();
  1008 	return (void *)dls;
  1009   dlopenerror:
  1010 	dounlock();
  1011 	return NULL;
  1012 }
  1013 
  1014 #if !FINK_BUILD
  1015 static void *SDL_OSX_dlsym(void * dl_restrict handle, const char * dl_restrict symbol)
  1016 {
  1017 	int sym_len = strlen(symbol);
  1018 	void *value = NULL;
  1019 	char *malloc_sym = NULL;
  1020 	dolock();
  1021 	malloc_sym = malloc(sym_len + 2);
  1022 	if (malloc_sym)
  1023 	{
  1024 		sprintf(malloc_sym, "_%s", symbol);
  1025 		value = dlsymIntern(handle, malloc_sym, 1);
  1026 		free(malloc_sym);
  1027 	}
  1028 	else
  1029 	{
  1030 		error("Unable to allocate memory");
  1031 		goto dlsymerror;
  1032 	}
  1033 	dounlock();
  1034 	return value;
  1035   dlsymerror:
  1036 	dounlock();
  1037 	return NULL;
  1038 }
  1039 #endif
  1040 
  1041 #if FINK_BUILD
  1042 
  1043 static void *dlsym_prepend_underscore(void *handle, const char *symbol)
  1044 {
  1045 	void *answer;
  1046 	dolock();
  1047 	answer = dlsym_prepend_underscore_intern(handle, symbol);
  1048 	dounlock();
  1049 	return answer;
  1050 }
  1051 
  1052 static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol)
  1053 {
  1054 /*
  1055  *	A quick and easy way for porting packages which call dlsym(handle,"sym")
  1056  *	If the porter adds -Ddlsym=dlsym_prepend_underscore to the CFLAGS then
  1057  *	this function will be called, and will add the required underscore.
  1058  *	
  1059  *	Note that I haven't figured out yet which should be "standard", prepend
  1060  *	the underscore always, or not at all. These global functions need to go away
  1061  *	for opendarwin.
  1062  */
  1063 	int sym_len = strlen(symbol);
  1064 	void *value = NULL;
  1065 	char *malloc_sym = NULL;
  1066 	malloc_sym = malloc(sym_len + 2);
  1067 	if (malloc_sym)
  1068 	{
  1069 		sprintf(malloc_sym, "_%s", symbol);
  1070 		value = dlsymIntern(handle, malloc_sym, 1);
  1071 		free(malloc_sym);
  1072 	}
  1073 	else
  1074 	{
  1075 		error("Unable to allocate memory");
  1076 	}
  1077 	return value;
  1078 }
  1079 
  1080 static void *dlsym_auto_underscore(void *handle, const char *symbol)
  1081 {
  1082 	void *answer;
  1083 	dolock();
  1084 	answer = dlsym_auto_underscore_intern(handle, symbol);
  1085 	dounlock();
  1086 	return answer;
  1087 
  1088 }
  1089 static void *dlsym_auto_underscore_intern(void *handle, const char *symbol)
  1090 {
  1091 	struct dlstatus *dls = handle;
  1092 	void *addr = 0;
  1093 	addr = dlsymIntern(dls, symbol, 0);
  1094 	if (!addr)
  1095 		addr = dlsym_prepend_underscore_intern(handle, symbol);
  1096 	return addr;
  1097 }
  1098 
  1099 
  1100 static void *SDL_OSX_dlsym(void * dl_restrict handle, const char * dl_restrict symbol)
  1101 {
  1102 	struct dlstatus *dls = handle;
  1103 	void *addr = 0;
  1104 	dolock();
  1105 	addr = dlsymIntern(dls, symbol, 1);
  1106 	dounlock();
  1107 	return addr;
  1108 }
  1109 #endif
  1110 
  1111 static int SDL_OSX_dlclose(void *handle)
  1112 {
  1113 	struct dlstatus *dls = handle;
  1114 	dolock();
  1115 	resetdlerror();
  1116 	if (!isValidStatus(dls))
  1117 	{
  1118 		goto dlcloseerror;
  1119 	}
  1120 	if (dls->module == MAGIC_DYLIB_MOD)
  1121 	{
  1122 		const char *name;
  1123 		if (!dls->lib)
  1124 		{
  1125 			name = "global context";
  1126 		}
  1127 		else
  1128 		{
  1129 			name = get_lib_name(dls->lib);
  1130 		}
  1131 		warning("trying to close a .dylib!");
  1132 		error("Not closing \"%s\" - dynamic libraries cannot be closed", name);
  1133 		goto dlcloseerror;
  1134 	}
  1135 	if (!dls->module)
  1136 	{
  1137 		error("module already closed");
  1138 		goto dlcloseerror;
  1139 	}
  1140 	
  1141 	if (dls->refs == 1)
  1142 	{
  1143 		unsigned long options = 0;
  1144 		void (*fini) (void);
  1145 		if ((fini = dlsymIntern(dls, "__fini", 0)))
  1146 		{
  1147 			debug("calling _fini()");
  1148 			fini();
  1149 		}
  1150 		options |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;
  1151 #ifdef RTLD_NODELETE
  1152 		if (isFlagSet(dls->mode, RTLD_NODELETE))
  1153 			options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
  1154 #endif
  1155 		if (!NSUnLinkModule(dls->module, options))
  1156 		{
  1157 			error("unable to unlink module");
  1158 			goto dlcloseerror;
  1159 		}
  1160 		dls->refs--;
  1161 		dls->module = 0;
  1162 		/* Note: the dlstatus struct dls is neither removed from the list
  1163 		 * nor is the memory it occupies freed. This shouldn't pose a 
  1164 		 * problem in mostly all cases, though.
  1165 		 */
  1166 	}
  1167 	dounlock();
  1168 	return 0;
  1169   dlcloseerror:
  1170 	dounlock();
  1171 	return 1;
  1172 }
  1173 
  1174 static char *SDL_OSX_dlerror(void)
  1175 {
  1176 	struct dlthread  *tss;
  1177 	const char * err_str = NULL;
  1178 	dlcompat_init_check();
  1179 	tss = pthread_getspecific(dlerror_key);
  1180 	if (tss != NULL && tss->errset != 0) {
  1181 		tss->errset = 0;	
  1182 		err_str = tss->errstr;
  1183 	}
  1184 	return (err_str);
  1185 }
  1186 
  1187 /* Given an address, return the mach_header for the image containing it
  1188  * or zero if the given address is not contained in any loaded images.
  1189  */
  1190 static const struct mach_header *image_for_address(const void *address)
  1191 {
  1192 	unsigned long i;
  1193 	unsigned long j;
  1194 	unsigned long count = _dyld_image_count();
  1195 	struct mach_header *mh = 0;
  1196 	struct load_command *lc = 0;
  1197 	unsigned long addr = NULL;
  1198 	for (i = 0; i < count; i++)
  1199 	{
  1200 		addr = (unsigned long)address - _dyld_get_image_vmaddr_slide(i);
  1201 		mh = _dyld_get_image_header(i);
  1202 		if (mh)
  1203 		{
  1204 			lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
  1205 			for (j = 0; j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
  1206 			{
  1207 				if (LC_SEGMENT == lc->cmd &&
  1208 					addr >= ((struct segment_command *)lc)->vmaddr &&
  1209 					addr <
  1210 					((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize)
  1211 				{
  1212 					goto image_found;
  1213 				}
  1214 			}
  1215 		}
  1216 		mh = 0;
  1217 	}
  1218   image_found:
  1219 	return mh;
  1220 }
  1221 
  1222 static int SDL_OSX_dladdr(const void * dl_restrict p, SDL_OSX_Dl_info * dl_restrict info)
  1223 {
  1224 /*
  1225 	FIXME: USe the routine image_for_address.
  1226 */
  1227 	unsigned long i;
  1228 	unsigned long j;
  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;
  1234 	int found = 0;
  1235 	if (!info)
  1236 		return 0;
  1237 	dolock();
  1238 	resetdlerror();
  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
  1245  */
  1246 	for (i = 0; i < count; i++)
  1247 	{
  1248 		addr = (unsigned long)p - _dyld_get_image_vmaddr_slide(i);
  1249 		mh = _dyld_get_image_header(i);
  1250 		if (mh)
  1251 		{
  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))
  1254 			{
  1255 				if (LC_SEGMENT == lc->cmd &&
  1256 					addr >= ((struct segment_command *)lc)->vmaddr &&
  1257 					addr <
  1258 					((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize)
  1259 				{
  1260 					info->dli_fname = _dyld_get_image_name(i);
  1261 					info->dli_fbase = (void *)mh;
  1262 					found = 1;
  1263 					break;
  1264 				}
  1265 			}
  1266 			if (found)
  1267 				break;
  1268 		}
  1269 	}
  1270 	if (!found)
  1271 	{
  1272 		dounlock();
  1273 		return 0;
  1274 	}
  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))
  1277 	{
  1278 		if (LC_SEGMENT == lc->cmd)
  1279 		{
  1280 			if (!strcmp(((struct segment_command *)lc)->segname, "__LINKEDIT"))
  1281 				break;
  1282 		}
  1283 	}
  1284 	table_off =
  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);
  1288 
  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))
  1291 	{
  1292 		if (LC_SYMTAB == lc->cmd)
  1293 		{
  1294 
  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++)
  1302 			{
  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 */
  1307 					)
  1308 				{
  1309 					symtable++;
  1310 					continue;
  1311 				}
  1312 				if ((addr >= symtable->n_value) && (diff >= (symtable->n_value - addr)))
  1313 				{
  1314 					diff = (unsigned long)symtable->n_value - addr;
  1315 					nearest = symtable;
  1316 				}
  1317 				symtable++;
  1318 			}
  1319 			if (nearest)
  1320 			{
  1321 				info->dli_saddr = nearest->n_value + ((void *)p - addr);
  1322 				info->dli_sname = (char *)(strtable + nearest->n_un.n_strx);
  1323 			}
  1324 		}
  1325 	}
  1326 	dounlock();
  1327 	return 1;
  1328 }
  1329 
  1330 
  1331 /*
  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.
  1339  */
  1340 #if 0 
  1341 static dlfunc_t SDL_OSX_dlfunc(void * dl_restrict handle, const char * dl_restrict symbol)
  1342 {
  1343 	union
  1344 	{
  1345 		void *d;
  1346 		dlfunc_t f;
  1347 	} rv;
  1348 	int sym_len = strlen(symbol);
  1349 	char *malloc_sym = NULL;
  1350 	dolock();
  1351 	malloc_sym = malloc(sym_len + 2);
  1352 	if (malloc_sym)
  1353 	{
  1354 		sprintf(malloc_sym, "_%s", symbol);
  1355 		rv.d = dlsymIntern(handle, malloc_sym, 1);
  1356 		free(malloc_sym);
  1357 	}
  1358 	else
  1359 	{
  1360 		error("Unable to allocate memory");
  1361 		goto dlfuncerror;
  1362 	}
  1363 	dounlock();
  1364 	return rv.f;
  1365   dlfuncerror:
  1366 	dounlock();
  1367 	return NULL;
  1368 }
  1369 #endif
  1370 
  1371 
  1372 
  1373 /* dlcompat ends, here's the SDL interface...  --ryan.  */
  1374 
  1375 
  1376 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  1377 /* System dependent library loading routines                           */
  1378 
  1379 #if !SDL_INTERNAL_BUILDING_LOADSO
  1380 #error Do not compile directly...compile src/SDL_loadso.c instead!
  1381 #endif
  1382 
  1383 #if !defined(MACOSX)
  1384 #error Compiling for the wrong platform?
  1385 #elif defined(USE_DLOPEN)
  1386 #error Do not use USE_DLOPEN on Mac OS X.
  1387 #endif
  1388 
  1389 #include "SDL_types.h"
  1390 #include "SDL_error.h"
  1391 #include "SDL_loadso.h"
  1392 
  1393 void *SDL_LoadObject(const char *sofile)
  1394 {
  1395 	void *handle = SDL_OSX_dlopen(sofile, RTLD_NOW);
  1396 	const char *loaderror = (char *)SDL_OSX_dlerror();
  1397 	if ( handle == NULL ) {
  1398 		SDL_SetError("Failed loading %s: %s", sofile, loaderror);
  1399 	}
  1400 	return(handle);
  1401 }
  1402 
  1403 void *SDL_LoadFunction(void *handle, const char *name)
  1404 {
  1405 	void *symbol = SDL_OSX_dlsym(handle, name);
  1406 	if ( symbol == NULL ) {
  1407 		SDL_SetError("Failed loading %s: %s", name, (const char *)SDL_OSX_dlerror());
  1408 	}
  1409 	return(symbol);
  1410 }
  1411 
  1412 void SDL_UnloadObject(void *handle)
  1413 {
  1414 	if ( handle != NULL ) {
  1415 		SDL_OSX_dlclose(handle);
  1416 	}
  1417 }
  1418 
  1419