2  * Copyright (c) 2017 Apple Inc. All rights reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. Please obtain a copy of the License at 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this 
  13  * The Original Code and all software distributed under the License are 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  18  * Please see the License for the specific language governing rights and 
  19  * limitations under the License. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  29 #include <sys/errno.h> 
  34 #include <TargetConditionals.h> 
  35 #include <malloc/malloc.h> 
  40 #include "dyld_priv.h" 
  42 #include "AllImages.h" 
  45 #include "Diagnostics.h" 
  46 #include "DyldSharedCache.h" 
  53 void                    parseDlHandle(void* h
, const MachOLoaded
** mh
, bool* dontContinue
); 
  56 // only in macOS and deprecated  
  57 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
  59 // macOS needs to support an old API that only works with fileype==MH_BUNDLE. 
  60 // In this deprecated API (unlike dlopen), loading and linking are separate steps. 
  61 // NSCreateObjectFileImageFrom*() just maps in the bundle mach-o file. 
  62 // NSLinkModule() does the load of dependent modules and rebasing/binding. 
  63 // To unload one of these, you must call NSUnLinkModule() and NSDestroyObjectFileImage() in any order! 
  66 NSObjectFileImageReturnCode 
NSCreateObjectFileImageFromFile(const char* path
, NSObjectFileImage
* ofi
) 
  68     log_apis("NSCreateObjectFileImageFromFile(\"%s\", %p)\n", path
, ofi
); 
  72     if ( ::stat(path
, &statbuf
) == -1 ) 
  73         return NSObjectFileImageFailure
; 
  75     // create ofi that just contains path. NSLinkModule does all the work 
  77     result
.path        
= strdup(path
); 
  78     result
.memSource   
= nullptr; 
  80     result
.loadAddress 
= nullptr; 
  82     *ofi 
= gAllImages
.addNSObjectFileImage(result
); 
  84     log_apis("NSCreateObjectFileImageFromFile() => %p\n", *ofi
); 
  86     return NSObjectFileImageSuccess
; 
  89 NSObjectFileImageReturnCode 
NSCreateObjectFileImageFromMemory(const void* memImage
, size_t memImageSize
, NSObjectFileImage 
*ofi
) 
  91     log_apis("NSCreateObjectFileImageFromMemory(%p, 0x%0lX, %p)\n", memImage
, memImageSize
, ofi
); 
  93     // sanity check the buffer is a mach-o file 
  94     __block Diagnostics diag
; 
  96         // check if it is current arch mach-o or fat with slice for current arch 
  98     const MachOFile
