tclLoadDyld.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:22k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * tclLoadDyld.c --
  3.  *
  4.  * This procedure provides a version of the TclLoadFile that works with
  5.  * Apple's dyld dynamic loading.
  6.  * Original version of his file (superseded long ago) provided by
  7.  * Wilfredo Sanchez (wsanchez@apple.com).
  8.  *
  9.  * Copyright (c) 1995 Apple Computer, Inc.
  10.  * Copyright (c) 2001-2007 Daniel A. Steffen <das@users.sourceforge.net>
  11.  *
  12.  * See the file "license.terms" for information on usage and redistribution of
  13.  * this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14.  *
  15.  * RCS: @(#) $Id: tclLoadDyld.c,v 1.14.2.11 2007/09/05 01:38:55 das Exp $
  16.  */
  17. #include "tclInt.h"
  18. #include "tclPort.h"
  19. #ifndef MODULE_SCOPE
  20. #define MODULE_SCOPE extern
  21. #endif
  22. #ifndef TCL_DYLD_USE_DLFCN
  23. /*
  24.  * Use preferred dlfcn API on 10.4 and later
  25.  */
  26. #   if !defined(NO_DLFCN_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1040
  27. # define TCL_DYLD_USE_DLFCN 1
  28. #   else
  29. # define TCL_DYLD_USE_DLFCN 0
  30. #   endif
  31. #endif
  32. #ifndef TCL_DYLD_USE_NSMODULE
  33. /*
  34.  * Use deprecated NSModule API only to support 10.3 and earlier:
  35.  */
  36. #   if MAC_OS_X_VERSION_MIN_REQUIRED < 1040
  37. # define TCL_DYLD_USE_NSMODULE 1
  38. #   else
  39. # define TCL_DYLD_USE_NSMODULE 0
  40. #   endif
  41. #endif
  42. #if TCL_DYLD_USE_DLFCN
  43. #include <dlfcn.h>
  44. #if defined(HAVE_WEAK_IMPORT) && MAC_OS_X_VERSION_MIN_REQUIRED < 1040
  45. /*
  46.  * Support for weakly importing dlfcn API.
  47.  */
  48. extern void *dlopen(const char *path, int mode) WEAK_IMPORT_ATTRIBUTE;
  49. extern void *dlsym(void *handle, const char *symbol) WEAK_IMPORT_ATTRIBUTE;
  50. extern int dlclose(void *handle) WEAK_IMPORT_ATTRIBUTE;
  51. extern char *dlerror(void) WEAK_IMPORT_ATTRIBUTE;
  52. #endif
  53. #endif
  54. #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY)
  55. #include <mach-o/dyld.h>
  56. #include <mach-o/fat.h>
  57. #include <mach-o/swap.h>
  58. #include <mach-o/arch.h>
  59. #include <libkern/OSByteOrder.h>
  60. #undef panic
  61. #include <mach/mach.h>
  62. #include <stdbool.h>
  63. typedef struct Tcl_DyldModuleHandle {
  64.     struct Tcl_DyldModuleHandle *nextPtr;
  65.     NSModule module;
  66. } Tcl_DyldModuleHandle;
  67. #endif /* TCL_DYLD_USE_NSMODULE */
  68. typedef struct Tcl_DyldLoadHandle {
  69. #if TCL_DYLD_USE_DLFCN
  70.     void *dlHandle;
  71. #endif
  72. #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY)
  73.     const struct mach_header *dyldLibHeader;
  74.     Tcl_DyldModuleHandle *modulePtr;
  75. #endif
  76. } Tcl_DyldLoadHandle;
  77. #if (TCL_DYLD_USE_DLFCN && MAC_OS_X_VERSION_MIN_REQUIRED < 1040) || 
  78. defined(TCL_LOAD_FROM_MEMORY)
  79. MODULE_SCOPE long tclMacOSXDarwinRelease;
  80. #endif
  81. #ifdef TCL_DEBUG_LOAD
  82. #define TclLoadDbgMsg(m, ...) do { 
  83.     fprintf(stderr, "%s:%d: %s(): " m ".n", 
  84.     strrchr(__FILE__, '/')+1, __LINE__, __func__, ##__VA_ARGS__); 
  85. } while (0)
  86. #else
  87. #define TclLoadDbgMsg(m, ...)
  88. #endif
  89. #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY)
  90. /*
  91.  *----------------------------------------------------------------------
  92.  *
  93.  * DyldOFIErrorMsg --
  94.  *
  95.  * Converts a numerical NSObjectFileImage error into an error message
  96.  * string.
  97.  *
  98.  * Results:
  99.  * Error message string.
  100.  *
  101.  * Side effects:
  102.  * None.
  103.  *
  104.  *----------------------------------------------------------------------
  105.  */
  106. static CONST char*
  107. DyldOFIErrorMsg(
  108.     int err)
  109. {
  110.     switch(err) {
  111.     case NSObjectFileImageSuccess:
  112. return NULL;
  113.     case NSObjectFileImageFailure:
  114. return "object file setup failure";
  115.     case NSObjectFileImageInappropriateFile:
  116. return "not a Mach-O MH_BUNDLE file";
  117.     case NSObjectFileImageArch:
  118. return "no object for this architecture";
  119.     case NSObjectFileImageFormat:
  120. return "bad object file format";
  121.     case NSObjectFileImageAccess:
  122. return "can't read object file";
  123.     default:
  124. return "unknown error";
  125.     }
  126. }
  127. #endif /* TCL_DYLD_USE_NSMODULE */
  128. /*
  129.  *----------------------------------------------------------------------
  130.  *
  131.  * TclpDlopen --
  132.  *
  133.  * Dynamically loads a binary code file into memory and returns a handle
  134.  * to the new code.
  135.  *
  136.  * Results:
  137.  * A standard Tcl completion code. If an error occurs, an error message
  138.  * is left in the interpreter's result.
  139.  *
  140.  * Side effects:
  141.  * New code suddenly appears in memory.
  142.  *
  143.  *----------------------------------------------------------------------
  144.  */
  145. MODULE_SCOPE int
  146. TclpDlopen(
  147.     Tcl_Interp *interp, /* Used for error reporting. */
  148.     Tcl_Obj *pathPtr, /* Name of the file containing the desired
  149.  * code (UTF-8). */
  150.     Tcl_LoadHandle *loadHandle, /* Filled with token for dynamically loaded
  151.  * file which will be passed back to
  152.  * (*unloadProcPtr)() to unload the file. */
  153.     Tcl_FSUnloadFileProc **unloadProcPtr)
  154. /* Filled with address of Tcl_FSUnloadFileProc
  155.  * function which should be used for this
  156.  * file. */
  157. {
  158.     Tcl_DyldLoadHandle *dyldLoadHandle;
  159. #if TCL_DYLD_USE_DLFCN
  160.     void *dlHandle = NULL;
  161. #endif
  162. #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY)
  163.     const struct mach_header *dyldLibHeader = NULL;
  164.     Tcl_DyldModuleHandle *modulePtr = NULL;
  165. #endif
  166. #if TCL_DYLD_USE_NSMODULE
  167.     NSLinkEditErrors editError;
  168.     int errorNumber;
  169.     const char *errorName, *objFileImageErrMsg = NULL;
  170. #endif
  171.     const char *errMsg = NULL;
  172.     int result;
  173.     Tcl_DString ds;
  174.     char *fileName = NULL;
  175.     const char *nativePath, *nativeFileName = NULL;
  176.     /*
  177.      * First try the full path the user gave us. This is particularly
  178.      * important if the cwd is inside a vfs, and we are trying to load using a
  179.      * relative path.
  180.      */
  181.     nativePath = Tcl_FSGetNativePath(pathPtr);
  182. #if TCL_DYLD_USE_DLFCN
  183. #if MAC_OS_X_VERSION_MIN_REQUIRED < 1040
  184.     if (tclMacOSXDarwinRelease >= 8)
  185. #endif
  186.     {
  187. dlHandle = dlopen(nativePath, RTLD_NOW | RTLD_LOCAL);
  188. if (!dlHandle) {
  189.     /*
  190.      * Let the OS loader examine the binary search path for whatever
  191.      * string the user gave us which hopefully refers to a file on the
  192.      * binary path.
  193.      */
  194.     fileName = Tcl_GetString(pathPtr);
  195.     nativeFileName = Tcl_UtfToExternalDString(NULL, fileName, -1, &ds);
  196.     dlHandle = dlopen(nativeFileName, RTLD_NOW | RTLD_LOCAL);
  197. }
  198. if (dlHandle) {
  199.     TclLoadDbgMsg("dlopen() successful");
  200. } else {
  201.     errMsg = dlerror();
  202.     TclLoadDbgMsg("dlopen() failed: %s", errMsg);
  203. }
  204.     }
  205.     if (!dlHandle)
  206. #endif /* TCL_DYLD_USE_DLFCN */
  207.     {
  208. #if TCL_DYLD_USE_NSMODULE
  209. dyldLibHeader = NSAddImage(nativePath,
  210. NSADDIMAGE_OPTION_RETURN_ON_ERROR);
  211. if (dyldLibHeader) {
  212.     TclLoadDbgMsg("NSAddImage() successful");
  213. } else {
  214.     NSLinkEditError(&editError, &errorNumber, &errorName, &errMsg);
  215.     if (editError == NSLinkEditFileAccessError) {
  216. /*
  217.  * The requested file was not found. Let the OS loader examine
  218.  * the binary search path for whatever string the user gave us
  219.  * which hopefully refers to a file on the binary path.
  220.  */
  221. if (!fileName) {
  222.     fileName = Tcl_GetString(pathPtr);
  223.     nativeFileName = Tcl_UtfToExternalDString(NULL, fileName,
  224.     -1, &ds);
  225. }
  226. dyldLibHeader = NSAddImage(nativeFileName,
  227. NSADDIMAGE_OPTION_WITH_SEARCHING |
  228. NSADDIMAGE_OPTION_RETURN_ON_ERROR);
  229. if (dyldLibHeader) {
  230.     TclLoadDbgMsg("NSAddImage() successful");
  231. } else {
  232.     NSLinkEditError(&editError, &errorNumber, &errorName,
  233.     &errMsg);
  234.     TclLoadDbgMsg("NSAddImage() failed: %s", errMsg);
  235. }
  236.     } else if ((editError == NSLinkEditFileFormatError
  237.     && errorNumber == EBADMACHO)
  238.     || editError == NSLinkEditOtherError){
  239. NSObjectFileImageReturnCode err;
  240. NSObjectFileImage dyldObjFileImage;
  241. NSModule module;
  242. /*
  243.  * The requested file was found but was not of type MH_DYLIB,
  244.  * attempt to load it as a MH_BUNDLE.
  245.  */
  246. err = NSCreateObjectFileImageFromFile(nativePath,
  247. &dyldObjFileImage);
  248. if (err == NSObjectFileImageSuccess && dyldObjFileImage) {
  249.     TclLoadDbgMsg("NSCreateObjectFileImageFromFile() "
  250.     "successful");
  251.     module = NSLinkModule(dyldObjFileImage, nativePath,
  252.     NSLINKMODULE_OPTION_BINDNOW
  253.     | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
  254.     NSDestroyObjectFileImage(dyldObjFileImage);
  255.     if (module) {
  256. modulePtr = (Tcl_DyldModuleHandle *)
  257. ckalloc(sizeof(Tcl_DyldModuleHandle));
  258. modulePtr->module = module;
  259. modulePtr->nextPtr = NULL;
  260. TclLoadDbgMsg("NSLinkModule() successful");
  261.     } else {
  262. NSLinkEditError(&editError, &errorNumber, &errorName,
  263. &errMsg);
  264. TclLoadDbgMsg("NSLinkModule() failed: %s", errMsg);
  265.     }
  266. } else {
  267.     objFileImageErrMsg = DyldOFIErrorMsg(err);
  268.     TclLoadDbgMsg("NSCreateObjectFileImageFromFile() failed: "
  269.     "%s", objFileImageErrMsg);
  270. }
  271.     }
  272. }
  273. #endif /* TCL_DYLD_USE_NSMODULE */
  274.     }
  275.     if (0
  276. #if TCL_DYLD_USE_DLFCN
  277.     || dlHandle
  278. #endif
  279. #if TCL_DYLD_USE_NSMODULE
  280.     || dyldLibHeader || modulePtr
  281. #endif
  282.     ) {
  283. dyldLoadHandle = (Tcl_DyldLoadHandle *)
  284. ckalloc(sizeof(Tcl_DyldLoadHandle));
  285. #if TCL_DYLD_USE_DLFCN
  286. dyldLoadHandle->dlHandle = dlHandle;
  287. #endif
  288. #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY)
  289. dyldLoadHandle->dyldLibHeader = dyldLibHeader;
  290. dyldLoadHandle->modulePtr = modulePtr;
  291. #endif
  292. *loadHandle = (Tcl_LoadHandle) dyldLoadHandle;
  293. *unloadProcPtr = &TclpUnloadFile;
  294. result = TCL_OK;
  295.     } else {
  296. Tcl_AppendResult(interp, errMsg, NULL);
  297. #if TCL_DYLD_USE_NSMODULE
  298. if (objFileImageErrMsg) {
  299.     Tcl_AppendResult(interp, "nNSCreateObjectFileImageFromFile() "
  300.     "error: ", objFileImageErrMsg, NULL);
  301. }
  302. #endif
  303. result = TCL_ERROR;
  304.     }
  305.     if(fileName) {
  306. Tcl_DStringFree(&ds);
  307.     }
  308.     return result;
  309. }
  310. /*
  311.  *----------------------------------------------------------------------
  312.  *
  313.  * TclpFindSymbol --
  314.  *
  315.  * Looks up a symbol, by name, through a handle associated with a
  316.  * previously loaded piece of code (shared library).
  317.  *
  318.  * Results:
  319.  * Returns a pointer to the function associated with 'symbol' if it is
  320.  * found. Otherwise returns NULL and may leave an error message in the
  321.  * interp's result.
  322.  *
  323.  *----------------------------------------------------------------------
  324.  */
  325. MODULE_SCOPE Tcl_PackageInitProc *
  326. TclpFindSymbol(
  327.     Tcl_Interp *interp, /* For error reporting. */
  328.     Tcl_LoadHandle loadHandle, /* Handle from TclpDlopen. */
  329.     CONST char *symbol) /* Symbol name to look up. */
  330. {
  331.     Tcl_DyldLoadHandle *dyldLoadHandle = (Tcl_DyldLoadHandle *) loadHandle;
  332.     Tcl_PackageInitProc *proc = NULL;
  333.     const char *errMsg = NULL;
  334.     Tcl_DString ds;
  335.     const char *native;
  336.     native = Tcl_UtfToExternalDString(NULL, symbol, -1, &ds);
  337. #if TCL_DYLD_USE_DLFCN
  338.     if (dyldLoadHandle->dlHandle) {
  339. proc = dlsym(dyldLoadHandle->dlHandle, native);
  340. if (proc) {
  341.     TclLoadDbgMsg("dlsym() successful");
  342. } else {
  343.     errMsg = dlerror();
  344.     TclLoadDbgMsg("dlsym() failed: %s", errMsg);
  345. }
  346.     } else
  347. #endif /* TCL_DYLD_USE_DLFCN */
  348.     {
  349. #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY)
  350. NSSymbol nsSymbol = NULL;
  351. Tcl_DString newName;
  352. /*
  353.  * dyld adds an underscore to the beginning of symbol names.
  354.  */
  355. Tcl_DStringInit(&newName);
  356. Tcl_DStringAppend(&newName, "_", 1);
  357. native = Tcl_DStringAppend(&newName, native, -1);
  358. if (dyldLoadHandle->dyldLibHeader) {
  359.     nsSymbol = NSLookupSymbolInImage(dyldLoadHandle->dyldLibHeader,
  360.     native, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW |
  361.     NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
  362.     if (nsSymbol) {
  363. TclLoadDbgMsg("NSLookupSymbolInImage() successful");
  364. #ifdef DYLD_SUPPORTS_DYLIB_UNLOADING
  365. /*
  366.  * Until dyld supports unloading of MY_DYLIB binaries, the
  367.  * following is not needed.
  368.  */
  369. NSModule module = NSModuleForSymbol(nsSymbol);
  370. Tcl_DyldModuleHandle *modulePtr = dyldLoadHandle->modulePtr;
  371. while (modulePtr != NULL) {
  372.     if (module == modulePtr->module) {
  373. break;
  374.     }
  375.     modulePtr = modulePtr->nextPtr;
  376. }
  377. if (modulePtr == NULL) {
  378.     modulePtr = (Tcl_DyldModuleHandle *)
  379.     ckalloc(sizeof(Tcl_DyldModuleHandle));
  380.     modulePtr->module = module;
  381.     modulePtr->nextPtr = dyldLoadHandle->modulePtr;
  382.     dyldLoadHandle->modulePtr = modulePtr;
  383. }
  384. #endif /* DYLD_SUPPORTS_DYLIB_UNLOADING */
  385.     } else {
  386. NSLinkEditErrors editError;
  387. int errorNumber;
  388. const char *errorName;
  389. NSLinkEditError(&editError, &errorNumber, &errorName, &errMsg);
  390. TclLoadDbgMsg("NSLookupSymbolInImage() failed: %s", errMsg);
  391.     }
  392. } else if (dyldLoadHandle->modulePtr) {
  393.     nsSymbol = NSLookupSymbolInModule(
  394.     dyldLoadHandle->modulePtr->module, native);
  395.     if (nsSymbol) {
  396. TclLoadDbgMsg("NSLookupSymbolInModule() successful");
  397.     } else {
  398. TclLoadDbgMsg("NSLookupSymbolInModule() failed");
  399.     }
  400. }
  401. if (nsSymbol) {
  402.     proc = NSAddressOfSymbol(nsSymbol);
  403.     if (proc) {
  404. TclLoadDbgMsg("NSAddressOfSymbol() successful");
  405.     } else {
  406. TclLoadDbgMsg("NSAddressOfSymbol() failed");
  407.     }
  408. }
  409. Tcl_DStringFree(&newName);
  410. #endif /* TCL_DYLD_USE_NSMODULE */
  411.     }
  412.     Tcl_DStringFree(&ds);
  413.     if (errMsg) {
  414. Tcl_AppendResult(interp, errMsg, NULL);
  415.     }
  416.     return proc;
  417. }
  418. /*
  419.  *----------------------------------------------------------------------
  420.  *
  421.  * TclpUnloadFile --
  422.  *
  423.  * Unloads a dynamically loaded binary code file from memory. Code
  424.  * pointers in the formerly loaded file are no longer valid after calling
  425.  * this function.
  426.  *
  427.  * Results:
  428.  * None.
  429.  *
  430.  * Side effects:
  431.  * Code dissapears from memory. Note that dyld currently only supports
  432.  * unloading of binaries of type MH_BUNDLE loaded with NSLinkModule() in
  433.  * TclpDlopen() above.
  434.  *
  435.  *----------------------------------------------------------------------
  436.  */
  437. MODULE_SCOPE void
  438. TclpUnloadFile(
  439.     Tcl_LoadHandle loadHandle) /* loadHandle returned by a previous call to
  440.  * TclpDlopen(). The loadHandle is a token
  441.  * that represents the loaded file. */
  442. {
  443.     Tcl_DyldLoadHandle *dyldLoadHandle = (Tcl_DyldLoadHandle *) loadHandle;
  444. #if TCL_DYLD_USE_DLFCN
  445.     if (dyldLoadHandle->dlHandle) {
  446. int result;
  447. result = dlclose(dyldLoadHandle->dlHandle);
  448. if (!result) {
  449.     TclLoadDbgMsg("dlclose() successful");
  450. } else {
  451.     TclLoadDbgMsg("dlclose() failed: %s", dlerror());
  452. }
  453.     } else
  454. #endif /* TCL_DYLD_USE_DLFCN */
  455.     {
  456. #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY)
  457. Tcl_DyldModuleHandle *modulePtr = dyldLoadHandle->modulePtr;
  458. while (modulePtr != NULL) {
  459.     void *ptr;
  460.     bool result;
  461.     result = NSUnLinkModule(modulePtr->module,
  462.     NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES);
  463.     if (result) {
  464. TclLoadDbgMsg("NSUnLinkModule() successful");
  465.     } else {
  466. TclLoadDbgMsg("NSUnLinkModule() failed");
  467.     }
  468.     ptr = modulePtr;
  469.     modulePtr = modulePtr->nextPtr;
  470.     ckfree(ptr);
  471. }
  472. #endif /* TCL_DYLD_USE_NSMODULE */
  473.     }
  474.     ckfree((char*) dyldLoadHandle);
  475. }
  476. /*
  477.  *----------------------------------------------------------------------
  478.  *
  479.  * TclGuessPackageName --
  480.  *
  481.  * If the "load" command is invoked without providing a package name,
  482.  * this procedure is invoked to try to figure it out.
  483.  *
  484.  * Results:
  485.  * Always returns 0 to indicate that we couldn't figure out a package
  486.  * name; generic code will then try to guess the package from the file
  487.  * name. A return value of 1 would have meant that we figured out the
  488.  * package name and put it in bufPtr.
  489.  *
  490.  * Side effects:
  491.  * None.
  492.  *
  493.  *----------------------------------------------------------------------
  494.  */
  495. int
  496. TclGuessPackageName(
  497.     CONST char *fileName, /* Name of file containing package (already
  498.  * translated to local form if needed). */
  499.     Tcl_DString *bufPtr) /* Initialized empty dstring. Append package
  500.  * name to this if possible. */
  501. {
  502.     return 0;
  503. }
  504. #ifdef TCL_LOAD_FROM_MEMORY
  505. /*
  506.  *----------------------------------------------------------------------
  507.  *
  508.  * TclpLoadMemoryGetBuffer --
  509.  *
  510.  * Allocate a buffer that can be used with TclpLoadMemory() below.
  511.  *
  512.  * Results:
  513.  * Pointer to allocated buffer or NULL if an error occurs.
  514.  *
  515.  * Side effects:
  516.  * Buffer is allocated.
  517.  *
  518.  *----------------------------------------------------------------------
  519.  */
  520. MODULE_SCOPE void *
  521. TclpLoadMemoryGetBuffer(
  522.     Tcl_Interp *interp, /* Used for error reporting. */
  523.     int size) /* Size of desired buffer. */
  524. {
  525.     void *buffer = NULL;
  526.     /*
  527.      * NSCreateObjectFileImageFromMemory is available but always fails
  528.      * prior to Darwin 7.
  529.      */
  530.     if (tclMacOSXDarwinRelease >= 7) {
  531. /*
  532.  * We must allocate the buffer using vm_allocate, because
  533.  * NSCreateObjectFileImageFromMemory will dispose of it using
  534.  * vm_deallocate.
  535.  */
  536. if (vm_allocate(mach_task_self(), (vm_address_t *) &buffer, size, 1)) {
  537.     buffer = NULL;
  538. }
  539.     }
  540.     return buffer;
  541. }
  542. /*
  543.  *----------------------------------------------------------------------
  544.  *
  545.  * TclpLoadMemory --
  546.  *
  547.  * Dynamically loads binary code file from memory and returns a handle to
  548.  * the new code.
  549.  *
  550.  * Results:
  551.  * A standard Tcl completion code. If an error occurs, an error message
  552.  * is left in the interpreter's result.
  553.  *
  554.  * Side effects:
  555.  * New code is loaded from memory.
  556.  *
  557.  *----------------------------------------------------------------------
  558.  */
  559. MODULE_SCOPE int
  560. TclpLoadMemory(
  561.     Tcl_Interp *interp, /* Used for error reporting. */
  562.     void *buffer, /* Buffer containing the desired code
  563.  * (allocated with TclpLoadMemoryGetBuffer). */
  564.     int size, /* Allocation size of buffer. */
  565.     int codeSize, /* Size of code data read into buffer or -1 if
  566.  * an error occurred and the buffer should
  567.  * just be freed. */
  568.     Tcl_LoadHandle *loadHandle, /* Filled with token for dynamically loaded
  569.  * file which will be passed back to
  570.  * (*unloadProcPtr)() to unload the file. */
  571.     Tcl_FSUnloadFileProc **unloadProcPtr)
  572. /* Filled with address of Tcl_FSUnloadFileProc
  573.  * function which should be used for this
  574.  * file. */
  575. {
  576.     Tcl_DyldLoadHandle *dyldLoadHandle;
  577.     NSObjectFileImage dyldObjFileImage = NULL;
  578.     Tcl_DyldModuleHandle *modulePtr;
  579.     NSModule module;
  580.     const char *objFileImageErrMsg = NULL;
  581.     /*
  582.      * Try to create an object file image that we can load from.
  583.      */
  584.     if (codeSize >= 0) {
  585. NSObjectFileImageReturnCode err = NSObjectFileImageSuccess;
  586. const struct fat_header *fh = buffer;
  587. uint32_t ms = 0;
  588. #ifndef __LP64__
  589. const struct mach_header *mh = NULL;
  590. #define mh_size  sizeof(struct mach_header)
  591. #define mh_magic MH_MAGIC
  592. #define arch_abi 0
  593. #else
  594. const struct mach_header_64 *mh = NULL;
  595. #define mh_size  sizeof(struct mach_header_64)
  596. #define mh_magic MH_MAGIC_64
  597. #define arch_abi CPU_ARCH_ABI64
  598. #endif
  599. if ((size_t) codeSize >= sizeof(struct fat_header)
  600. && fh->magic == OSSwapHostToBigInt32(FAT_MAGIC)) {
  601.     uint32_t fh_nfat_arch = OSSwapBigToHostInt32(fh->nfat_arch);
  602.     /*
  603.      * Fat binary, try to find mach_header for our architecture
  604.      */
  605.     TclLoadDbgMsg("Fat binary, %d archs", fh_nfat_arch);
  606.     if ((size_t) codeSize >= sizeof(struct fat_header) +
  607.     fh_nfat_arch * sizeof(struct fat_arch)) {
  608. void *fatarchs = (char*)buffer + sizeof(struct fat_header);
  609. const NXArchInfo *arch = NXGetLocalArchInfo();
  610. struct fat_arch *fa;
  611. if (fh->magic != FAT_MAGIC) {
  612.     swap_fat_arch(fatarchs, fh_nfat_arch, arch->byteorder);
  613. }
  614. fa = NXFindBestFatArch(arch->cputype | arch_abi,
  615. arch->cpusubtype, fatarchs, fh_nfat_arch);
  616. if (fa) {
  617.     TclLoadDbgMsg("NXFindBestFatArch() successful: "
  618.     "local cputype %d subtype %d, "
  619.     "fat cputype %d subtype %d",
  620.     arch->cputype | arch_abi, arch->cpusubtype,
  621.     fa->cputype, fa->cpusubtype);
  622.     mh = (void*)((char*)buffer + fa->offset);
  623.     ms = fa->size;
  624. } else {
  625.     TclLoadDbgMsg("NXFindBestFatArch() failed");
  626.     err = NSObjectFileImageInappropriateFile;
  627. }
  628. if (fh->magic != FAT_MAGIC) {
  629.     swap_fat_arch(fatarchs, fh_nfat_arch, arch->byteorder);
  630. }
  631.     } else {
  632. TclLoadDbgMsg("Fat binary header failure");
  633. err = NSObjectFileImageInappropriateFile;
  634.     }
  635. } else {
  636.     /*
  637.      * Thin binary
  638.      */
  639.     TclLoadDbgMsg("Thin binary");
  640.     mh = buffer;
  641.     ms = codeSize;
  642. }
  643. if (ms && !(ms >= mh_size && mh->magic == mh_magic &&
  644.  mh->filetype == MH_BUNDLE)) {
  645.     TclLoadDbgMsg("Inappropriate file: magic %x filetype %d",
  646.     mh->magic, mh->filetype);
  647.     err = NSObjectFileImageInappropriateFile;
  648. }
  649. if (err == NSObjectFileImageSuccess) {
  650.     err = NSCreateObjectFileImageFromMemory(buffer, codeSize,
  651.     &dyldObjFileImage);
  652.     if (err == NSObjectFileImageSuccess) {
  653. TclLoadDbgMsg("NSCreateObjectFileImageFromMemory() "
  654. "successful");
  655.     } else {
  656. objFileImageErrMsg = DyldOFIErrorMsg(err);
  657. TclLoadDbgMsg("NSCreateObjectFileImageFromMemory() failed: %s",
  658. objFileImageErrMsg);
  659.     }
  660. } else {
  661.     objFileImageErrMsg = DyldOFIErrorMsg(err);
  662. }
  663.     }
  664.     /*
  665.      * If it went wrong (or we were asked to just deallocate), get rid of the
  666.      * memory block and create an error message.
  667.      */
  668.     if (dyldObjFileImage == NULL) {
  669. vm_deallocate(mach_task_self(), (vm_address_t) buffer, size);
  670. if (objFileImageErrMsg != NULL) {
  671.     Tcl_AppendResult(interp, "NSCreateObjectFileImageFromMemory() "
  672.     "error: ", objFileImageErrMsg, NULL);
  673. }
  674. return TCL_ERROR;
  675.     }
  676.     /*
  677.      * Extract the module we want from the image of the object file.
  678.      */
  679.     module = NSLinkModule(dyldObjFileImage, "[Memory Based Bundle]",
  680.     NSLINKMODULE_OPTION_BINDNOW | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
  681.     NSDestroyObjectFileImage(dyldObjFileImage);
  682.     if (module) {
  683. TclLoadDbgMsg("NSLinkModule() successful");
  684.     } else {
  685. NSLinkEditErrors editError;
  686. int errorNumber;
  687. const char *errorName, *errMsg;
  688. NSLinkEditError(&editError, &errorNumber, &errorName, &errMsg);
  689. TclLoadDbgMsg("NSLinkModule() failed: %s", errMsg);
  690. Tcl_AppendResult(interp, errMsg, NULL);
  691. return TCL_ERROR;
  692.     }
  693.     /*
  694.      * Stash the module reference within the load handle we create and return.
  695.      */
  696.     modulePtr = (Tcl_DyldModuleHandle *) ckalloc(sizeof(Tcl_DyldModuleHandle));
  697.     modulePtr->module = module;
  698.     modulePtr->nextPtr = NULL;
  699.     dyldLoadHandle = (Tcl_DyldLoadHandle *)
  700.     ckalloc(sizeof(Tcl_DyldLoadHandle));
  701. #if TCL_DYLD_USE_DLFCN
  702.     dyldLoadHandle->dlHandle = NULL;
  703. #endif
  704.     dyldLoadHandle->dyldLibHeader = NULL;
  705.     dyldLoadHandle->modulePtr = modulePtr;
  706.     *loadHandle = (Tcl_LoadHandle) dyldLoadHandle;
  707.     *unloadProcPtr = &TclpUnloadFile;
  708.     return TCL_OK;
  709. }
  710. #endif /* TCL_LOAD_FROM_MEMORY */
  711. /*
  712.  * Local Variables:
  713.  * mode: c
  714.  * c-basic-offset: 4
  715.  * fill-column: 79
  716.  * End:
  717.  */