1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2004-2012 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
27 #include <malloc/malloc.h>
31 #include <TargetConditionals.h>
32 #include <System/sys/csr.h>
33 #include <crt_externs.h>
34 #include <Availability.h>
35 #if !TARGET_OS_DRIVERKIT
36 #include <vproc_priv.h>
39 #include <sys/types.h>
42 #include <System/sys/codesign.h>
43 #include <libc_private.h>
45 #include <mach-o/dyld_images.h>
46 #include <mach-o/dyld.h>
47 #include <mach-o/dyld_priv.h>
51 #include "dyld_cache_format.h"
52 #include "objc-shared-cache.h"
54 #include "ImageLoader.h"
58 #include "AllImages.h"
59 #include "StartGlue.h"
63 // this was in dyld_priv.h but it is no longer exported
65 const struct dyld_all_image_infos
* _dyld_get_all_image_infos() __attribute__((visibility("hidden")));
69 extern "C" int __cxa_atexit(void (*func
)(void *), void *arg
, void *dso
);
70 extern "C" void __cxa_finalize(const void *dso
);
71 extern "C" void __cxa_finalize_ranges(const struct __cxa_range_t ranges
[], int count
);
74 // private interface between libSystem.dylib and dyld
76 extern "C" int _dyld_func_lookup(const char* dyld_func_name
, void **address
);
79 static void dyld_func_lookup_and_resign(const char *dyld_func_name
, T
*__ptrauth_dyld_function_ptr
* address
) {
81 int res
= _dyld_func_lookup(dyld_func_name
, &funcAsVoidPtr
);
84 // If C function pointer discriminators are type-diverse this cast will be
85 // an authenticate and resign operation.
86 *address
= reinterpret_cast<T
*>(funcAsVoidPtr
);
89 #if TARGET_OS_IOS && !TARGET_OS_SIMULATOR
91 extern int compatFuncLookup(const char* name
, void** address
) __API_AVAILABLE(ios(13.0));
93 extern "C" void setLookupFunc(void*);
97 extern void* __ptrauth_dyld_address_auth gUseDyld3
;
100 // <rdar://problem/61161069> libdyld.dylib should use abort_with_payload() for asserts
102 void abort_report_np(const char* format
, ...)
106 _SIMPLE_STRING s
= _simple_salloc();
108 va_start(list
, format
);
109 _simple_vsprintf(s
, format
, list
);
111 str
= _simple_string(s
);
114 // _simple_salloc failed, but at least format may have useful info by itself
121 typedef void (*funcType
)(const char* msg
) __attribute__((__noreturn__
));
122 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
123 dyld_func_lookup_and_resign("__dyld_halt", &p
);
126 // halt() doesn't return, so we can't call _simple_sfree
129 // libc uses assert()
130 #pragma clang diagnostic push
131 #pragma clang diagnostic ignored "-Winvalid-noreturn"
133 void __assert_rtn(const char* func
, const char* file
, int line
, const char* failedexpr
)
136 abort_report_np("Assertion failed: (%s), file %s, line %d.\n", failedexpr
, file
, line
);
138 abort_report_np("Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr
, func
, file
, line
);
141 #pragma clang diagnostic pop
144 // deprecated APIs are still availble on Mac OS X, but not on iPhone OS
146 #define DEPRECATED_APIS_SUPPORTED 1
148 #define DEPRECATED_APIS_SUPPORTED 0
152 * names_match() takes an install_name from an LC_LOAD_DYLIB command and a
153 * libraryName (which is -lx or -framework Foo argument passed to the static
154 * link editor for the same library) and determines if they match. This depends
155 * on conventional use of names including major versioning.
160 const char *install_name
,
161 const char* libraryName
)
163 const char *basename
;
167 * Conventional install names have these forms:
168 * /System/Library/Frameworks/AppKit.framework/Versions/A/Appkit
169 * /Local/Library/Frameworks/AppKit.framework/Appkit
170 * /lib/libsys_s.A.dylib
171 * /usr/lib/libsys_s.dylib
173 basename
= strrchr(install_name
, '/');
175 basename
= install_name
;
180 * By checking the base name matching the library name we take care
181 * of the -framework cases.
183 if(strcmp(basename
, libraryName
) == 0)
187 * Now check the base name for "lib" if so proceed to check for the
188 * -lx case dealing with a possible .X.dylib and a .dylib extension.
190 if(strncmp(basename
, "lib", 3) ==0){
191 n
= strlen(libraryName
);
192 if(strncmp(basename
+3, libraryName
, n
) == 0){
193 if(strncmp(basename
+3+n
, ".dylib", 6) == 0)
195 if(basename
[3+n
] == '.' &&
196 basename
[3+n
+1] != '\0' &&
197 strncmp(basename
+3+n
+2, ".dylib", 6) == 0)
204 #if DEPRECATED_APIS_SUPPORTED
206 void NSInstallLinkEditErrorHandlers(
207 const NSLinkEditErrorHandlers
* handlers
)
210 return dyld3::NSInstallLinkEditErrorHandlers(handlers
);
212 DYLD_LOCK_THIS_BLOCK
;
213 typedef void (*ucallback_t
)(const char* symbol_name
);
214 typedef NSModule (*mcallback_t
)(NSSymbol s
, NSModule old
, NSModule newhandler
);
215 typedef void (*lcallback_t
)(NSLinkEditErrors c
, int errorNumber
,
216 const char* fileName
, const char* errorString
);
217 typedef void (*funcType
)(ucallback_t undefined
, mcallback_t multiple
, lcallback_t linkEdit
);
218 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
221 dyld_func_lookup_and_resign("__dyld_install_handlers", &p
);
222 mcallback_t m
= handlers
->multiple
;
223 p(handlers
->undefined
, m
, handlers
->linkEdit
);
231 return dyld3::NSNameOfModule(module);
233 DYLD_LOCK_THIS_BLOCK
;
234 typedef const char* (*funcType
)(NSModule
module);
235 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
238 dyld_func_lookup_and_resign("__dyld_NSNameOfModule", &p
);
243 NSLibraryNameForModule(
247 return dyld3::NSLibraryNameForModule(module);
249 DYLD_LOCK_THIS_BLOCK
;
250 typedef const char* (*funcType
)(NSModule
module);
251 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
254 dyld_func_lookup_and_resign("__dyld_NSLibraryNameForModule", &p
);
259 NSIsSymbolNameDefined(
260 const char* symbolName
)
263 return dyld3::NSIsSymbolNameDefined(symbolName
);
265 DYLD_LOCK_THIS_BLOCK
;
266 typedef bool (*funcType
)(const char* symbolName
);
267 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
270 dyld_func_lookup_and_resign("__dyld_NSIsSymbolNameDefined", &p
);
271 return(p(symbolName
));
275 NSIsSymbolNameDefinedWithHint(
276 const char* symbolName
,
277 const char* libraryNameHint
)
280 return dyld3::NSIsSymbolNameDefinedWithHint(symbolName
, libraryNameHint
);
282 DYLD_LOCK_THIS_BLOCK
;
283 typedef bool (*funcType
)(const char* symbolName
,
284 const char* libraryNameHint
);
285 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
288 dyld_func_lookup_and_resign("__dyld_NSIsSymbolNameDefinedWithHint", &p
);
289 return(p(symbolName
, libraryNameHint
));
293 NSIsSymbolNameDefinedInImage(
294 const struct mach_header
*image
,
295 const char* symbolName
)
298 return dyld3::NSIsSymbolNameDefinedInImage(image
, symbolName
);
300 DYLD_LOCK_THIS_BLOCK
;
301 typedef bool (*funcType
)(const struct mach_header
*image
,
302 const char* symbolName
);
303 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
306 dyld_func_lookup_and_resign("__dyld_NSIsSymbolNameDefinedInImage", &p
);
307 return(p(image
, symbolName
));
311 NSLookupAndBindSymbol(
312 const char* symbolName
)
315 return dyld3::NSLookupAndBindSymbol(symbolName
);
317 DYLD_LOCK_THIS_BLOCK
;
318 typedef NSSymbol (*funcType
)(const char* symbolName
);
319 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
322 dyld_func_lookup_and_resign("__dyld_NSLookupAndBindSymbol", &p
);
323 return(p(symbolName
));
327 NSLookupAndBindSymbolWithHint(
328 const char* symbolName
,
329 const char* libraryNameHint
)
332 return dyld3::NSLookupAndBindSymbolWithHint(symbolName
, libraryNameHint
);
334 DYLD_LOCK_THIS_BLOCK
;
335 typedef NSSymbol (*funcType
)(const char* symbolName
,
336 const char* libraryNameHint
);
337 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
340 dyld_func_lookup_and_resign("__dyld_NSLookupAndBindSymbolWithHint", &p
);
341 return(p(symbolName
, libraryNameHint
));
345 NSLookupSymbolInModule(
347 const char* symbolName
)
350 return dyld3::NSLookupSymbolInModule(module, symbolName
);
352 DYLD_LOCK_THIS_BLOCK
;
353 typedef NSSymbol (*funcType
)(NSModule
module, const char* symbolName
);
354 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
357 dyld_func_lookup_and_resign("__dyld_NSLookupSymbolInModule", &p
);
358 return(p(module, symbolName
));
362 NSLookupSymbolInImage(
363 const struct mach_header
*image
,
364 const char* symbolName
,
368 return dyld3::NSLookupSymbolInImage(image
, symbolName
, options
);
370 DYLD_LOCK_THIS_BLOCK
;
371 typedef NSSymbol (*funcType
)(const struct mach_header
*image
,
372 const char* symbolName
,
374 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
377 dyld_func_lookup_and_resign("__dyld_NSLookupSymbolInImage", &p
);
378 return(p(image
, symbolName
, options
));
386 return dyld3::NSNameOfSymbol(symbol
);
388 DYLD_LOCK_THIS_BLOCK
;
389 typedef char * (*funcType
)(NSSymbol symbol
);
390 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
393 dyld_func_lookup_and_resign("__dyld_NSNameOfSymbol",&p
);
402 return dyld3::NSAddressOfSymbol(symbol
);
404 DYLD_LOCK_THIS_BLOCK
;
405 typedef void * (*funcType
)(NSSymbol symbol
);
406 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
409 dyld_func_lookup_and_resign("__dyld_NSAddressOfSymbol", &p
);
418 return dyld3::NSModuleForSymbol(symbol
);
420 DYLD_LOCK_THIS_BLOCK
;
421 typedef NSModule (*funcType
)(NSSymbol symbol
);
422 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
425 dyld_func_lookup_and_resign("__dyld_NSModuleForSymbol", &p
);
431 const char* pathName
)
434 return dyld3::NSAddLibrary(pathName
);
436 DYLD_LOCK_THIS_BLOCK
;
437 typedef bool (*funcType
)(const char* pathName
);
438 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
441 dyld_func_lookup_and_resign("__dyld_NSAddLibrary", &p
);
446 NSAddLibraryWithSearching(
447 const char* pathName
)
450 return dyld3::NSAddLibrary(pathName
);
452 DYLD_LOCK_THIS_BLOCK
;
453 typedef bool (*funcType
)(const char* pathName
);
454 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
457 dyld_func_lookup_and_resign("__dyld_NSAddLibraryWithSearching", &p
);
461 const struct mach_header
*
463 const char* image_name
,
467 return dyld3::NSAddImage(image_name
, options
);
469 DYLD_LOCK_THIS_BLOCK
;
470 typedef const struct mach_header
* (*funcType
)(const char* image_name
,
472 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
475 dyld_func_lookup_and_resign("__dyld_NSAddImage", &p
);
476 return(p(image_name
, options
));
478 #endif // DEPRECATED_APIS_SUPPORTED
481 * This routine returns the current version of the named shared library the
482 * executable it was built with. The libraryName parameter is the same as the
483 * -lx or -framework Foo argument passed to the static link editor when building
484 * the executable (with -lx it would be "x" and with -framework Foo it would be
485 * "Foo"). If this the executable was not built against the specified library
486 * it returns -1. It should be noted that if this only returns the value the
487 * current version of the named shared library the executable was built with
488 * and not a list of current versions that dependent libraries and bundles the
489 * program is using were built with.
491 int32_t NSVersionOfLinkTimeLibrary(const char* libraryName
)
494 return dyld3::NSVersionOfLinkTimeLibrary(libraryName
);
496 // Lazily call _NSGetMachExecuteHeader() and cache result
498 static mach_header_64
* mh
= NULL
;
500 static mach_header
* mh
= NULL
;
503 mh
= _NSGetMachExecuteHeader();
505 const load_command
* lc
= (load_command
*)((char*)mh
+ sizeof(mach_header_64
));
507 const load_command
* lc
= (load_command
*)((char*)mh
+ sizeof(mach_header
));
509 for(uint32_t i
= 0; i
< mh
->ncmds
; i
++){
512 case LC_LOAD_WEAK_DYLIB
:
513 case LC_LOAD_UPWARD_DYLIB
:
514 const dylib_command
* dl
= (dylib_command
*)lc
;
515 const char* install_name
= (char*)dl
+ dl
->dylib
.name
.offset
;
516 if ( names_match(install_name
, libraryName
) )
517 return dl
->dylib
.current_version
;
520 lc
= (load_command
*)((char*)lc
+ lc
->cmdsize
);
526 * This routine returns the current version of the named shared library the
527 * program it is running against. The libraryName parameter is the same as
528 * would be static link editor using the -lx or -framework Foo flags (with -lx
529 * it would be "x" and with -framework Foo it would be "Foo"). If the program
530 * is not using the specified library it returns -1.
532 int32_t NSVersionOfRunTimeLibrary(const char* libraryName
)
535 return dyld3::NSVersionOfRunTimeLibrary(libraryName
);
537 uint32_t n
= _dyld_image_count();
538 for(uint32_t i
= 0; i
< n
; i
++){
539 const mach_header
* mh
= _dyld_get_image_header(i
);
542 if ( mh
->filetype
!= MH_DYLIB
)
545 const load_command
* lc
= (load_command
*)((char*)mh
+ sizeof(mach_header_64
));
547 const load_command
* lc
= (load_command
*)((char*)mh
+ sizeof(mach_header
));
549 for(uint32_t j
= 0; j
< mh
->ncmds
; j
++){
550 if ( lc
->cmd
== LC_ID_DYLIB
) {
551 const dylib_command
* dl
= (dylib_command
*)lc
;
552 const char* install_name
= (char *)dl
+ dl
->dylib
.name
.offset
;
553 if ( names_match(install_name
, libraryName
) )
554 return dl
->dylib
.current_version
;
556 lc
= (load_command
*)((char*)lc
+ lc
->cmdsize
);
563 uint32_t dyld_get_program_sdk_watch_os_version()
566 return dyld3::dyld_get_program_sdk_watch_os_version();
568 __block
uint32_t retval
= 0;
569 __block
bool versionFound
= false;
570 dyld3::dyld_get_image_versions((mach_header
*)_NSGetMachExecuteHeader(), ^(dyld_platform_t platform
, uint32_t sdk_version
, uint32_t min_version
) {
571 if (versionFound
) return;
573 if (dyld_get_base_platform(platform
) == PLATFORM_WATCHOS
) {
575 retval
= sdk_version
;
582 uint32_t dyld_get_program_min_watch_os_version()
585 return dyld3::dyld_get_program_min_watch_os_version();
587 __block
uint32_t retval
= 0;
588 __block
bool versionFound
= false;
589 dyld3::dyld_get_image_versions((mach_header
*)_NSGetMachExecuteHeader(), ^(dyld_platform_t platform
, uint32_t sdk_version
, uint32_t min_version
) {
590 if (versionFound
) return;
592 if (dyld_get_base_platform(platform
) == PLATFORM_WATCHOS
) {
594 retval
= min_version
;
603 uint32_t dyld_get_program_sdk_bridge_os_version()
606 return dyld3::dyld_get_program_sdk_bridge_os_version();
608 __block
uint32_t retval
= 0;
609 __block
bool versionFound
= false;
610 dyld3::dyld_get_image_versions((mach_header
*)_NSGetMachExecuteHeader(), ^(dyld_platform_t platform
, uint32_t sdk_version
, uint32_t min_version
) {
611 if (versionFound
) return;
613 if (dyld_get_base_platform(platform
) == PLATFORM_BRIDGEOS
) {
615 retval
= sdk_version
;
622 uint32_t dyld_get_program_min_bridge_os_version()
625 return dyld3::dyld_get_program_min_bridge_os_version();
627 __block
uint32_t retval
= 0;
628 __block
bool versionFound
= false;
629 dyld3::dyld_get_image_versions((mach_header
*)_NSGetMachExecuteHeader(), ^(dyld_platform_t platform
, uint32_t sdk_version
, uint32_t min_version
) {
630 if (versionFound
) return;
632 if (dyld_get_base_platform(platform
) == PLATFORM_BRIDGEOS
) {
634 retval
= min_version
;
643 * Returns the sdk version (encode as nibble XXXX.YY.ZZ) the
644 * specified binary was built against.
646 * First looks for LC_VERSION_MIN_* in binary and if sdk field is
647 * not zero, return that value.
648 * Otherwise, looks for the libSystem.B.dylib the binary linked
649 * against and uses a table to convert that to an sdk version.
651 uint32_t dyld_get_sdk_version(const mach_header
* mh
)
653 return dyld3::dyld_get_sdk_version(mh
);
656 uint32_t dyld_get_program_sdk_version()
658 return dyld3::dyld_get_sdk_version((mach_header
*)_NSGetMachExecuteHeader());
661 uint32_t dyld_get_min_os_version(const struct mach_header
* mh
)
663 return dyld3::dyld_get_min_os_version(mh
);
667 uint32_t dyld_get_program_min_os_version()
669 return dyld3::dyld_get_min_os_version((mach_header
*)_NSGetMachExecuteHeader());
673 bool _dyld_get_image_uuid(const struct mach_header
* mh
, uuid_t uuid
)
676 return dyld3::_dyld_get_image_uuid(mh
, uuid
);
678 const load_command
* startCmds
= NULL
;
679 if ( mh
->magic
== MH_MAGIC_64
)
680 startCmds
= (load_command
*)((char *)mh
+ sizeof(mach_header_64
));
681 else if ( mh
->magic
== MH_MAGIC
)
682 startCmds
= (load_command
*)((char *)mh
+ sizeof(mach_header
));
684 return false; // not a mach-o file, or wrong endianness
686 const load_command
* const cmdsEnd
= (load_command
*)((char*)startCmds
+ mh
->sizeofcmds
);
687 const load_command
* cmd
= startCmds
;
688 for(uint32_t i
= 0; i
< mh
->ncmds
; ++i
) {
689 const load_command
* nextCmd
= (load_command
*)((char *)cmd
+ cmd
->cmdsize
);
690 if ( (cmd
->cmdsize
< 8) || (nextCmd
> cmdsEnd
) || (nextCmd
< startCmds
)) {
693 if ( cmd
->cmd
== LC_UUID
) {
694 const uuid_command
* uuidCmd
= (uuid_command
*)cmd
;
695 memcpy(uuid
, uuidCmd
->uuid
, 16);
704 dyld_platform_t
dyld_get_active_platform(void) {
706 return dyld3::dyld_get_active_platform();
708 return (dyld_platform_t
)_dyld_get_all_image_infos()->platform
;
711 dyld_platform_t
dyld_get_base_platform(dyld_platform_t platform
) {
712 return dyld3::dyld_get_base_platform(platform
);
715 bool dyld_is_simulator_platform(dyld_platform_t platform
) {
716 return dyld3::dyld_is_simulator_platform(platform
);
719 bool dyld_sdk_at_least(const struct mach_header
* mh
, dyld_build_version_t version
) {
720 return dyld3::dyld_sdk_at_least(mh
, version
);
723 bool dyld_minos_at_least(const struct mach_header
* mh
, dyld_build_version_t version
) {
724 return dyld3::dyld_minos_at_least(mh
, version
);
727 bool dyld_program_sdk_at_least(dyld_build_version_t version
) {
728 return dyld3::dyld_program_sdk_at_least(version
);
731 bool dyld_program_minos_at_least(dyld_build_version_t version
) {
732 return dyld3::dyld_program_minos_at_least(version
);
735 // Function that walks through the load commands and calls the internal block for every version found
736 // Intended as a fallback for very complex (and rare) version checks, or for tools that need to
737 // print our everything for diagnostic reasons
738 void dyld_get_image_versions(const struct mach_header
* mh
, void (^callback
)(dyld_platform_t platform
, uint32_t sdk_version
, uint32_t min_version
)) {
739 dyld3::dyld_get_image_versions(mh
, callback
);
744 #if DEPRECATED_APIS_SUPPORTED
746 * NSCreateObjectFileImageFromFile() creates an NSObjectFileImage for the
747 * specified file name if the file is a correct Mach-O file that can be loaded
748 * with NSloadModule(). For return codes of NSObjectFileImageFailure and
749 * NSObjectFileImageFormat an error message is printed to stderr. All
750 * other codes cause no printing.
752 NSObjectFileImageReturnCode
753 NSCreateObjectFileImageFromFile(
754 const char* pathName
,
755 NSObjectFileImage
*objectFileImage
)
758 return dyld3::NSCreateObjectFileImageFromFile(pathName
, objectFileImage
);
760 DYLD_LOCK_THIS_BLOCK
;
761 typedef NSObjectFileImageReturnCode (*funcType
)(const char*, NSObjectFileImage
*);
762 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
765 dyld_func_lookup_and_resign("__dyld_NSCreateObjectFileImageFromFile", &p
);
766 return p(pathName
, objectFileImage
);
771 * NSCreateObjectFileImageFromMemory() creates an NSObjectFileImage for the
772 * object file mapped into memory at address of size length if the object file
773 * is a correct Mach-O file that can be loaded with NSloadModule(). For return
774 * codes of NSObjectFileImageFailure and NSObjectFileImageFormat an error
775 * message is printed to stderr. All other codes cause no printing.
777 NSObjectFileImageReturnCode
778 NSCreateObjectFileImageFromMemory(
781 NSObjectFileImage
*objectFileImage
)
783 // <rdar://problem/51812762> NSCreatObjectFileImageFromMemory fail opaquely if Hardened runtime is enabled
785 if ( csops(0, CS_OPS_STATUS
, &flags
, sizeof(flags
)) != -1 ) {
786 if ( (flags
& (CS_ENFORCEMENT
|CS_KILL
)) == (CS_ENFORCEMENT
|CS_KILL
) ) {
787 //fprintf(stderr, "dyld: warning: NSCreatObjectFileImageFromMemory() cannot be used in harden process 0x%08X\n", flags);
788 return NSObjectFileImageAccess
;
793 return dyld3::NSCreateObjectFileImageFromMemory(address
, size
, objectFileImage
);
795 DYLD_LOCK_THIS_BLOCK
;
796 typedef NSObjectFileImageReturnCode (*funcType
)(const void*, size_t, NSObjectFileImage
*);
797 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
800 dyld_func_lookup_and_resign("__dyld_NSCreateObjectFileImageFromMemory", &p
);
801 return p(address
, size
, objectFileImage
);
804 #if OBSOLETE_DYLD_API
806 * NSCreateCoreFileImageFromFile() creates an NSObjectFileImage for the
807 * specified core file name if the file is a correct Mach-O core file.
808 * For return codes of NSObjectFileImageFailure and NSObjectFileImageFormat
809 * an error message is printed to stderr. All other codes cause no printing.
811 NSObjectFileImageReturnCode
812 NSCreateCoreFileImageFromFile(
813 const char* pathName
,
814 NSObjectFileImage
*objectFileImage
)
816 DYLD_LOCK_THIS_BLOCK
;
817 typedef NSObjectFileImageReturnCode (*funcType
)(const char*, NSObjectFileImage
*) = NULL
;
820 dyld_func_lookup_and_resign("__dyld_NSCreateCoreFileImageFromFile", &p
);
821 return p(pathName
, objectFileImage
);
826 NSDestroyObjectFileImage(
827 NSObjectFileImage objectFileImage
)
830 return dyld3::NSDestroyObjectFileImage(objectFileImage
);
832 DYLD_LOCK_THIS_BLOCK
;
833 typedef bool (*funcType
)(NSObjectFileImage
);
834 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
837 dyld_func_lookup_and_resign("__dyld_NSDestroyObjectFileImage", &p
);
838 return p(objectFileImage
);
844 NSObjectFileImage objectFileImage
,
845 const char* moduleName
,
849 return dyld3::NSLinkModule(objectFileImage
, moduleName
, options
);
851 DYLD_LOCK_THIS_BLOCK
;
852 typedef NSModule (*funcType
)(NSObjectFileImage
, const char*, unsigned long);
853 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
856 dyld_func_lookup_and_resign("__dyld_NSLinkModule", &p
);
858 return p(objectFileImage
, moduleName
, options
);
865 * NSSymbolDefinitionCountInObjectFileImage() returns the number of symbol
866 * definitions in the NSObjectFileImage.
869 NSSymbolDefinitionCountInObjectFileImage(
870 NSObjectFileImage objectFileImage
)
873 return dyld3::NSSymbolDefinitionCountInObjectFileImage(objectFileImage
);
875 DYLD_LOCK_THIS_BLOCK
;
876 typedef uint32_t (*funcType
)(NSObjectFileImage
);
877 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
880 dyld_func_lookup_and_resign("__dyld_NSSymbolDefinitionCountInObjectFileImage", &p
);
882 return p(objectFileImage
);
886 * NSSymbolDefinitionNameInObjectFileImage() returns the name of the i'th
887 * symbol definitions in the NSObjectFileImage. If the ordinal specified is
888 * outside the range [0..NSSymbolDefinitionCountInObjectFileImage], NULL will
892 NSSymbolDefinitionNameInObjectFileImage(
893 NSObjectFileImage objectFileImage
,
897 return dyld3::NSSymbolDefinitionNameInObjectFileImage(objectFileImage
, ordinal
);
899 DYLD_LOCK_THIS_BLOCK
;
900 typedef const char* (*funcType
)(NSObjectFileImage
, uint32_t);
901 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
904 dyld_func_lookup_and_resign("__dyld_NSSymbolDefinitionNameInObjectFileImage", &p
);
906 return p(objectFileImage
, ordinal
);
910 * NSSymbolReferenceCountInObjectFileImage() returns the number of references
911 * to undefined symbols the NSObjectFileImage.
914 NSSymbolReferenceCountInObjectFileImage(
915 NSObjectFileImage objectFileImage
)
918 return dyld3::NSSymbolReferenceCountInObjectFileImage(objectFileImage
);
920 DYLD_LOCK_THIS_BLOCK
;
921 typedef uint32_t (*funcType
)(NSObjectFileImage
);
922 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
925 dyld_func_lookup_and_resign("__dyld_NSSymbolReferenceCountInObjectFileImage", &p
);
927 return p(objectFileImage
);
931 * NSSymbolReferenceNameInObjectFileImage() returns the name of the i'th
932 * undefined symbol in the NSObjectFileImage. If the ordinal specified is
933 * outside the range [0..NSSymbolReferenceCountInObjectFileImage], NULL will be
937 NSSymbolReferenceNameInObjectFileImage(
938 NSObjectFileImage objectFileImage
,
940 bool *tentative_definition
) /* can be NULL */
943 return dyld3::NSSymbolReferenceNameInObjectFileImage(objectFileImage
, ordinal
, tentative_definition
);
945 DYLD_LOCK_THIS_BLOCK
;
946 typedef const char* (*funcType
)(NSObjectFileImage
, uint32_t, bool*);
947 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
950 dyld_func_lookup_and_resign("__dyld_NSSymbolReferenceNameInObjectFileImage", &p
);
952 return p(objectFileImage
, ordinal
, tentative_definition
);
956 * NSIsSymbolDefinedInObjectFileImage() returns TRUE if the specified symbol
957 * name has a definition in the NSObjectFileImage and FALSE otherwise.
960 NSIsSymbolDefinedInObjectFileImage(
961 NSObjectFileImage objectFileImage
,
962 const char* symbolName
)
965 return dyld3::NSIsSymbolDefinedInObjectFileImage(objectFileImage
, symbolName
);
967 DYLD_LOCK_THIS_BLOCK
;
968 typedef bool (*funcType
)(NSObjectFileImage
, const char*);
969 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
972 dyld_func_lookup_and_resign("__dyld_NSIsSymbolDefinedInObjectFileImage", &p
);
974 return p(objectFileImage
, symbolName
);
978 * NSGetSectionDataInObjectFileImage() returns a pointer to the section contents
979 * in the NSObjectFileImage for the specified segmentName and sectionName if
980 * it exists and it is not a zerofill section. If not it returns NULL. If
981 * the parameter size is not NULL the size of the section is also returned
982 * indirectly through that pointer.
985 NSGetSectionDataInObjectFileImage(
986 NSObjectFileImage objectFileImage
,
987 const char* segmentName
,
988 const char* sectionName
,
989 unsigned long *size
) /* can be NULL */
992 return dyld3::NSGetSectionDataInObjectFileImage(objectFileImage
, segmentName
, sectionName
, size
);
994 DYLD_LOCK_THIS_BLOCK
;
995 typedef void* (*funcType
)(NSObjectFileImage
, const char*, const char*, unsigned long*);
996 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
999 dyld_func_lookup_and_resign("__dyld_NSGetSectionDataInObjectFileImage", &p
);
1001 return p(objectFileImage
, segmentName
, sectionName
, size
);
1007 NSLinkEditErrors
*c
,
1009 const char* *fileName
,
1010 const char* *errorString
)
1013 return dyld3::NSLinkEditError(c
, errorNumber
, fileName
, errorString
);
1015 DYLD_LOCK_THIS_BLOCK
;
1016 typedef void (*funcType
)(NSLinkEditErrors
*c
,
1018 const char* *fileName
,
1019 const char* *errorString
);
1020 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1023 dyld_func_lookup_and_resign("__dyld_link_edit_error", &p
);
1025 p(c
, errorNumber
, fileName
, errorString
);
1034 return dyld3::NSUnLinkModule(module, options
);
1036 DYLD_LOCK_THIS_BLOCK
;
1037 typedef bool (*funcType
)(NSModule
module, uint32_t options
);
1038 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1041 dyld_func_lookup_and_resign("__dyld_unlink_module", &p
);
1043 return p(module, options
);
1046 #if OBSOLETE_DYLD_API
1049 NSModule moduleToReplace
,
1050 NSObjectFileImage newObjectFileImage
,
1058 #endif // DEPRECATED_APIS_SUPPORTED
1061 *_NSGetExecutablePath copies the path of the executable into the buffer and
1062 * returns 0 if the path was successfully copied in the provided buffer. If the
1063 * buffer is not large enough, -1 is returned and the expected buffer size is
1064 * copied in *bufsize. Note that _NSGetExecutablePath will return "a path" to
1065 * the executable not a "real path" to the executable. That is the path may be
1066 * a symbolic link and not the real file. And with deep directories the total
1067 * bufsize needed could be more than MAXPATHLEN.
1070 _NSGetExecutablePath(
1075 return dyld3::_NSGetExecutablePath(buf
, bufsize
);
1077 DYLD_NO_LOCK_THIS_BLOCK
;
1078 typedef int (*funcType
)(char *buf
, uint32_t *bufsize
);
1079 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1082 dyld_func_lookup_and_resign("__dyld__NSGetExecutablePath", &p
);
1083 return(p(buf
, bufsize
));
1086 #if DEPRECATED_APIS_SUPPORTED
1088 _dyld_lookup_and_bind(
1089 const char* symbol_name
,
1094 return dyld3::_dyld_lookup_and_bind(symbol_name
, address
, module);
1096 DYLD_LOCK_THIS_BLOCK
;
1097 typedef void (*funcType
)(const char*, void** , NSModule
*);
1098 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1101 dyld_func_lookup_and_resign("__dyld_lookup_and_bind", &p
);
1102 p(symbol_name
, address
, module);
1106 _dyld_lookup_and_bind_with_hint(
1107 const char* symbol_name
,
1108 const char* library_name_hint
,
1112 DYLD_LOCK_THIS_BLOCK
;
1113 typedef void (*funcType
)(const char*, const char*, void**, NSModule
*);
1114 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1117 dyld_func_lookup_and_resign("__dyld_lookup_and_bind_with_hint", &p
);
1118 p(symbol_name
, library_name_hint
, address
, module);
1121 #if OBSOLETE_DYLD_API
1123 _dyld_lookup_and_bind_objc(
1124 const char* symbol_name
,
1128 DYLD_LOCK_THIS_BLOCK
;
1129 typedef void (*funcType
)(const char* , void**, NSModule
*) = NULL
;
1132 dyld_func_lookup_and_resign("__dyld_lookup_and_bind_objc", &p
);
1133 p(symbol_name
, address
, module);
1138 _dyld_lookup_and_bind_fully(
1139 const char* symbol_name
,
1143 DYLD_LOCK_THIS_BLOCK
;
1144 typedef void (*funcType
)(const char*, void**, NSModule
*);
1145 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1148 dyld_func_lookup_and_resign("__dyld_lookup_and_bind_fully", &p
);
1149 p(symbol_name
, address
, module);
1153 _dyld_bind_fully_image_containing_address(
1154 const void* address
)
1156 DYLD_LOCK_THIS_BLOCK
;
1157 typedef bool (*funcType
)(const void*);
1158 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1161 dyld_func_lookup_and_resign("__dyld_bind_fully_image_containing_address", &p
);
1164 #endif // DEPRECATED_APIS_SUPPORTED
1168 * _dyld_register_func_for_add_image registers the specified function to be
1169 * called when a new image is added (a bundle or a dynamic shared library) to
1170 * the program. When this function is first registered it is called for once
1171 * for each image that is currently part of the program.
1174 _dyld_register_func_for_add_image(
1175 void (*func
)(const struct mach_header
*mh
, intptr_t vmaddr_slide
))
1178 return dyld3::_dyld_register_func_for_add_image(func
);
1180 DYLD_LOCK_THIS_BLOCK
;
1181 // Func must be a "void *" because dyld itself calls it. DriverKit
1182 // libdyld.dylib uses diversified C function pointers but its dyld (the
1183 // plain OS one) doesn't, so it must be resigned with 0 discriminator.
1184 typedef void (*funcType
)(void *func
);
1185 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1188 dyld_func_lookup_and_resign("__dyld_register_func_for_add_image", &p
);
1189 p(reinterpret_cast<void *>(func
));
1193 * _dyld_register_func_for_remove_image registers the specified function to be
1194 * called when an image is removed (a bundle or a dynamic shared library) from
1198 _dyld_register_func_for_remove_image(
1199 void (*func
)(const struct mach_header
*mh
, intptr_t vmaddr_slide
))
1202 return dyld3::_dyld_register_func_for_remove_image(func
);
1204 DYLD_LOCK_THIS_BLOCK
;
1205 // Func must be a "void *" because dyld itself calls it. DriverKit
1206 // libdyld.dylib uses diversified C function pointers but its dyld (the
1207 // plain OS one) doesn't, so it must be resigned with 0 discriminator.
1208 typedef void (*funcType
)(void *func
);
1209 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1212 dyld_func_lookup_and_resign("__dyld_register_func_for_remove_image", &p
);
1213 p(reinterpret_cast<void *>(func
));
1216 #if OBSOLETE_DYLD_API
1218 * _dyld_register_func_for_link_module registers the specified function to be
1219 * called when a module is bound into the program. When this function is first
1220 * registered it is called for once for each module that is currently bound into
1224 _dyld_register_func_for_link_module(
1225 void (*func
)(NSModule
module))
1227 DYLD_LOCK_THIS_BLOCK
;
1228 // Func must be a "void *" because dyld itself calls it. DriverKit
1229 // libdyld.dylib uses diversified C function pointers but its dyld (the
1230 // plain OS one) doesn't, so it must be resigned with 0 discriminator.
1231 static void (*funcType
)(void *func
) = NULL
;
1234 dyld_func_lookup_and_resign("__dyld_register_func_for_link_module", &p
);
1235 p(reinterpret_cast<void *>(func
));
1239 * _dyld_register_func_for_unlink_module registers the specified function to be
1240 * called when a module is unbound from the program.
1243 _dyld_register_func_for_unlink_module(
1244 void (*func
)(NSModule
module))
1246 DYLD_LOCK_THIS_BLOCK
;
1247 // Func must be a "void *" because dyld itself calls it. DriverKit
1248 // libdyld.dylib uses diversified C function pointers but its dyld (the
1249 // plain OS one) doesn't, so it must be resigned with 0 discriminator.
1250 static void (*funcType
)(void *func
) = NULL
;
1253 dyld_func_lookup_and_resign("__dyld_register_func_for_unlink_module", &p
);
1254 p(reinterpret_cast<void *>(func
));
1258 * _dyld_register_func_for_replace_module registers the specified function to be
1259 * called when a module is to be replace with another module in the program.
1262 _dyld_register_func_for_replace_module(
1263 void (*func
)(NSModule oldmodule
, NSModule newmodule
))
1265 DYLD_LOCK_THIS_BLOCK
;
1266 // Func must be a "void *" because dyld itself calls it. DriverKit
1267 // libdyld.dylib uses diversified C function pointers but its dyld (the
1268 // plain OS one) doesn't, so it must be resigned with 0 discriminator.
1269 typedef void (*funcType
)(void *func
) = NULL
;
1272 dyld_func_lookup_and_resign("__dyld_register_func_for_replace_module", &p
);
1273 p(reinterpret_cast<void *>(func
));
1278 * _dyld_get_objc_module_sect_for_module is passed a module and sets a
1279 * pointer to the (__OBJC,__module) section and its size for the specified
1283 _dyld_get_objc_module_sect_for_module(
1286 unsigned long *size
)
1288 DYLD_LOCK_THIS_BLOCK
;
1289 typedef void (*funcType
)(NSModule
module,
1291 unsigned long *size
) = NULL
;
1294 dyld_func_lookup_and_resign("__dyld_get_objc_module_sect_for_module", &p
);
1295 p(module, objc_module
, size
);
1300 #if DEPRECATED_APIS_SUPPORTED
1304 // this function exists for compatiblity only
1310 _dyld_image_count(void)
1313 return dyld3::_dyld_image_count();
1315 DYLD_NO_LOCK_THIS_BLOCK
;
1316 typedef uint32_t (*funcType
)(void);
1317 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1320 dyld_func_lookup_and_resign("__dyld_image_count", &p
);
1324 const struct mach_header
*
1325 _dyld_get_image_header(uint32_t image_index
)
1328 return dyld3::_dyld_get_image_header(image_index
);
1330 DYLD_NO_LOCK_THIS_BLOCK
;
1331 typedef struct mach_header
* (*funcType
)(uint32_t image_index
);
1332 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1335 dyld_func_lookup_and_resign("__dyld_get_image_header", &p
);
1336 return(p(image_index
));
1340 _dyld_get_image_vmaddr_slide(uint32_t image_index
)
1343 return dyld3::_dyld_get_image_vmaddr_slide(image_index
);
1345 DYLD_NO_LOCK_THIS_BLOCK
;
1346 typedef unsigned long (*funcType
)(uint32_t image_index
);
1347 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1350 dyld_func_lookup_and_resign("__dyld_get_image_vmaddr_slide", &p
);
1351 return(p(image_index
));
1355 _dyld_get_image_name(uint32_t image_index
)
1358 return dyld3::_dyld_get_image_name(image_index
);
1360 DYLD_NO_LOCK_THIS_BLOCK
;
1361 typedef const char* (*funcType
)(uint32_t image_index
);
1362 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1365 dyld_func_lookup_and_resign("__dyld_get_image_name", &p
);
1366 return(p(image_index
));
1369 // SPI in Mac OS X 10.6
1370 intptr_t _dyld_get_image_slide(const struct mach_header
* mh
)
1372 // always use dyld3 version because it does better error handling
1373 return dyld3::_dyld_get_image_slide(mh
);
1376 const struct mach_header
*
1377 _dyld_get_prog_image_header()
1380 return dyld3::_dyld_get_prog_image_header();
1382 DYLD_LOCK_THIS_BLOCK
;
1383 typedef const struct mach_header
* (*funcType
)(void);
1384 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1387 dyld_func_lookup_and_resign("__dyld_get_prog_image_header", &p
);
1391 #if DEPRECATED_APIS_SUPPORTED
1393 _dyld_image_containing_address(const void* address
)
1396 return dyld3::_dyld_image_containing_address(address
);
1398 DYLD_LOCK_THIS_BLOCK
;
1399 typedef bool (*funcType
)(const void*);
1400 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1403 dyld_func_lookup_and_resign("__dyld_image_containing_address", &p
);
1407 const struct mach_header
*
1408 _dyld_get_image_header_containing_address(
1409 const void* address
)
1412 return dyld3::_dyld_get_image_header_containing_address(address
);
1414 DYLD_LOCK_THIS_BLOCK
;
1415 typedef const struct mach_header
* (*funcType
)(const void*);
1416 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1419 dyld_func_lookup_and_resign("__dyld_get_image_header_containing_address", &p
);
1423 bool _dyld_launched_prebound(void)
1425 DYLD_LOCK_THIS_BLOCK
;
1426 typedef bool (*funcType
)(void);
1427 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1430 dyld_func_lookup_and_resign("__dyld_launched_prebound", &p
);
1434 bool _dyld_all_twolevel_modules_prebound(void)
1436 DYLD_LOCK_THIS_BLOCK
;
1437 typedef bool (*funcType
)(void);
1438 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1441 dyld_func_lookup_and_resign("__dyld_all_twolevel_modules_prebound", &p
);
1444 #endif // DEPRECATED_APIS_SUPPORTED
1447 #include <dlfcn_private.h>
1449 #include <pthread.h>
1451 #include <mach-o/dyld.h>
1452 #include "dyldLibSystemInterface.h"
1455 // pthread key used to access per-thread dlerror message
1456 static pthread_key_t dlerrorPerThreadKey
;
1457 static bool dlerrorPerThreadKeyInitialized
= false;
1459 // data kept per-thread
1460 struct dlerrorPerThreadData
1462 size_t sizeAllocated
;
1466 // function called by dyld to get buffer to store dlerror message
1467 static char* getPerThreadBufferFor_dlerror(size_t sizeRequired
)
1469 // ok to create key lazily because this function is called within dyld lock, so there is no race condition
1470 if (!dlerrorPerThreadKeyInitialized
) {
1471 // create key and tell pthread package to call free() on any data associated with key if thread dies
1472 pthread_key_create(&dlerrorPerThreadKey
, &free
);
1473 dlerrorPerThreadKeyInitialized
= true;
1476 const size_t size
= (sizeRequired
< 256) ? 256 : sizeRequired
;
1477 dlerrorPerThreadData
* data
= (dlerrorPerThreadData
*)pthread_getspecific(dlerrorPerThreadKey
);
1478 if ( data
== NULL
) {
1479 //int mallocSize = offsetof(dlerrorPerThreadData, message[size]);
1480 const size_t mallocSize
= sizeof(dlerrorPerThreadData
)+size
;
1481 data
= (dlerrorPerThreadData
*)malloc(mallocSize
);
1482 data
->sizeAllocated
= size
;
1483 pthread_setspecific(dlerrorPerThreadKey
, data
);
1485 else if ( data
->sizeAllocated
< sizeRequired
) {
1487 //int mallocSize = offsetof(dlerrorPerThreadData, message[size]);
1488 const size_t mallocSize
= sizeof(dlerrorPerThreadData
)+size
;
1489 data
= (dlerrorPerThreadData
*)malloc(mallocSize
);
1490 data
->sizeAllocated
= size
;
1491 pthread_setspecific(dlerrorPerThreadKey
, data
);
1493 return data
->message
;
1496 // <rdar://problem/10595338> dlerror buffer leak
1497 // Only allocate buffer if an actual error message needs to be set
1498 static bool hasPerThreadBufferFor_dlerror()
1500 if (!dlerrorPerThreadKeyInitialized
)
1503 return (pthread_getspecific(dlerrorPerThreadKey
) != NULL
);
1506 #if TARGET_OS_DRIVERKIT
1507 static bool isLaunchdOwned()
1512 // use non-lazy pointer to vproc_swap_integer so that lazy binding does not recurse
1513 typedef vproc_err_t (*vswapproc
)(vproc_t vp
, vproc_gsk_t key
,int64_t *inval
, int64_t *outval
);
1514 static vswapproc swapProc
= &vproc_swap_integer
;
1516 static bool isLaunchdOwned()
1518 static bool checked
= false;
1519 static bool result
= false;
1523 (*swapProc
)(NULL
, VPROC_GSK_IS_MANAGED
, NULL
, &val
);
1524 result
= ( val
!= 0 );
1530 static void shared_cache_missing()
1532 // leave until dyld's that might call this are rare
1535 static void shared_cache_out_of_date()
1537 // leave until dyld's that might call this are rare
1540 // FIXME: This is a mess. Why can't Driverkit have its own dyld?
1541 static int cxa_atexit_thunk(void (*func
)(void *), void *arg
, void *dso
)
1543 // Func will have come from dyld and so be signed with 0 discriminator,
1544 // resign it appropriately before passing to the real __cxa_atexit.
1545 func
= ptrauth_auth_and_resign(func
, ptrauth_key_function_pointer
, 0,
1546 ptrauth_key_function_pointer
,
1547 ptrauth_function_pointer_type_discriminator(__typeof__(func
)));
1548 return __cxa_atexit(func
, arg
, dso
);
1551 template<typename FTy
> static FTy
*resign_for_dyld(FTy
*func
) {
1552 return ptrauth_auth_and_resign(func
, ptrauth_key_function_pointer
,
1553 ptrauth_function_pointer_type_discriminator(__typeof__(func
)),
1554 ptrauth_key_function_pointer
, 0);
1558 // the table passed to dyld containing thread helpers
1559 static dyld::LibSystemHelpers sHelpers
= { 13 };
1561 static const objc_opt::objc_opt_t
* gObjCOpt
= nullptr;
1563 // during initialization of libSystem this routine will run
1564 // and call dyld, registering the helper functions.
1566 extern "C" void tlv_initializer();
1567 void _dyld_initializer()
1569 sHelpers
.acquireGlobalDyldLock
= resign_for_dyld(&dyldGlobalLockAcquire
);
1570 sHelpers
.releaseGlobalDyldLock
= resign_for_dyld(&dyldGlobalLockRelease
);
1571 sHelpers
.getThreadBufferFor_dlerror
= resign_for_dyld(&getPerThreadBufferFor_dlerror
);
1572 sHelpers
.malloc
= resign_for_dyld(&malloc
);
1573 sHelpers
.free
= resign_for_dyld(&free
);
1574 sHelpers
.cxa_atexit
= resign_for_dyld(&cxa_atexit_thunk
);
1575 sHelpers
.dyld_shared_cache_missing
= resign_for_dyld(&shared_cache_missing
);
1576 sHelpers
.dyld_shared_cache_out_of_date
= resign_for_dyld(&shared_cache_out_of_date
);
1577 sHelpers
.acquireDyldInitializerLock
= NULL
;
1578 sHelpers
.releaseDyldInitializerLock
= NULL
;
1579 sHelpers
.pthread_key_create
= resign_for_dyld(&pthread_key_create
);
1580 sHelpers
.pthread_setspecific
= resign_for_dyld(&pthread_setspecific
);
1581 sHelpers
.malloc_size
= resign_for_dyld(&malloc_size
);
1582 sHelpers
.pthread_getspecific
= resign_for_dyld(&pthread_getspecific
);
1583 sHelpers
.cxa_finalize
= resign_for_dyld(&__cxa_finalize
);
1584 sHelpers
.startGlueToCallExit
= address_of_start
;
1585 sHelpers
.hasPerThreadBufferFor_dlerror
= resign_for_dyld(&hasPerThreadBufferFor_dlerror
);
1586 sHelpers
.isLaunchdOwned
= resign_for_dyld(&isLaunchdOwned
);
1587 sHelpers
.vm_alloc
= resign_for_dyld(&vm_allocate
);
1588 sHelpers
.mmap
= resign_for_dyld(&mmap
);
1589 sHelpers
.cxa_finalize_ranges
= resign_for_dyld(&__cxa_finalize_ranges
);
1591 typedef void (*funcType
)(dyld::LibSystemHelpers
*);
1592 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1594 // Get the optimized objc pointer now that the cache is loaded
1595 const dyld_all_image_infos
* allInfo
= _dyld_get_all_image_infos();
1596 if ( allInfo
!= nullptr ) {
1597 const DyldSharedCache
* cache
= (const DyldSharedCache
*)(allInfo
->sharedCacheBaseAddress
);
1598 if ( cache
!= nullptr )
1599 gObjCOpt
= cache
->objcOpt();
1603 dyld3::gAllImages
.applyInitialImages();
1604 #if TARGET_OS_IOS && !TARGET_OS_SIMULATOR
1605 // For binaries built before 13.0, set the lookup function if they need it
1606 if (dyld_get_program_sdk_version() < DYLD_PACKED_VERSION(13,0,0))
1607 setLookupFunc((void*)&dyld3::compatFuncLookup
);
1611 dyld_func_lookup_and_resign("__dyld_register_thread_helpers", &p
);
1619 int dladdr(const void* addr
, Dl_info
* info
)
1621 dyld3::ScopedTimer
timer(DBG_DYLD_TIMING_DLADDR
, (uint64_t)addr
, 0, 0);
1624 result
= dyld3::dladdr(addr
, info
);
1626 DYLD_LOCK_THIS_BLOCK
;
1627 typedef int (*funcType
)(const void* , Dl_info
*);
1628 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1631 dyld_func_lookup_and_resign("__dyld_dladdr", &p
);
1632 result
= p(addr
, info
);
1634 timer
.setData4(result
);
1635 timer
.setData5(info
!= NULL
? info
->dli_fbase
: 0);
1636 timer
.setData6(info
!= NULL
? info
->dli_saddr
: 0);
1640 #if !TARGET_OS_DRIVERKIT
1644 return dyld3::dlerror();
1646 DYLD_LOCK_THIS_BLOCK
;
1647 typedef char* (*funcType
)();
1648 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1651 dyld_func_lookup_and_resign("__dyld_dlerror", &p
);
1655 int dlclose(void* handle
)
1657 dyld3::ScopedTimer
timer(DBG_DYLD_TIMING_DLCLOSE
, (uint64_t)handle
, 0, 0);
1660 timer
.setData4(result
);
1661 return dyld3::dlclose(handle
);
1664 DYLD_LOCK_THIS_BLOCK
;
1665 typedef int (*funcType
)(void* handle
);
1666 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1669 dyld_func_lookup_and_resign("__dyld_dlclose", &p
);
1671 timer
.setData4(result
);
1675 static void* dlopen_internal(const char* path
, int mode
, void* callerAddress
)
1677 dyld3::ScopedTimer
timer(DBG_DYLD_TIMING_DLOPEN
, path
, mode
, 0);
1678 void* result
= nullptr;
1680 result
= dyld3::dlopen_internal(path
, mode
, callerAddress
);
1681 timer
.setData4(result
);
1685 // dlopen is special. locking is done inside dyld to allow initializer to run without lock
1686 DYLD_NO_LOCK_THIS_BLOCK
;
1688 typedef void* (*funcType
)(const char* path
, int, void*);
1689 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1692 dyld_func_lookup_and_resign("__dyld_dlopen_internal", &p
);
1693 result
= p(path
, mode
, callerAddress
);
1694 // use asm block to prevent tail call optimization
1695 // this is needed because dlopen uses __builtin_return_address() and depends on this glue being in the frame chain
1696 // <rdar://problem/5313172 dlopen() looks too far up stack, can cause crash>
1697 __asm__
volatile("");
1698 timer
.setData4(result
);
1703 void* dlopen(const char* path
, int mode
)
1705 void* result
= dlopen_internal(path
, mode
, __builtin_return_address(0));
1713 void* dlopen_from(const char* path
, int mode
, void* addressInCaller
)
1715 #if __has_feature(ptrauth_calls)
1716 addressInCaller
= __builtin_ptrauth_strip(addressInCaller
, ptrauth_key_asia
);
1718 return dlopen_internal(path
, mode
, addressInCaller
);
1722 void* dlopen_audited(const char* path
, int mode
)
1724 return dlopen(path
, mode
);
1728 bool dlopen_preflight(const char* path
)
1730 dyld3::ScopedTimer
timer(DBG_DYLD_TIMING_DLOPEN_PREFLIGHT
, path
, 0, 0);
1731 bool result
= false;
1734 result
= dyld3::dlopen_preflight_internal(path
);
1735 timer
.setData4(result
);
1739 DYLD_LOCK_THIS_BLOCK
;
1740 typedef bool (*funcType
)(const char* path
, void* callerAddress
);
1741 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1744 dyld_func_lookup_and_resign("__dyld_dlopen_preflight_internal", &p
);
1745 result
= p(path
, __builtin_return_address(0));
1746 timer
.setData4(result
);
1750 void* dlsym(void* handle
, const char* symbol
)
1752 dyld3::ScopedTimer
timer(DBG_DYLD_TIMING_DLSYM
, handle
, symbol
, 0);
1753 void* result
= nullptr;
1756 result
= dyld3::dlsym_internal(handle
, symbol
, __builtin_return_address(0));
1757 timer
.setData4(result
);
1761 DYLD_LOCK_THIS_BLOCK
;
1762 typedef void* (*funcType
)(void* handle
, const char* symbol
, void *callerAddress
);
1763 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1766 dyld_func_lookup_and_resign("__dyld_dlsym_internal", &p
);
1767 result
= p(handle
, symbol
, __builtin_return_address(0));
1768 timer
.setData4(result
);
1771 #endif // !TARGET_OS_DRIVERKIT
1774 const struct dyld_all_image_infos
* _dyld_get_all_image_infos()
1777 return dyld3::_dyld_get_all_image_infos();
1779 DYLD_NO_LOCK_THIS_BLOCK
;
1780 typedef struct dyld_all_image_infos
* (*funcType
)();
1781 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1784 dyld_func_lookup_and_resign("__dyld_get_all_image_infos", &p
);
1788 #if SUPPORT_ZERO_COST_EXCEPTIONS
1789 bool _dyld_find_unwind_sections(void* addr
, dyld_unwind_sections
* info
)
1792 return dyld3::_dyld_find_unwind_sections(addr
, info
);
1794 DYLD_NO_LOCK_THIS_BLOCK
;
1795 typedef void* (*funcType
)(void*, dyld_unwind_sections
*);
1796 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1799 dyld_func_lookup_and_resign("__dyld_find_unwind_sections", &p
);
1800 return p(addr
, info
);
1805 #if __i386__ || __x86_64__ || __arm__ || __arm64__
1806 __attribute__((visibility("hidden")))
1807 void* _dyld_fast_stub_entry(void* loadercache
, long lazyinfo
)
1809 DYLD_NO_LOCK_THIS_BLOCK
;
1810 typedef void* (*funcType
)(void*, long);
1811 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1814 dyld_func_lookup_and_resign("__dyld_fast_stub_entry", &p
);
1815 return p(loadercache
, lazyinfo
);
1820 const char* dyld_image_path_containing_address(const void* addr
)
1823 return dyld3::dyld_image_path_containing_address(addr
);
1825 DYLD_NO_LOCK_THIS_BLOCK
;
1826 typedef const char* (*funcType
)(const void*);
1827 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1830 dyld_func_lookup_and_resign("__dyld_image_path_containing_address", &p
);
1834 const struct mach_header
* dyld_image_header_containing_address(const void* addr
)
1837 return dyld3::dyld_image_header_containing_address(addr
);
1839 DYLD_NO_LOCK_THIS_BLOCK
;
1840 typedef const mach_header
* (*funcType
)(const void*);
1841 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1844 dyld_func_lookup_and_resign("__dyld_get_image_header_containing_address", &p
);
1849 bool dyld_shared_cache_some_image_overridden()
1852 return dyld3::dyld_shared_cache_some_image_overridden();
1854 DYLD_NO_LOCK_THIS_BLOCK
;
1855 typedef bool (*funcType
)();
1856 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1859 dyld_func_lookup_and_resign("__dyld_shared_cache_some_image_overridden", &p
);
1863 bool _dyld_get_shared_cache_uuid(uuid_t uuid
)
1866 return dyld3::_dyld_get_shared_cache_uuid(uuid
);
1868 DYLD_NO_LOCK_THIS_BLOCK
;
1869 typedef bool (*funcType
)(uuid_t
);
1870 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1873 dyld_func_lookup_and_resign("__dyld_get_shared_cache_uuid", &p
);
1877 const void* _dyld_get_shared_cache_range(size_t* length
)
1880 return dyld3::_dyld_get_shared_cache_range(length
);
1882 DYLD_NO_LOCK_THIS_BLOCK
;
1883 typedef const void* (*funcType
)(size_t*);
1884 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1887 dyld_func_lookup_and_resign("__dyld_get_shared_cache_range", &p
);
1891 bool _dyld_shared_cache_optimized()
1894 return dyld3::_dyld_shared_cache_optimized();
1896 const dyld_all_image_infos
* allInfo
= _dyld_get_all_image_infos();
1897 if ( allInfo
!= nullptr ) {
1898 const dyld_cache_header
* cacheHeader
= (dyld_cache_header
*)(allInfo
->sharedCacheBaseAddress
);
1899 if ( cacheHeader
!= nullptr )
1900 return (cacheHeader
->cacheType
== kDyldSharedCacheTypeProduction
);
1905 bool _dyld_shared_cache_is_locally_built()
1908 return dyld3::_dyld_shared_cache_is_locally_built();
1910 const dyld_all_image_infos
* allInfo
= _dyld_get_all_image_infos();
1911 if ( allInfo
!= nullptr ) {
1912 const dyld_cache_header
* cacheHeader
= (dyld_cache_header
*)(allInfo
->sharedCacheBaseAddress
);
1913 if ( cacheHeader
!= nullptr )
1914 return (cacheHeader
->locallyBuiltCache
== 1);
1919 const char* _dyld_shared_cache_real_path(const char* path
)
1921 const dyld_all_image_infos
* allInfo
= _dyld_get_all_image_infos();
1922 if ( allInfo
!= nullptr ) {
1923 const DyldSharedCache
* cache
= (const DyldSharedCache
*)(allInfo
->sharedCacheBaseAddress
);
1924 if ( cache
!= nullptr )
1925 return cache
->getCanonicalPath(path
);
1930 bool _dyld_shared_cache_contains_path(const char* path
)
1932 return _dyld_shared_cache_real_path(path
) != nullptr;
1936 uint32_t _dyld_launch_mode()
1939 return dyld3::_dyld_launch_mode();
1941 // in dyld2 mode all flag bits are zero
1945 void _dyld_images_for_addresses(unsigned count
, const void* addresses
[], struct dyld_image_uuid_offset infos
[])
1948 return dyld3::_dyld_images_for_addresses(count
, addresses
, infos
);
1950 DYLD_NO_LOCK_THIS_BLOCK
;
1951 typedef const void (*funcType
)(unsigned, const void*[], struct dyld_image_uuid_offset
[]);
1952 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1955 dyld_func_lookup_and_resign("__dyld_images_for_addresses", &p
);
1956 return p(count
, addresses
, infos
);
1959 void _dyld_register_for_image_loads(void (*func
)(const mach_header
* mh
, const char* path
, bool unloadable
))
1962 return dyld3::_dyld_register_for_image_loads(func
);
1964 DYLD_NO_LOCK_THIS_BLOCK
;
1965 typedef const void (*funcType
)(void (*)(const mach_header
* mh
, const char* path
, bool unloadable
));
1966 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1969 dyld_func_lookup_and_resign("__dyld_register_for_image_loads", &p
);
1973 void _dyld_register_for_bulk_image_loads(void (*func
)(unsigned imageCount
, const struct mach_header
* mhs
[], const char* paths
[]))
1976 return dyld3::_dyld_register_for_bulk_image_loads(func
);
1978 DYLD_NO_LOCK_THIS_BLOCK
;
1979 typedef const void (*funcType
)(void (*)(unsigned imageCount
, const mach_header
* mhs
[], const char* paths
[]));
1980 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
1983 dyld_func_lookup_and_resign("__dyld_register_for_bulk_image_loads", &p
);
1987 bool dyld_need_closure(const char* execPath
, const char* dataContainerRootDir
)
1989 return dyld3::dyld_need_closure(execPath
, dataContainerRootDir
);
1992 bool dyld_process_is_restricted()
1995 return dyld3::dyld_process_is_restricted();
1997 DYLD_NO_LOCK_THIS_BLOCK
;
1998 typedef bool (*funcType
)();
1999 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
2002 dyld_func_lookup_and_resign("__dyld_process_is_restricted", &p
);
2006 const char* dyld_shared_cache_file_path()
2009 return dyld3::dyld_shared_cache_file_path();
2011 DYLD_NO_LOCK_THIS_BLOCK
;
2012 typedef const char* (*funcType
)();
2013 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
2016 dyld_func_lookup_and_resign("__dyld_shared_cache_file_path", &p
);
2020 bool dyld_has_inserted_or_interposing_libraries()
2023 return dyld3::dyld_has_inserted_or_interposing_libraries();
2025 DYLD_NO_LOCK_THIS_BLOCK
;
2026 typedef bool (*funcType
)();
2027 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
2030 dyld_func_lookup_and_resign("__dyld_has_inserted_or_interposing_libraries", &p
);
2034 bool _dyld_has_fix_for_radar(const char *rdar
) {
2035 // There is no point in shimming this to dyld3, actual functionality can exist purely in libSystem for
2036 // both dyld2 and dyld3.
2041 void dyld_dynamic_interpose(const struct mach_header
* mh
, const struct dyld_interpose_tuple array
[], size_t count
)
2044 return dyld3::dyld_dynamic_interpose(mh
, array
, count
);
2046 DYLD_LOCK_THIS_BLOCK
;
2047 typedef void (*funcType
)(const struct mach_header
* mh
, const struct dyld_interpose_tuple array
[], size_t count
);
2048 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
2051 dyld_func_lookup_and_resign("__dyld_dynamic_interpose", &p
);
2052 p(mh
, array
, count
);
2055 // SPI called __fork
2056 void _dyld_atfork_prepare()
2059 return dyld3::_dyld_atfork_prepare();
2062 // SPI called __fork
2063 void _dyld_atfork_parent()
2066 return dyld3::_dyld_atfork_parent();
2069 // SPI called __fork
2070 void _dyld_fork_child()
2073 return dyld3::_dyld_fork_child();
2075 DYLD_NO_LOCK_THIS_BLOCK
;
2076 typedef void (*funcType
)();
2077 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
2080 dyld_func_lookup_and_resign("__dyld_fork_child", &p
);
2086 static void* mapStartOfCache(const char* path
, size_t length
)
2088 struct stat statbuf
;
2089 if ( dyld3::stat(path
, &statbuf
) == -1 )
2092 if ( (size_t)statbuf
.st_size
< length
)
2095 int cache_fd
= dyld3::open(path
, O_RDONLY
, 0);
2099 void* result
= ::mmap(NULL
, length
, PROT_READ
, MAP_PRIVATE
, cache_fd
, 0);
2102 if ( result
== MAP_FAILED
)
2109 static const dyld_cache_header
* findCacheInDirAndMap(const uuid_t cacheUuid
, const char* dirPath
)
2111 DIR* dirp
= ::opendir(dirPath
);
2112 if ( dirp
!= NULL
) {
2114 dirent
* entp
= NULL
;
2115 char cachePath
[PATH_MAX
];
2116 while ( ::readdir_r(dirp
, &entry
, &entp
) == 0 ) {
2119 if ( entp
->d_type
!= DT_REG
)
2121 if ( strlcpy(cachePath
, dirPath
, PATH_MAX
) >= PATH_MAX
)
2123 if ( strlcat(cachePath
, "/", PATH_MAX
) >= PATH_MAX
)
2125 if ( strlcat(cachePath
, entp
->d_name
, PATH_MAX
) >= PATH_MAX
)
2127 if ( const dyld_cache_header
* cacheHeader
= (dyld_cache_header
*)mapStartOfCache(cachePath
, 0x00100000) ) {
2128 if ( (::memcmp(cacheHeader
, "dyld_", 5) != 0) || (::memcmp(cacheHeader
->uuid
, cacheUuid
, 16) != 0) ) {
2129 // wrong uuid, unmap and keep looking
2130 ::munmap((void*)cacheHeader
, 0x00100000);
2144 int dyld_shared_cache_find_iterate_text(const uuid_t cacheUuid
, const char* extraSearchDirs
[], void (^callback
)(const dyld_shared_cache_dylib_text_info
* info
))
2147 return dyld3::dyld_shared_cache_find_iterate_text(cacheUuid
, extraSearchDirs
, callback
);
2149 const dyld_cache_header
* cacheHeader
= NULL
;
2150 bool needToUnmap
= true;
2152 // get info from dyld about this process, to see if requested cache is already mapped into this process
2153 const dyld_all_image_infos
* allInfo
= _dyld_get_all_image_infos();
2154 if ( (allInfo
!= NULL
) && (allInfo
->sharedCacheBaseAddress
!= 0) && (memcmp(allInfo
->sharedCacheUUID
, cacheUuid
, 16) == 0) ) {
2155 // requested cache is already mapped, just re-use it
2156 cacheHeader
= (dyld_cache_header
*)(allInfo
->sharedCacheBaseAddress
);
2157 needToUnmap
= false;
2160 // look first is default location for cache files
2161 #if TARGET_OS_IPHONE
2162 cacheHeader
= findCacheInDirAndMap(cacheUuid
, IPHONE_DYLD_SHARED_CACHE_DIR
);
2164 cacheHeader
= findCacheInDirAndMap(cacheUuid
, MACOSX_MRM_DYLD_SHARED_CACHE_DIR
);
2166 // if not there, look in extra search locations
2167 if ( cacheHeader
== NULL
) {
2168 for (const char** p
= extraSearchDirs
; *p
!= NULL
; ++p
) {
2169 cacheHeader
= findCacheInDirAndMap(cacheUuid
, *p
);
2170 if ( cacheHeader
!= NULL
)
2176 if ( cacheHeader
== NULL
)
2179 if ( cacheHeader
->mappingOffset
<= __offsetof(dyld_cache_header
, imagesTextOffset
) ) {
2180 // old cache without imagesText array
2182 ::munmap((void*)cacheHeader
, 0x00100000);
2186 // walk imageText table and call callback for each entry
2187 const dyld_cache_mapping_info
* mappings
= (dyld_cache_mapping_info
*)((char*)cacheHeader
+ cacheHeader
->mappingOffset
);
2188 const uint64_t cacheUnslidBaseAddress
= mappings
[0].address
;
2189 const dyld_cache_image_text_info
* imagesText
= (dyld_cache_image_text_info
*)((char*)cacheHeader
+ cacheHeader
->imagesTextOffset
);
2190 const dyld_cache_image_text_info
* imagesTextEnd
= &imagesText
[cacheHeader
->imagesTextCount
];
2191 for (const dyld_cache_image_text_info
* p
=imagesText
; p
< imagesTextEnd
; ++p
) {
2192 dyld_shared_cache_dylib_text_info dylibTextInfo
;
2193 dylibTextInfo
.version
= 2;
2194 dylibTextInfo
.loadAddressUnslid
= p
->loadAddress
;
2195 dylibTextInfo
.textSegmentSize
= p
->textSegmentSize
;
2196 dylibTextInfo
.path
= (char*)cacheHeader
+ p
->pathOffset
;
2197 ::memcpy(dylibTextInfo
.dylibUuid
, p
->uuid
, 16);
2198 dylibTextInfo
.textSegmentOffset
= p
->loadAddress
- cacheUnslidBaseAddress
;
2199 callback(&dylibTextInfo
);
2203 ::munmap((void*)cacheHeader
, 0x00100000);
2208 int dyld_shared_cache_iterate_text(const uuid_t cacheUuid
, void (^callback
)(const dyld_shared_cache_dylib_text_info
* info
))
2211 return dyld3::dyld_shared_cache_iterate_text(cacheUuid
, callback
);
2213 const char* extraSearchDirs
[] = { NULL
};
2214 return dyld_shared_cache_find_iterate_text(cacheUuid
, extraSearchDirs
, callback
);
2218 bool _dyld_is_memory_immutable(const void* addr
, size_t length
)
2221 return dyld3::_dyld_is_memory_immutable(addr
, length
);
2223 DYLD_NO_LOCK_THIS_BLOCK
;
2224 typedef bool (*funcType
)(const void*, size_t);
2225 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
2228 dyld_func_lookup_and_resign("__dyld_is_memory_immutable", &p
);
2229 return p(addr
, length
);
2233 void _dyld_objc_notify_register(_dyld_objc_notify_mapped mapped
,
2234 _dyld_objc_notify_init init
,
2235 _dyld_objc_notify_unmapped unmapped
)
2238 return dyld3::_dyld_objc_notify_register(mapped
, init
, unmapped
);
2240 DYLD_LOCK_THIS_BLOCK
;
2241 typedef bool (*funcType
)(_dyld_objc_notify_mapped
, _dyld_objc_notify_init
, _dyld_objc_notify_unmapped
);
2242 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
2245 dyld_func_lookup_and_resign("__dyld_objc_notify_register", &p
);
2246 p(mapped
, init
, unmapped
);
2249 void _dyld_missing_symbol_abort()
2251 return dyld3::_dyld_missing_symbol_abort();
2254 const char* _dyld_get_objc_selector(const char* selName
)
2256 // Check the shared cache table if it exists.
2257 if ( gObjCOpt
!= nullptr ) {
2258 if ( const objc_opt::objc_selopt_t
* selopt
= gObjCOpt
->selopt() ) {
2259 const char* name
= selopt
->get(selName
);
2260 if (name
!= nullptr)
2266 return dyld3::_dyld_get_objc_selector(selName
);
2271 void _dyld_for_each_objc_class(const char* className
,
2272 void (^callback
)(void* classPtr
, bool isLoaded
, bool* stop
)) {
2274 return dyld3::_dyld_for_each_objc_class(className
, callback
);
2277 void _dyld_for_each_objc_protocol(const char* protocolName
,
2278 void (^callback
)(void* protocolPtr
, bool isLoaded
, bool* stop
)) {
2280 return dyld3::_dyld_for_each_objc_protocol(protocolName
, callback
);
2283 void _dyld_register_driverkit_main(void (*mainFunc
)(void))
2286 return dyld3::_dyld_register_driverkit_main(mainFunc
);
2288 typedef bool (*funcType
)(void *);
2289 static funcType __ptrauth_dyld_function_ptr p
= NULL
;
2292 dyld_func_lookup_and_resign("__dyld_register_driverkit_main", &p
);
2293 p(reinterpret_cast<void *>(mainFunc
));
2296 // This is populated in the shared cache builder, so that the ranges are protected by __DATA_CONST
2297 // If we have a root, we can find this range in the shared cache libdyld at runtime
2298 typedef std::pair
<const uint8_t*, const uint8_t*> ObjCConstantRange
;
2301 __attribute__((section(("__DATA, __objc_ranges"))))
2303 __attribute__((section(("__DATA_CONST, __objc_ranges"))))
2305 __attribute__((used
))
2306 static ObjCConstantRange gSharedCacheObjCConstantRanges
[dyld_objc_string_kind
+ 1];
2308 static std::pair
<const void*, uint64_t> getDyldCacheConstantRanges() {
2309 const dyld_all_image_infos
* allInfo
= _dyld_get_all_image_infos();
2310 if ( allInfo
!= nullptr ) {
2311 const DyldSharedCache
* cache
= (const DyldSharedCache
*)(allInfo
->sharedCacheBaseAddress
);
2312 if ( cache
!= nullptr ) {
2313 return cache
->getObjCConstantRange();
2316 return { nullptr, 0 };
2319 bool _dyld_is_objc_constant(DyldObjCConstantKind kind
, const void* addr
) {
2320 assert(kind
<= dyld_objc_string_kind
);
2321 // The common case should be that the value is in range, as this is a security
2322 // check, so first test against the values in the struct. If we have a root then
2323 // we'll take the slow path later
2324 if ( (addr
>= gSharedCacheObjCConstantRanges
[kind
].first
) && (addr
< gSharedCacheObjCConstantRanges
[kind
].second
) ) {
2325 // Make sure that we are pointing at the start of a constant object, not in to the middle of it
2326 uint64_t offset
= (uint64_t)addr
- (uint64_t)gSharedCacheObjCConstantRanges
[kind
].first
;
2327 return (offset
% (uint64_t)DyldSharedCache::ConstantClasses::cfStringAtomSize
) == 0;
2330 // If we are in the shared cache, then the above check was sufficient, so this really isn't a valid constant address
2331 extern void* __dso_handle
;
2332 const dyld3::MachOAnalyzer
* ma
= (const dyld3::MachOAnalyzer
*)&__dso_handle
;
2333 if ( ma
->inDyldCache() )
2336 // We now know we are a root, so use the pointers in the shared cache libdyld version of gSharedCacheObjCConstantRanges
2337 static std::pair
<const void*, uint64_t> sharedCacheRanges
= { nullptr, ~0ULL };
2339 // FIXME: Should we fold this in as an inititalizer above?
2340 // That would mean we need to link against somewhere to get ___cxa_guard_acquire/___cxa_guard_release
2341 if ( sharedCacheRanges
.second
== ~0ULL )
2342 sharedCacheRanges
= getDyldCacheConstantRanges();
2344 // We have the range of the section in libdyld in the shared cache, now get an array of ranges from it
2345 uint64_t numRanges
= sharedCacheRanges
.second
/ sizeof(ObjCConstantRange
);
2346 if ( kind
>= numRanges
)
2349 const ObjCConstantRange
* rangeArrayBase
= (const ObjCConstantRange
*)sharedCacheRanges
.first
;
2350 if ( (addr
>= rangeArrayBase
[kind
].first
) && (addr
< rangeArrayBase
[kind
].second
) ) {
2351 // Make sure that we are pointing at the start of a constant object, not in to the middle of it
2352 uint64_t offset
= (uint64_t)addr
- (uint64_t)rangeArrayBase
[kind
].first
;
2353 return (offset
% (uint64_t)DyldSharedCache::ConstantClasses::cfStringAtomSize
) == 0;