comparison src/loadso/macosx/SDL_sysloadso.c @ 1361:19418e4422cb

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