comparison src/loadso/macosx/SDL_loadso.c @ 1173:e9cf8c1b4590

Split up src/SDL_loadso.c into platform directories.
author Ryan C. Gordon <icculus@icculus.org>
date Thu, 17 Nov 2005 03:15:05 +0000
parents
children 173c063d4f55
comparison
equal deleted inserted replaced
1172:f69f4d25fb20 1173:e9cf8c1b4590
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