📄 sdl_dlcompat.c
字号:
/* SDL - Simple DirectMedia Layer Copyright (C) 1997-2006 Sam Lantinga This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Sam Lantinga slouken@libsdl.org*/#include "SDL_config.h"#ifdef SDL_LOADSO_DLCOMPAT/* Please note that dlcompat apparently ships in current Mac OS X versions * as a system library that provides compatibility with the Unix "dlopen" * interface. In order to allow SDL to work on older OS X releases and also * not conflict with the system lib on newer versions, we include dlcompat * in SDL and change the symbols to prevent symbol clash with any existing * system libraries. --ryan. *//* here is the dlcompat license: *//*Copyright (c) 2002 Jorge Acereda <jacereda@users.sourceforge.net> & Peter O'Gorman <ogorman@users.sourceforge.net> Portions may be copyright others, see the AUTHORS file included with thisdistribution.Maintained by Peter O'Gorman <ogorman@users.sourceforge.net>Bug Reports and other queries should go to <ogorman@users.sourceforge.net>Permission is hereby granted, free of charge, to any person obtaininga copy of this software and associated documentation files (the"Software"), to deal in the Software without restriction, includingwithout limitation the rights to use, copy, modify, merge, publish,distribute, sublicense, and/or sell copies of the Software, and topermit persons to whom the Software is furnished to do so, subject tothe following conditions:The above copyright notice and this permission notice shall beincluded in all copies or substantial portions of the Software.THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OFMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE ANDNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BELIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTIONOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTIONWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.*/#include <pthread.h>#include <sys/types.h>#include <sys/stat.h>#include <stdarg.h>#include <limits.h>#include <mach-o/dyld.h>#include <mach-o/nlist.h>#include <mach-o/getsect.h>#include "SDL_stdinc.h"/* Just playing to see if it would compile with the freebsd headers, it does, * but because of the different values for RTLD_LOCAL etc, it would break binary * compat... oh well */#ifndef __BSD_VISIBLE#define __BSD_VISIBLE 1#endif/*include "dlfcn.h"*/#ifdef __cplusplusextern "C" {#endif#if defined (__GNUC__) && __GNUC__ > 3#define dl_restrict __restrict#else#define dl_restrict#endif#if 0#ifndef _POSIX_SOURCE/* * Structure filled in by dladdr(). */typedef struct SDL_OSX_dl_info { const char *dli_fname; /* Pathname of shared object */ void *dli_fbase; /* Base address of shared object */ const char *dli_sname; /* Name of nearest symbol */ void *dli_saddr; /* Address of nearest symbol */} SDL_OSX_Dl_info;static int SDL_OSX_dladdr(const void * dl_restrict, SDL_OSX_Dl_info * dl_restrict);#endif /* ! _POSIX_SOURCE */#endif /* 0 */static int SDL_OSX_dlclose(void * handle);static const char * SDL_OSX_dlerror(void);static void * SDL_OSX_dlopen(const char *path, int mode);static void * SDL_OSX_dlsym(void * dl_restrict handle, const char * dl_restrict symbol);#define RTLD_LAZY 0x1#define RTLD_NOW 0x2#define RTLD_LOCAL 0x4#define RTLD_GLOBAL 0x8#ifndef _POSIX_SOURCE#define RTLD_NOLOAD 0x10#define RTLD_NODELETE 0x80/* * Special handle arguments for SDL_OSX_dlsym(). */#define RTLD_NEXT ((void *) -1) /* Search subsequent objects. */#define RTLD_DEFAULT ((void *) -2) /* Use default search algorithm. */#endif /* ! _POSIX_SOURCE */#ifdef __cplusplus}#endif#ifndef dl_restrict#define dl_restrict __restrict#endif/* This is not available on 10.1 */#ifndef LC_LOAD_WEAK_DYLIB#define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD)#endif/* With this stuff here, this thing may actually compile/run on 10.0 systems * Not that I have a 10.0 system to test it on anylonger */#ifndef LC_REQ_DYLD#define LC_REQ_DYLD 0x80000000#endif#ifndef NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED#define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 0x4#endif#ifndef NSADDIMAGE_OPTION_RETURN_ON_ERROR#define NSADDIMAGE_OPTION_RETURN_ON_ERROR 0x1#endif#ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_BIND#define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND 0x0#endif#ifndef NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR#define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4#endif/* These symbols will be looked for in dyld */static const struct mach_header *(*dyld_NSAddImage) (const char *, unsigned long) = 0;static int (*dyld_NSIsSymbolNameDefinedInImage) (const struct mach_header *, const char *) = 0;static NSSymbol(*dyld_NSLookupSymbolInImage) (const struct mach_header *, const char *, unsigned long) = 0;/* Define this to make dlcompat reuse data block. This way in theory we save * a little bit of overhead. However we then couldn't correctly catch excess * calls to SDL_OSX_dlclose(). Hence we don't use this feature */#undef REUSE_STATUS/* Size of the internal error message buffer (used by dlerror()) */#define ERR_STR_LEN 251/* Maximum number of search paths supported by getSearchPath */#define MAX_SEARCH_PATHS 32#define MAGIC_DYLIB_OFI ((NSObjectFileImage) 'DYOF')#define MAGIC_DYLIB_MOD ((NSModule) 'DYMO')/* internal flags */#define DL_IN_LIST 0x01/* our mutex */static pthread_mutex_t dlcompat_mutex;/* Our thread specific storage */static pthread_key_t dlerror_key;struct dlthread{ int lockcnt; unsigned char errset; char errstr[ERR_STR_LEN];};/* This is our central data structure. Whenever a module is loaded via * SDL_OSX_dlopen(), we create such a struct. */struct dlstatus{ struct dlstatus *next; /* pointer to next element in the linked list */ NSModule module; const struct mach_header *lib; int refs; /* reference count */ int mode; /* mode in which this module was loaded */ dev_t device; ino_t inode; int flags; /* Any internal flags we may need */};/* Head node of the dlstatus list */static struct dlstatus mainStatus = { 0, MAGIC_DYLIB_MOD, NULL, -1, RTLD_GLOBAL, 0, 0, 0 };static struct dlstatus *stqueue = &mainStatus;/* Storage for the last error message (used by dlerror()) *//* static char err_str[ERR_STR_LEN]; *//* static int err_filled = 0; *//* Prototypes to internal functions */static void debug(const char *fmt, ...);static void error(const char *str, ...);static const char *safegetenv(const char *s);static const char *searchList(void);static const char *getSearchPath(int i);static const char *getFullPath(int i, const char *file);static const struct stat *findFile(const char *file, const char **fullPath);static int isValidStatus(struct dlstatus *status);static inline int isFlagSet(int mode, int flag);static struct dlstatus *lookupStatus(const struct stat *sbuf);static void insertStatus(struct dlstatus *dls, const struct stat *sbuf);static int promoteLocalToGlobal(struct dlstatus *dls);static void *reference(struct dlstatus *dls, int mode);static void *dlsymIntern(struct dlstatus *dls, const char *symbol, int canSetError);static struct dlstatus *allocStatus(void);static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, int mode);static NSSymbol search_linked_libs(const struct mach_header *mh, const char *symbol);static const char *get_lib_name(const struct mach_header *mh);static const struct mach_header *get_mach_header_from_NSModule(NSModule mod);static void dlcompat_init_func(void);static inline void dlcompat_init_check(void);static inline void dolock(void);static inline void dounlock(void);static void dlerrorfree(void *data);static void resetdlerror(void);static const struct mach_header *my_find_image(const char *name);static const struct mach_header *image_for_address(const void *address);static inline char *dyld_error_str(void);#if FINK_BUILD/* Two Global Functions */static void *dlsym_prepend_underscore(void *handle, const char *symbol);static void *dlsym_auto_underscore(void *handle, const char *symbol);/* And their _intern counterparts */static void *dlsym_prepend_underscore_intern(void *handle, const char *symbol);static void *dlsym_auto_underscore_intern(void *handle, const char *symbol);#endif/* Functions */static void debug(const char *fmt, ...){#if DEBUG > 1 va_list arg; va_start(arg, fmt); fprintf(stderr, "DLDEBUG: "); vfprintf(stderr, fmt, arg); fprintf(stderr, "\n"); fflush(stderr); va_end(arg);#endif}static void error(const char *str, ...){ va_list arg; struct dlthread *tss; char * err_str; va_start(arg, str); tss = pthread_getspecific(dlerror_key); err_str = tss->errstr; SDL_strlcpy(err_str, "dlcompat: ", ERR_STR_LEN); vsnprintf(err_str + 10, ERR_STR_LEN - 10, str, arg); va_end(arg); debug("ERROR: %s\n", err_str); tss->errset = 1;}static void warning(const char *str){#if DEBUG > 0 fprintf(stderr, "WARNING: dlcompat: %s\n", str);#endif}static const char *safegetenv(const char *s){ const char *ss = SDL_getenv(s); return ss ? ss : "";}/* because this is only used for debugging and error reporting functions, we * don't really care about how elegant it is... it could use the load * commands to find the install name of the library, but... */static const char *get_lib_name(const struct mach_header *mh){ unsigned long count = _dyld_image_count(); unsigned long i; const char *val = NULL; if (mh) { for (i = 0; i < count; i++) { if (mh == _dyld_get_image_header(i)) { val = _dyld_get_image_name(i); break; } } } return val;}/* Returns the mach_header for the module bu going through all the loaded images * and finding the one with the same name as the module. There really ought to be * an api for doing this, would be faster, but there isn't one right now */static const struct mach_header *get_mach_header_from_NSModule(NSModule mod){ const char *mod_name = NSNameOfModule(mod); const struct mach_header *mh = NULL; unsigned long count = _dyld_image_count(); unsigned long i; debug("Module name: %s", mod_name); for (i = 0; i < count; i++) { if (!SDL_strcmp(mod_name, _dyld_get_image_name(i))) { mh = _dyld_get_image_header(i); break; } } return mh;}/* Compute and return a list of all directories that we should search when * trying to locate a module. We first look at the values of LD_LIBRARY_PATH * and DYLD_LIBRARY_PATH, and then finally fall back to looking into * /usr/lib and /lib. Since both of the environments variables can contain a * list of colon seperated paths, we simply concat them and the two other paths * into one big string, which we then can easily parse. * Splitting this string into the actual path list is done by getSearchPath() */static const char *searchList(){ size_t buf_size; static char *buf=NULL; const char *ldlp = safegetenv("LD_LIBRARY_PATH"); const char *dyldlp = safegetenv("DYLD_LIBRARY_PATH"); const char *stdpath = SDL_getenv("DYLD_FALLBACK_LIBRARY_PATH"); if (!stdpath) stdpath = "/usr/local/lib:/lib:/usr/lib"; if (!buf) { buf_size = SDL_strlen(ldlp) + SDL_strlen(dyldlp) + SDL_strlen(stdpath) + 4; buf = SDL_malloc(buf_size); SDL_snprintf(buf, buf_size, "%s%s%s%s%s%c", dyldlp, (dyldlp[0] ? ":" : ""), ldlp, (ldlp[0] ? ":" : ""), stdpath, '\0'); } return buf;}/* Returns the ith search path from the list as computed by searchList() */static const char *getSearchPath(int i){ static const char *list = 0; static char **path = (char **)0; static int end = 0; static int numsize = MAX_SEARCH_PATHS; static char **tmp; /* So we can call SDL_free() in the "destructor" we use i=-1 to return the alloc'd array */ if (i == -1) { return (const char*)path; } if (!path) { path = (char **)SDL_calloc(MAX_SEARCH_PATHS, sizeof(char **)); } if (!list && !end) list = searchList(); if (i >= (numsize)) { debug("Increasing size for long PATH"); tmp = (char **)SDL_calloc((MAX_SEARCH_PATHS + numsize), sizeof(char **)); if (tmp) { SDL_memcpy(tmp, path, sizeof(char **) * numsize); SDL_free(path); path = tmp; numsize += MAX_SEARCH_PATHS; } else { return 0; } } while (!path[i] && !end) { path[i] = strsep((char **)&list, ":"); if (path[i][0] == 0) path[i] = 0; end = (list == 0); } return path[i];}static const char *getFullPath(int i, const char *file){ static char buf[PATH_MAX]; const char *path = getSearchPath(i); if (path) { SDL_snprintf(buf, PATH_MAX, "%s/%s", path, file); } return path ? buf : 0;}/* Given a file name, try to determine the full path for that file. Starts * its search in the current directory, and then tries all paths in the * search list in the order they are specified there. */static const struct stat *findFile(const char *file, const char **fullPath){ int i = 0; static struct stat sbuf; char *fileName; debug("finding file %s", file); *fullPath = file; if (0 == stat(file, &sbuf)) return &sbuf; if (SDL_strchr(file, '/')) return 0; /* If the path had a / we don't look in env var places */ fileName = NULL; if (!fileName) fileName = (char *)file; while ((*fullPath = getFullPath(i++, fileName))) { if (0 == stat(*fullPath, &sbuf)) return &sbuf; } ; return 0;}/* Determine whether a given dlstatus is valid or not */static int isValidStatus(struct dlstatus *status){ /* Walk the list to verify status is contained in it */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -