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