* mf 
= (MachOFile
*)memImage
; 
  99     if ( mf
->hasMachOMagic() && mf
->isMachO(diag
, memImageSize
) ) { 
 100         if ( strcmp(mf
->archName(), MachOFile::currentArchName()) == 0 ) 
 103         // <rdar://problem/42727628> support thin x86_64 on haswell machines 
 104         else if ( (strcmp(MachOFile::currentArchName(), "x86_64h") == 0) && (strcmp(mf
->archName(), "x86_64") == 0) ) 
 108     else if ( const FatFile
* ff 
= FatFile::isFatFile(memImage
) ) { 
 109         uint64_t sliceOffset
; 
 112         if ( ff
->isFatFileWithSlice(diag
, memImageSize
, MachOFile::currentArchName(), sliceOffset
, sliceLen
, missingSlice
) ) { 
 113             mf 
= (MachOFile
*)((long)memImage
+sliceOffset
); 
 114             if ( mf
->isMachO(diag
, sliceLen
) ) { 
 120         if ( !mf
->supportsPlatform(Platform::macOS
) ) 
 124         log_apis("NSCreateObjectFileImageFromMemory() not mach-o\n"); 
 125         return NSObjectFileImageFailure
; 
 128     // this API can only be used with bundles 
 129     if ( !mf
->isBundle() ) { 
 130         log_apis("NSCreateObjectFileImageFromMemory() not a bundle\n"); 
 131         return NSObjectFileImageInappropriateFile
; 
 134     // allocate ofi that just lists the memory range 
 136     result
.path        
= nullptr; 
 137     result
.memSource   
= memImage
; 
 138     result
.memLength   
= memImageSize
; 
 139     result
.loadAddress 
= nullptr; 
 141     *ofi 
= gAllImages
.addNSObjectFileImage(result
); 
 143     log_apis("NSCreateObjectFileImageFromMemory() => %p\n", *ofi
); 
 145     return NSObjectFileImageSuccess
; 
 148 NSModule 
NSLinkModule(NSObjectFileImage ofi
, const char* moduleName
, uint32_t options
) 
 150     DYLD_LOAD_LOCK_THIS_BLOCK
 
 151     log_apis("NSLinkModule(%p, \"%s\", 0x%08X)\n", ofi
, moduleName
, options
); 
 153     __block 
const char* path 
= nullptr; 
 154     bool foundImage 
= gAllImages
.forNSObjectFileImage(ofi
, ^(OFIInfo 
&image
) { 
 155         // if this is memory based image, write to temp file, then use file based loading 
 156         if ( image
.memSource 
!= nullptr ) { 
 157             // make temp file with content of memory buffer 
 158             bool successfullyWritten 
= false; 
 159             image
.path 
= ::tempnam(nullptr, "NSCreateObjectFileImageFromMemory-"); 
 160             if ( image
.path 
!= nullptr ) { 
 161                 int fd 
= ::open(image
.path
, O_WRONLY 
| O_CREAT 
| O_EXCL
, 0644); 
 163                     ssize_t writtenSize 
= ::pwrite(fd
, image
.memSource
, image
.memLength
, 0); 
 164                     if ( writtenSize 
== image
.memLength 
) 
 165                         successfullyWritten 
= true; 
 169             if ( !successfullyWritten 
) { 
 170                 if ( image
.path 
!= nullptr ) { 
 171                     free((void*)image
.path
); 
 172                     image
.path 
= nullptr; 
 174                 log_apis("NSLinkModule() => NULL (could not save memory image to temp file)\n"); 
 182         // ofi is invalid if not in list 
 183         log_apis("NSLinkModule() => NULL (invalid NSObjectFileImage)\n"); 
 190     // dlopen the binary outside of the read lock as we don't want to risk deadlock 
 192     void* callerAddress 
= __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue 
 193     const MachOLoaded
* loadAddress 
= gAllImages
.dlopen(diag
, path
, false, false, false, true, callerAddress
); 
 194     if ( diag
.hasError() ) { 
 195         log_apis("   NSLinkModule: failed: %s\n", diag
.errorMessage()); 
 199     // Now update the load address of this object 
 200     gAllImages
.forNSObjectFileImage(ofi
, ^(OFIInfo 
&image
) { 
 201         image
.loadAddress 
= loadAddress
; 
 203         // if memory based load, delete temp file 
 204         if ( image
.memSource 
!= nullptr ) { 
 205             log_apis("   NSLinkModule: delete temp file: %s\n", image
.path
); 
 206             ::unlink(image
.path
); 
 210     log_apis("NSLinkModule() => %p\n", loadAddress
); 
 211     return (NSModule
)loadAddress
; 
 214 // NSUnLinkModule unmaps the image, but does not release the NSObjectFileImage 
 215 bool NSUnLinkModule(NSModule 
module, uint32_t options
) 
 217     DYLD_LOAD_LOCK_THIS_BLOCK
 
 218     log_apis("NSUnLinkModule(%p, 0x%08X)\n", module, options
); 
 220     __block 
const mach_header
* mh 
= nullptr; 
 221     gAllImages
.infoForImageMappedAt(module, ^(const LoadedImage
& foundImage
, uint8_t permissions
) { 
 222         mh 
= foundImage
.loadedAddress(); 
 226         gAllImages
.decRefCount(mh
); // removes image if reference count went to zero 
 228     log_apis("NSUnLinkModule() => %d\n", mh 
!= nullptr); 
 230     return mh 
!= nullptr; 
 233 // NSDestroyObjectFileImage releases the NSObjectFileImage, but the mapped image may remain in use 
 234 bool NSDestroyObjectFileImage(NSObjectFileImage imageHandle
) 
 236     log_apis("NSDestroyObjectFileImage(%p)\n", imageHandle
); 
 238     __block 
const void* memSource 
= nullptr; 
 239     __block 
size_t      memLength 
= 0; 
 240     __block 
const char* path      
= nullptr; 
 241     bool foundImage 
= gAllImages
.forNSObjectFileImage(imageHandle
, ^(OFIInfo 
&image
) { 
 243         memSource 
= image
.memSource
; 
 244         memLength 
= image
.memLength
; 
 252     gAllImages
.removeNSObjectFileImage(imageHandle
); 
 254     // if object was created from a memory, release that memory 
 255     // NOTE: this is the way dyld has always done this. NSCreateObjectFileImageFromMemory() hands ownership of the memory to dyld 
 256     if ( memSource 
!= nullptr ) { 
 257         // we don't know if memory came from malloc or vm_allocate, so ask malloc 
 258         if ( malloc_size(memSource
) != 0 ) 
 259             free((void*)(memSource
)); 
 261             vm_deallocate(mach_task_self(), (vm_address_t
)memSource
, memLength
); 
 268 uint32_t NSSymbolDefinitionCountInObjectFileImage(NSObjectFileImage objectFileImage
) 
 270     halt("NSSymbolDefinitionCountInObjectFileImage() is obsolete"); 
 273 const char* NSSymbolDefinitionNameInObjectFileImage(NSObjectFileImage objectFileImage
, uint32_t ordinal
) 
 275     halt("NSSymbolDefinitionNameInObjectFileImage() is obsolete"); 
 278 uint32_t NSSymbolReferenceCountInObjectFileImage(NSObjectFileImage objectFileImage
) 
 280     halt("NSSymbolReferenceCountInObjectFileImage() is obsolete"); 
 283 const char* NSSymbolReferenceNameInObjectFileImage(NSObjectFileImage objectFileImage
, uint32_t ordinal
, bool *tentative_definition
) 
 285     halt("NSSymbolReferenceNameInObjectFileImage() is obsolete"); 
 288 bool NSIsSymbolDefinedInObjectFileImage(NSObjectFileImage imageHandle
, const char* symbolName
) 
 290     log_apis("NSIsSymbolDefinedInObjectFileImage(%p, %s)\n", imageHandle
, symbolName
); 
 292     __block 
bool hasSymbol 
= false; 
 293     bool foundImage 
= gAllImages
.forNSObjectFileImage(imageHandle
, ^(OFIInfo 
&image
) { 
 295         bool resultPointsToInstructions 
= false; 
 296         hasSymbol 
= image
.loadAddress
->hasExportedSymbol(symbolName
, nullptr, &addr
, &resultPointsToInstructions
); 
 299     // ofi is invalid if not in list 
 306 void* NSGetSectionDataInObjectFileImage(NSObjectFileImage imageHandle
, const char* segmentName
, const char* sectionName
, size_t* size
) 
 308     __block 
const void* result 
= nullptr; 
 309     bool foundImage 
= gAllImages
.forNSObjectFileImage(imageHandle
, ^(OFIInfo 
&image
) { 
 311         result 
= image
.loadAddress
->findSectionContent(segmentName
, sectionName
, sz
); 
 315     // ofi is invalid if not in list 
 319         return (void*)result
; 
 322 const char* NSNameOfModule(NSModule m
) 
 324     log_apis("NSNameOfModule(%p)\n", m
); 
 326     __block 
const char* result 
= nullptr; 
 327     gAllImages
.infoForImageMappedAt(m
, ^(const LoadedImage
& foundImage
, uint8_t permissions
) { 
 328         result 
= gAllImages
.imagePath(foundImage
.image()); 
 334 const char* NSLibraryNameForModule(NSModule m
) 
 336     log_apis("NSLibraryNameForModule(%p)\n", m
); 
 338      __block 
const char* result 
= nullptr; 
 339     gAllImages
.infoForImageMappedAt(m
, ^(const LoadedImage
& foundImage
, uint8_t permissions
) { 
 340         result 
= gAllImages
.imagePath(foundImage
.image()); 
 346 static bool flatFindSymbol(const char* symbolName
, void** symbolAddress
, const mach_header
** foundInImageAtLoadAddress
) 
 348     __block 
bool result 
= false; 
 349     gAllImages
.forEachImage(^(const LoadedImage
& loadedImage
, bool& stop
) { 
 350         bool resultPointsToInstructions 
= false; 
 351         if ( loadedImage
.loadedAddress()->hasExportedSymbol(symbolName
, nullptr, symbolAddress
, &resultPointsToInstructions
) ) { 
 352             *foundInImageAtLoadAddress 
= loadedImage
.loadedAddress(); 
 360 bool NSIsSymbolNameDefined(const char* symbolName
) 
 362     log_apis("NSIsSymbolNameDefined(%s)\n", symbolName
); 
 364     const mach_header
* foundInImageAtLoadAddress
; 
 366     return flatFindSymbol(symbolName
, &address
, &foundInImageAtLoadAddress
); 
 369 bool NSIsSymbolNameDefinedWithHint(const char* symbolName
, const char* libraryNameHint
) 
 371     log_apis("NSIsSymbolNameDefinedWithHint(%s, %s)\n", symbolName
, libraryNameHint
); 
 373     const mach_header
* foundInImageAtLoadAddress
; 
 375     return flatFindSymbol(symbolName
, &address
, &foundInImageAtLoadAddress
); 
 378 bool NSIsSymbolNameDefinedInImage(const struct mach_header
* mh
, const char* symbolName
) 
 380     log_apis("NSIsSymbolNameDefinedInImage(%p, %s)\n", mh
, symbolName
); 
 383     bool resultPointsToInstructions 
= false; 
 384     return ((MachOLoaded
*)mh
)->hasExportedSymbol(symbolName
, nullptr, &addr
, &resultPointsToInstructions
); 
 387 NSSymbol 
NSLookupAndBindSymbol(const char* symbolName
) 
 389     log_apis("NSLookupAndBindSymbol(%s)\n", symbolName
); 
 391     const mach_header
* foundInImageAtLoadAddress
; 
 393     if ( flatFindSymbol(symbolName
, &symbolAddress
, &foundInImageAtLoadAddress
) ) { 
 394         return (NSSymbol
)symbolAddress
; 
 399 NSSymbol 
NSLookupAndBindSymbolWithHint(const char* symbolName
, const char* libraryNameHint
) 
 401     log_apis("NSLookupAndBindSymbolWithHint(%s, %s)\n", symbolName
, libraryNameHint
); 
 403     const mach_header
* foundInImageAtLoadAddress
; 
 405     if ( flatFindSymbol(symbolName
, &symbolAddress
, &foundInImageAtLoadAddress
) ) { 
 406         return (NSSymbol
)symbolAddress
; 
 411 NSSymbol 
NSLookupSymbolInModule(NSModule 
module, const char* symbolName
) 
 413     log_apis("NSLookupSymbolInModule(%p. %s)\n", module, symbolName
); 
 415     const MachOLoaded
* mh 
= (const MachOLoaded
*)module; 
 417     bool resultPointsToInstructions 
= false; 
 418     if ( mh
->hasExportedSymbol(symbolName
, nullptr, &addr
, &resultPointsToInstructions
) ) { 
 419         return (NSSymbol
)addr
; 
 424 NSSymbol 
NSLookupSymbolInImage(const mach_header
* mh
, const char* symbolName
, uint32_t options
) 
 426     log_apis("NSLookupSymbolInImage(%p, \"%s\", 0x%08X)\n", mh
, symbolName
, options
); 
 429     bool resultPointsToInstructions 
= false; 
 430         if ( ((MachOLoaded
*)mh
)->hasExportedSymbol(symbolName
, nullptr, &addr
, &resultPointsToInstructions
) ) { 
 431         log_apis("   NSLookupSymbolInImage() => %p\n", addr
); 
 432         return (NSSymbol
)addr
; 
 434     if ( options 
& NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 
) { 
 435         log_apis("   NSLookupSymbolInImage() => NULL\n"); 
 442 const char* NSNameOfSymbol(NSSymbol symbol
) 
 444     halt("NSNameOfSymbol() is obsolete"); 
 447 void* NSAddressOfSymbol(NSSymbol symbol
) 
 449     log_apis("NSAddressOfSymbol(%p)\n", symbol
); 
 451     // in dyld 1.0, NSSymbol was a pointer to the nlist entry in the symbol table 
 452     return (void*)symbol
; 
 455 NSModule 
NSModuleForSymbol(NSSymbol symbol
) 
 457     log_apis("NSModuleForSymbol(%p)\n", symbol
); 
 459     __block NSModule result 
= nullptr; 
 460     gAllImages
.infoForImageMappedAt(symbol
, ^(const LoadedImage
& foundImage
, uint8_t permissions
) { 
 461         result 
= (NSModule
)foundImage
.loadedAddress(); 
 467 void NSLinkEditError(NSLinkEditErrors 
*c
, int *errorNumber
, const char** fileName
, const char** errorString
) 
 469     log_apis("NSLinkEditError(%p, %p, %p, %p)\n", c
, errorNumber
, fileName
, errorString
); 
 470     *c 
= NSLinkEditOtherError
; 
 476 bool NSAddLibrary(const char* pathName
) 
 478     log_apis("NSAddLibrary(%s)\n", pathName
); 
 480     void* callerAddress 
= __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue 
 481     return ( dlopen_internal(pathName
, 0, callerAddress
) != nullptr); 
 484 bool NSAddLibraryWithSearching(const char* pathName
) 
 486     log_apis("NSAddLibraryWithSearching(%s)\n", pathName
); 
 488     void* callerAddress 
= __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue 
 489     return ( dlopen_internal(pathName
, 0, callerAddress
) != nullptr); 
 492 const mach_header
* NSAddImage(const char* imageName
, uint32_t options
) 
 494     log_apis("NSAddImage(\"%s\", 0x%08X)\n", imageName
, options
); 
 496     // Note: this is a quick and dirty implementation that just uses dlopen() and ignores some option flags 
 497     uint32_t dloptions 
= 0; 
 498     if ( (options 
& NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
) != 0 ) 
 499         dloptions 
|= RTLD_NOLOAD
; 
 501     void* callerAddress 
= __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue 
 502     void* h 
= dlopen_internal(imageName
, dloptions
, callerAddress
); 
 503     if ( h 
!= nullptr ) { 
 504         const MachOLoaded
* mh
; 
 506         parseDlHandle(h
, &mh
, &dontContinue
); 
 510     if ( (options 
& (NSADDIMAGE_OPTION_RETURN_ON_ERROR
|NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
)) == 0 ) { 
 511         halt("NSAddImage() image not found"); 
 516 void NSInstallLinkEditErrorHandlers(const NSLinkEditErrorHandlers 
*handlers
) 
 518     halt("NSInstallLinkEditErrorHandlers() is obsolete"); 
 521 bool _dyld_present(void) 
 523     log_apis("_dyld_present()\n"); 
 528 bool _dyld_launched_prebound(void)   
 530     halt("_dyld_launched_prebound() is obsolete"); 
 533 bool _dyld_all_twolevel_modules_prebound(void) 
 535     halt("_dyld_all_twolevel_modules_prebound() is obsolete"); 
 538 bool _dyld_bind_fully_image_containing_address(const void* address
) 
 540     log_apis("_dyld_bind_fully_image_containing_address(%p)\n", address
); 
 542     // in dyld3, everything is always fully bound 
 546 bool _dyld_image_containing_address(const void* address
) 
 548     log_apis("_dyld_image_containing_address(%p)\n", address
); 
 550     return (dyld_image_header_containing_address(address
) != nullptr); 
 553 void _dyld_lookup_and_bind(const char* symbolName
, void **address
, NSModule
* module) 
 555     log_apis("_dyld_lookup_and_bind(%s, %p, %p)\n", symbolName
, address
, module); 
 557     const mach_header
* foundInImageAtLoadAddress
; 
 558     if ( flatFindSymbol(symbolName
, address
, &foundInImageAtLoadAddress
) ) { 
 559         *module = (NSModule
)foundInImageAtLoadAddress
; 
 567 void _dyld_lookup_and_bind_with_hint(const char* symbolName
, const char* libraryNameHint
, void** address
, NSModule
* module) 
 569     log_apis("_dyld_lookup_and_bind_with_hint(%s, %s, %p, %p)\n", symbolName
, libraryNameHint
, address
, module); 
 571     const mach_header
* foundInImageAtLoadAddress
; 
 572     if ( flatFindSymbol(symbolName
, address
, &foundInImageAtLoadAddress
) ) { 
 573         *module = (NSModule
)foundInImageAtLoadAddress
; 
 582 void _dyld_lookup_and_bind_fully(const char* symbolName
, void** address
, NSModule
* module) 
 584     log_apis("_dyld_lookup_and_bind_fully(%s, %p, %p)\n", symbolName
, address
, module); 
 586     const mach_header
* foundInImageAtLoadAddress
; 
 587     if ( flatFindSymbol(symbolName
, address
, &foundInImageAtLoadAddress
) ) { 
 588         *module = (NSModule
)foundInImageAtLoadAddress
; 
 596 const struct mach_header
* _dyld_get_image_header_containing_address(const void* address
) 
 598     log_apis("_dyld_get_image_header_containing_address(%p)\n", address
); 
 600     return dyld_image_header_containing_address(address
);