📄 sdl_dlcompat.c
字号:
struct dlstatus *dls = stqueue; while (dls && status != dls) dls = dls->next; if (dls == 0) error("invalid handle"); else if ((dls->module == 0) || (dls->refs == 0)) error("handle to closed library"); else return TRUE; return FALSE;}static inline int isFlagSet(int mode, int flag){ return (mode & flag) == flag;}static struct dlstatus *lookupStatus(const struct stat *sbuf){ struct dlstatus *dls = stqueue; debug("looking for status"); while (dls && ( /* isFlagSet(dls->mode, RTLD_UNSHARED) */ 0 || sbuf->st_dev != dls->device || sbuf->st_ino != dls->inode)) dls = dls->next; return dls;}static void insertStatus(struct dlstatus *dls, const struct stat *sbuf){ debug("inserting status"); dls->inode = sbuf->st_ino; dls->device = sbuf->st_dev; dls->refs = 0; dls->mode = 0; if ((dls->flags & DL_IN_LIST) == 0) { dls->next = stqueue; stqueue = dls; dls->flags |= DL_IN_LIST; }}static struct dlstatus *allocStatus(){ struct dlstatus *dls;#ifdef REUSE_STATUS dls = stqueue; while (dls && dls->module) dls = dls->next; if (!dls)#endif dls = SDL_calloc(sizeof(*dls),1); return dls;}static int promoteLocalToGlobal(struct dlstatus *dls){ static int (*p) (NSModule module) = 0; debug("promoting"); if (!p) _dyld_func_lookup("__dyld_NSMakePrivateModulePublic", (void **)&p); return (dls->module == MAGIC_DYLIB_MOD) || (p && p(dls->module));}static void *reference(struct dlstatus *dls, int mode){ if (dls) { if (dls->module == MAGIC_DYLIB_MOD && isFlagSet(mode, RTLD_LOCAL)) { warning("trying to open a .dylib with RTLD_LOCAL"); error("unable to open a .dylib with RTLD_LOCAL"); return NULL; } if (isFlagSet(mode, RTLD_GLOBAL) && !isFlagSet(dls->mode, RTLD_GLOBAL) && !promoteLocalToGlobal(dls)) { error("unable to promote local module to global"); return NULL; } dls->mode |= mode; dls->refs++; } else debug("reference called with NULL argument"); return dls;}static const struct mach_header *my_find_image(const char *name){ const struct mach_header *mh = 0; const char *id = NULL; int i = _dyld_image_count(); int j; mh = (struct mach_header *) dyld_NSAddImage(name, NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED | NSADDIMAGE_OPTION_RETURN_ON_ERROR); if (!mh) { for (j = 0; j < i; j++) { id = _dyld_get_image_name(j); if (!SDL_strcmp(id, name)) { mh = _dyld_get_image_header(j); break; } } } return mh;}/* * dyld adds libraries by first adding the directly dependant libraries in link order, and * then adding the dependencies for those libraries, so we should do the same... but we don't * bother adding the extra dependencies, if the symbols are neither in the loaded image nor * any of it's direct dependencies, then it probably isn't there. */static NSSymbol search_linked_libs(const struct mach_header * mh, const char *symbol){ unsigned int n; struct load_command *lc = 0; struct mach_header *wh; NSSymbol nssym = 0; if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage) { lc = (struct load_command *)((char *)mh + sizeof(struct mach_header)); for (n = 0; n < mh->ncmds; n++, lc = (struct load_command *)((char *)lc + lc->cmdsize)) { if ((LC_LOAD_DYLIB == lc->cmd) || (LC_LOAD_WEAK_DYLIB == lc->cmd)) { if ((wh = (struct mach_header *) my_find_image((char *)(((struct dylib_command *)lc)->dylib.name.offset + (char *)lc)))) { if (dyld_NSIsSymbolNameDefinedInImage(wh, symbol)) { nssym = dyld_NSLookupSymbolInImage(wh, symbol, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); break; } } } } if ((!nssym) && NSIsSymbolNameDefined(symbol)) { /* I've never seen this debug message...*/ debug("Symbol \"%s\" is defined but was not found", symbol); } } return nssym;}/* Up to the caller to SDL_free() returned string */static inline char *dyld_error_str(){ NSLinkEditErrors dylder; int dylderno; const char *dylderrstr; const char *dyldfile; char* retStr = NULL; NSLinkEditError(&dylder, &dylderno, &dyldfile, &dylderrstr); if (dylderrstr && *dylderrstr) { retStr = SDL_strdup(dylderrstr); } return retStr;}static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError){ NSSymbol nssym = 0;#ifdef __GCC__ void *caller = __builtin_return_address(1); /* Be *very* careful about inlining */#else void *caller = NULL;#endif const struct mach_header *caller_mh = 0; char *savedErrorStr = NULL; resetdlerror();#ifndef RTLD_SELF#define RTLD_SELF ((void *) -3)#endif if (NULL == dls) dls = RTLD_SELF; if ((RTLD_NEXT == dls) || (RTLD_SELF == dls)) { if (dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage && caller) { caller_mh = image_for_address(caller); if (RTLD_SELF == dls) { /* FIXME: We should be using the NSModule api, if SELF is an MH_BUNDLE * But it appears to work anyway, and looking at the code in dyld_libfuncs.c * this is acceptable. */ if (dyld_NSIsSymbolNameDefinedInImage(caller_mh, symbol)) { nssym = dyld_NSLookupSymbolInImage(caller_mh, symbol, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); } } if (!nssym) { if (RTLD_SELF == dls) savedErrorStr = dyld_error_str(); nssym = search_linked_libs(caller_mh, symbol); } } else { if (canSetError) error("RTLD_SELF and RTLD_NEXT are not supported"); return NULL; } } if (!nssym) { if (RTLD_DEFAULT == dls) { dls = &mainStatus; } if (!isValidStatus(dls)) return NULL; if (dls->module != MAGIC_DYLIB_MOD) { nssym = NSLookupSymbolInModule(dls->module, symbol); if (!nssym && NSIsSymbolNameDefined(symbol)) { debug("Searching dependencies"); savedErrorStr = dyld_error_str(); nssym = search_linked_libs(get_mach_header_from_NSModule(dls->module), symbol); } } else if (dls->lib && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage) { if (dyld_NSIsSymbolNameDefinedInImage(dls->lib, symbol)) { nssym = dyld_NSLookupSymbolInImage(dls->lib, symbol, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); } else if (NSIsSymbolNameDefined(symbol)) { debug("Searching dependencies"); savedErrorStr = dyld_error_str(); nssym = search_linked_libs(dls->lib, symbol); } } else if (dls->module == MAGIC_DYLIB_MOD) { /* Global context, use NSLookupAndBindSymbol */ if (NSIsSymbolNameDefined(symbol)) { /* There doesn't seem to be a return on error option for this call??? this is potentially broken, if binding fails, it will improperly exit the application. */ nssym = NSLookupAndBindSymbol(symbol); } else { if (savedErrorStr) SDL_free(savedErrorStr); savedErrorStr = SDL_malloc(256); SDL_snprintf(savedErrorStr, 256, "Symbol \"%s\" not in global context",symbol); } } } /* Error reporting */ if (!nssym) { if (!savedErrorStr || !SDL_strlen(savedErrorStr)) { if (savedErrorStr) SDL_free(savedErrorStr); savedErrorStr = SDL_malloc(256); SDL_snprintf(savedErrorStr, 256,"Symbol \"%s\" not found",symbol); } if (canSetError) { error(savedErrorStr); } else { debug(savedErrorStr); } if (savedErrorStr) SDL_free(savedErrorStr); return NULL; } return NSAddressOfSymbol(nssym);}static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode){ NSObjectFileImage ofi = 0; NSObjectFileImageReturnCode ofirc; struct dlstatus *dls; NSLinkEditErrors ler; int lerno; const char *errstr; const char *file; void (*init) (void); ofirc = NSCreateObjectFileImageFromFile(path, &ofi); switch (ofirc) { case NSObjectFileImageSuccess: break; case NSObjectFileImageInappropriateFile: if (dyld_NSAddImage && dyld_NSIsSymbolNameDefinedInImage && dyld_NSLookupSymbolInImage) { if (isFlagSet(mode, RTLD_LOCAL)) { warning("trying to open a .dylib with RTLD_LOCAL"); error("unable to open this file with RTLD_LOCAL"); return NULL; } } else { error("opening this file is unsupported on this system"); return NULL; } break; case NSObjectFileImageFailure: error("object file setup failure"); return NULL; case NSObjectFileImageArch: error("no object for this architecture"); return NULL; case NSObjectFileImageFormat: error("bad object file format"); return NULL; case NSObjectFileImageAccess: error("can't read object file"); return NULL; default: error("unknown error from NSCreateObjectFileImageFromFile()"); return NULL; } dls = lookupStatus(sbuf); if (!dls) { dls = allocStatus(); } if (!dls) { error("unable to allocate memory"); return NULL; } // dls->lib = 0; if (ofirc == NSObjectFileImageInappropriateFile) { if ((dls->lib = dyld_NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR))) { debug("Dynamic lib loaded at %ld", dls->lib); ofi = MAGIC_DYLIB_OFI; dls->module = MAGIC_DYLIB_MOD; ofirc = NSObjectFileImageSuccess; /* Although it is possible with a bit of work to modify this so it works and functions with RTLD_NOW, I don't deem it necessary at the moment */ } if (!(dls->module)) { NSLinkEditError(&ler, &lerno, &file, &errstr); if (!errstr || (!SDL_strlen(errstr))) error("Can't open this file type"); else error(errstr); if ((dls->flags & DL_IN_LIST) == 0) { SDL_free(dls); } return NULL; } } else { dls->module = NSLinkModule(ofi, path, NSLINKMODULE_OPTION_RETURN_ON_ERROR | NSLINKMODULE_OPTION_PRIVATE | (isFlagSet(mode, RTLD_NOW) ? NSLINKMODULE_OPTION_BINDNOW : 0)); NSDestroyObjectFileImage(ofi); if (dls->module) { dls->lib = get_mach_header_from_NSModule(dls->module); } } if (!dls->module) { NSLinkEditError(&ler, &lerno, &file, &errstr); if ((dls->flags & DL_IN_LIST) == 0) { SDL_free(dls); } error(errstr); return NULL; } insertStatus(dls, sbuf); dls = reference(dls, mode); if ((init = dlsymIntern(dls, "__init", 0))) { debug("calling _init()"); init(); } return dls;}inline static void dlcompat_init_check(void){ static pthread_mutex_t l = PTHREAD_MUTEX_INITIALIZER; static int init_done = 0; pthread_mutex_lock(&l); if (!init_done) { dlcompat_init_func(); init_done = 1; } pthread_mutex_unlock(&l);}static void dlcompat_init_func(void){ _dyld_func_lookup("__dyld_NSAddImage", (void **)&dyld_NSAddImage); _dyld_func_lookup("__dyld_NSIsSymbolNameDefinedInImage", (void **)&dyld_NSIsSymbolNameDefinedInImage); _dyld_func_lookup("__dyld_NSLookupSymbolInImage", (void **)&dyld_NSLookupSymbolInImage); if (pthread_mutex_init(&dlcompat_mutex, NULL)) exit(1); if (pthread_key_create(&dlerror_key, &dlerrorfree)) exit(1);}static void resetdlerror(){ struct dlthread *tss; tss = pthread_getspecific(dlerror_key); tss->errset = 0;}static void dlerrorfree(void *data){ SDL_free(data);}/* We kind of want a recursive lock here, but meet a little trouble * because they are not available pre OS X 10.2, so we fake it * using thread specific storage to keep a lock count */ static inline void dolock(void){ int err = 0; struct dlthread *tss; dlcompat_init_check(); tss = pthread_getspecific(dlerror_key); if (!tss) { tss = SDL_malloc(sizeof(struct dlthread)); tss->lockcnt = 0; tss->errset = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -