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