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
);