]> git.saurik.com Git - apple/dyld.git/commitdiff
dyld-353.2.1.tar.gz os-x-1010 os-x-10101 os-x-10102 os-x-10103 os-x-10104 v353.2.1
authorApple <opensource@apple.com>
Fri, 24 Oct 2014 18:04:27 +0000 (18:04 +0000)
committerApple <opensource@apple.com>
Fri, 24 Oct 2014 18:04:27 +0000 (18:04 +0000)
98 files changed:
base.xcconfig [new file with mode: 0644]
doc/man/man1/dyld.1
dyld.xcconfig [new file with mode: 0644]
dyld.xcodeproj/project.pbxproj
dyld_sim-entitlements.plist [new file with mode: 0644]
include/mach-o/dyld.h
include/mach-o/dyld_priv.h
launch-cache/Architectures.hpp
launch-cache/FileAbstraction.hpp
launch-cache/MachOBinder.hpp
launch-cache/MachOFileAbstraction.hpp
launch-cache/MachOLayout.hpp
launch-cache/MachORebaser.hpp
launch-cache/MachOTrie.hpp
launch-cache/ObjCModernAbstraction.hpp
launch-cache/dsc_extractor.cpp
launch-cache/dsc_iterator.cpp
launch-cache/dsc_iterator.h
launch-cache/dyld_shared_cache_util.cpp
launch-cache/update_dyld_shared_cache.cpp
libdyld.xcconfig [new file with mode: 0644]
src/ImageLoader.cpp
src/ImageLoader.h
src/ImageLoaderMachO.cpp
src/ImageLoaderMachO.h
src/ImageLoaderMachOClassic.cpp
src/ImageLoaderMachOClassic.h
src/ImageLoaderMachOCompressed.cpp
src/ImageLoaderMachOCompressed.h
src/dyld.cpp
src/dyld.h
src/dyldAPIs.cpp
src/dyldAPIsInLibSystem.cpp
src/dyldExceptions.c
src/dyldInitialization.cpp
src/dyldLibSystemGlue.c
src/dyldLibSystemInterface.h
src/dyldNew.cpp
src/dyldStartup.s
src/dyldSyscallInterface.h
src/dyld_debug.c [deleted file]
src/dyld_gdb.cpp
src/dyld_stub_binder.s
src/glue.c
src/start_glue.h
src/start_glue.s
src/stub_binding_helper.s
src/threadLocalHelpers.s
src/threadLocalVariables.c
unit-tests/build-iPhoneOS-unit-tests
unit-tests/include/common.makefile
unit-tests/test-cases/dlclose-order/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlclose-order/bar.cxx [new file with mode: 0644]
unit-tests/test-cases/dlclose-order/base.c [new file with mode: 0644]
unit-tests/test-cases/dlclose-order/base.h [new file with mode: 0644]
unit-tests/test-cases/dlclose-order/baz.cxx [new file with mode: 0644]
unit-tests/test-cases/dlclose-order/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlclose-order/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-leak-threaded/main.c
unit-tests/test-cases/dlopen-leak/main.c
unit-tests/test-cases/dlopen-search-leak/main.c
unit-tests/test-cases/dlopen_preflight-leak-image-deny-single/main.c
unit-tests/test-cases/dlopen_preflight-leak/main.c
unit-tests/test-cases/image-remove-crash/Makefile [new file with mode: 0644]
unit-tests/test-cases/image-remove-crash/foo.c [new file with mode: 0644]
unit-tests/test-cases/image-remove-crash/main.c [new file with mode: 0644]
unit-tests/test-cases/image-state-deny-cache-leak/Makefile [new file with mode: 0644]
unit-tests/test-cases/image-state-deny-cache-leak/bar.c [new file with mode: 0644]
unit-tests/test-cases/image-state-deny-cache-leak/foo.c [new file with mode: 0644]
unit-tests/test-cases/image-state-deny-cache-leak/main.c [new file with mode: 0644]
unit-tests/test-cases/image-state-deny-leak/Makefile [new file with mode: 0644]
unit-tests/test-cases/image-state-deny-leak/bar.c [new file with mode: 0644]
unit-tests/test-cases/image-state-deny-leak/foo.c [new file with mode: 0644]
unit-tests/test-cases/image-state-deny-leak/main.c [new file with mode: 0644]
unit-tests/test-cases/interpose-basic-prebound/mystrdup.c
unit-tests/test-cases/interpose-basic/mystrdup.c
unit-tests/test-cases/interpose-dynamic-basic/Makefile [new file with mode: 0644]
unit-tests/test-cases/interpose-dynamic-basic/main.c [new file with mode: 0644]
unit-tests/test-cases/interpose-dynamic-dlsym/Makefile [new file with mode: 0644]
unit-tests/test-cases/interpose-dynamic-dlsym/foo.c [new file with mode: 0644]
unit-tests/test-cases/interpose-dynamic-dlsym/main.c [new file with mode: 0644]
unit-tests/test-cases/interpose-dynamic-lazy/Makefile [new file with mode: 0644]
unit-tests/test-cases/interpose-dynamic-lazy/foo.c [new file with mode: 0644]
unit-tests/test-cases/interpose-dynamic-lazy/main.c [new file with mode: 0644]
unit-tests/test-cases/rpath-no-trailing-slash/Makefile [new file with mode: 0644]
unit-tests/test-cases/rpath-no-trailing-slash/foo.c [new file with mode: 0644]
unit-tests/test-cases/rpath-no-trailing-slash/main.c [new file with mode: 0644]
unit-tests/test-cases/symbol-resolver-lazy-prebound/bar.o [new file with mode: 0644]
unit-tests/test-cases/text-perm-alt-segment/Makefile [new file with mode: 0644]
unit-tests/test-cases/text-perm-alt-segment/foo.c [new file with mode: 0644]
unit-tests/test-cases/text-perm-alt-segment/main.c [new file with mode: 0644]
unit-tests/test-cases/tlv-basic/Makefile
unit-tests/test-cases/tlv-basic/main.c
unit-tests/test-cases/tlv-dylib/Makefile
unit-tests/test-cases/upward-dylib-init-order/Makefile
unit-tests/test-cases/upward-dylib-init-order/common.c
unit-tests/test-cases/upward-dylib-init-order/common.h
unit-tests/test-cases/upward-dylib-init-order/u2.c [new file with mode: 0644]

diff --git a/base.xcconfig b/base.xcconfig
new file mode 100644 (file)
index 0000000..91782c7
--- /dev/null
@@ -0,0 +1,4 @@
+#include "<DEVELOPER_DIR>/AppleInternal/XcodeConfig/SimulatorSupport.xcconfig"
+
+// Set INSTALL_PATH[sdk=macosx*] when SimulatorSupport.xcconfig is unavailable
+INSTALL_PATH[sdk=macosx*] = $(INSTALL_PATH_ACTUAL)
index b89239d43c78ea8f15e457937bc659da2a43c68c..50729a7d2c86901d6cb2346e5e3254cdd748a9e1 100644 (file)
@@ -14,6 +14,8 @@ DYLD_FALLBACK_LIBRARY_PATH
 .br
 DYLD_VERSIONED_LIBRARY_PATH
 .br
+DYLD_PRINT_TO_FILE
+.br
 DYLD_ROOT_PATH
 .br
 DYLD_SHARED_REGION
@@ -34,8 +36,6 @@ DYLD_PRINT_LIBRARIES_POST_LAUNCH
 .br
 DYLD_BIND_AT_LAUNCH
 .br
-DYLD_NO_FIX_PREBINDING
-.br
 DYLD_DISABLE_DOFS
 .br
 DYLD_PRINT_APIS
@@ -146,6 +146,12 @@ Whichever has the larger current_version value will be used in the process whene
 a dylib with that install name is required.  This is similar to DYLD_LIBRARY_PATH
 except instead of always overriding, it only overrides is the supplied library is newer.
 .TP
+.B DYLD_PRINT_TO_FILE
+This is a path to a (writable) file. Normally, the dynamic linker writes all
+logging output (triggered by DYLD_PRINT_* settings) to file descriptor 2 
+(which is usually stderr).  But this setting causes the dynamic linker to
+write logging output to the specified file.  
+.TP
 .B DYLD_ROOT_PATH
 This is a colon separated list of directories.  The dynamic linker will prepend each of
 this directory paths to every image access until a file is found.    
@@ -211,13 +217,6 @@ lazily bound at the time of their first call.
 Right before the process's main() is called, dyld prints out information about how
 dyld spent its time.  Useful for analyzing launch performance.
 .TP
-.B DYLD_NO_FIX_PREBINDING
-Normally, dyld will trigger the dyld shared cache to be regenerated if it notices
-the cache is out of date while launching a process.  If this environment variable
-is set, dyld will not trigger a cache rebuild.  This is useful to set while installing
-a large set of OS dylibs, to ensure the cache is not regenerated until the install
-is complete.
-.TP
 .B DYLD_DISABLE_DOFS 
 Causes dyld not register dtrace static probes with the kernel.
 .TP
diff --git a/dyld.xcconfig b/dyld.xcconfig
new file mode 100644 (file)
index 0000000..7c6bbfe
--- /dev/null
@@ -0,0 +1,20 @@
+ALIGNMENT[arch=armv7s]     = -Wl,-segalign,0x4000
+
+BASE_ADDRESS[arch=armv7*]  =     0x1fe00000
+BASE_ADDRESS[arch=arm64]   =    0x120000000
+BASE_ADDRESS[arch=i386]    =     0x8fe00000
+BASE_ADDRESS[arch=x86_64]  = 0x7fff5fc00000
+
+ENTRY[sdk=*simulator*]     = -Wl,-e,_start_sim
+ENTRY[sdk=iphoneos*]       = -Wl,-e,__dyld_start
+ENTRY[sdk=macosx*]         = -Wl,-e,__dyld_start
+
+EXPORTED_SYMBOLS_FILE[sdk=*simulator*]   = $(SRCROOT)/src/dyld_sim.exp
+EXPORTED_SYMBOLS_FILE[sdk=iphoneos*]     = $(SRCROOT)/src/dyld.exp
+EXPORTED_SYMBOLS_FILE[sdk=macosx*]       = $(SRCROOT)/src/dyld.exp
+
+PRODUCT_NAME[sdk=*simulator*] = dyld_sim
+PRODUCT_NAME[sdk=iphoneos*]   = dyld
+PRODUCT_NAME[sdk=macosx*]     = dyld
+
+INSTALL_PATH_ACTUAL   = /usr/lib
index d8e3000a6a4ea7cff037f5ac487fa54bdb06d6dd..c0dde471d02c57afb7b8f7748a383f80e3b40fae 100644 (file)
@@ -17,7 +17,6 @@
                                F908137111D3FB5000626CC1 /* usr|local|include|mach-o */,
                                F908137211D3FB5000626CC1 /* usr|share|man|man1 */,
                                F908137311D3FB5000626CC1 /* usr|share|man|man3 */,
-                               F9F479FE152A63F2008F75C2 /* simulator clean up */,
                        );
                        dependencies = (
                                F9B4D78012AD9736000605A6 /* PBXTargetDependency */,
@@ -42,7 +41,6 @@
 /* End PBXAggregateTarget section */
 
 /* Begin PBXBuildFile section */
-               F906E2240639E96400B13DB2 /* dyld_debug.c in Sources */ = {isa = PBXBuildFile; fileRef = F906E2230639E96400B13DB2 /* dyld_debug.c */; };
                F908134C11D3ED6200626CC1 /* dyld.h in usr|include|mach-o */ = {isa = PBXBuildFile; fileRef = F9ED4CEA0630A80600DF4E74 /* dyld.h */; };
                F908134D11D3ED6200626CC1 /* dyld_images.h in usr|include|mach-o */ = {isa = PBXBuildFile; fileRef = F98D274C0AA79D7400416316 /* dyld_images.h */; };
                F908135911D3FA8700626CC1 /* dlfcn.h in usr|include */ = {isa = PBXBuildFile; fileRef = F99EE6AE06B48D4200BF1992 /* dlfcn.h */; };
                F908135111D3ED9000626CC1 /* usr|include|mach-o */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = "$(INSTALL_PATH_PREFIX)//usr/include/mach-o";
+                       dstPath = "$(INSTALL_PATH_PREFIX)/usr/include/mach-o";
                        dstSubfolderSpec = 0;
                        files = (
                                F908134C11D3ED6200626CC1 /* dyld.h in usr|include|mach-o */,
                F908137011D3FB5000626CC1 /* usr|include */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = "$(INSTALL_PATH_PREFIX)//usr/include";
+                       dstPath = "$(INSTALL_PATH_PREFIX)/usr/include";
                        dstSubfolderSpec = 0;
                        files = (
                                F908135911D3FA8700626CC1 /* dlfcn.h in usr|include */,
                F908137111D3FB5000626CC1 /* usr|local|include|mach-o */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = "$(INSTALL_PATH_PREFIX)//usr/local/include/mach-o";
+                       dstPath = "$(INSTALL_PATH_PREFIX)/usr/local/include/mach-o";
                        dstSubfolderSpec = 0;
                        files = (
                                F908135D11D3FACD00626CC1 /* dyld-interposing.h in usr|local|include|mach-o */,
                F908137211D3FB5000626CC1 /* usr|share|man|man1 */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = /usr/share/man/man1;
+                       dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man1";
                        dstSubfolderSpec = 0;
                        files = (
                                F908136411D3FB0300626CC1 /* dyld.1 in usr|share|man|man1 */,
                F908137311D3FB5000626CC1 /* usr|share|man|man3 */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = /usr/share/man/man3;
+                       dstPath = "$(INSTALL_PATH_PREFIX)/usr/share/man/man3";
                        dstSubfolderSpec = 0;
                        files = (
                                F908136811D3FB3A00626CC1 /* dladdr.3 in usr|share|man|man3 */,
                F98C78D10F7C00EA006257D2 /* usr|local|include|mach-o */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = "$(INSTALL_LOCATION)/usr/local/include/mach-o";
+                       dstPath = "$(INSTALL_PATH_PREFIX)$(INSTALL_LOCATION)/usr/local/include/mach-o";
                        dstSubfolderSpec = 0;
                        files = (
                                F98C78F00F7C02E8006257D2 /* dsc_iterator.h in usr|local|include|mach-o */,
                F9C69EFC14EC8AB8009CAE2E /* usr|local|include */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = "$(INSTALL_PATH_PREFIX)//usr/local/include";
+                       dstPath = "$(INSTALL_PATH_PREFIX)/usr/local/include";
                        dstSubfolderSpec = 0;
                        files = (
                                F9C69EFE14EC8AD2009CAE2E /* objc-shared-cache.h in usr|local|include */,
                F9D238DD0A9E2FEE002B55C7 /* usr|share|man|man1 */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = "$(INSTALL_LOCATION)/usr/$(LOCAL)/share/man/man1";
+                       dstPath = "$(INSTALL_PATH_PREFIX)$(INSTALL_LOCATION)/usr/$(LOCAL)/share/man/man1";
                        dstSubfolderSpec = 0;
                        files = (
                                F9D238DB0A9E2FD0002B55C7 /* update_dyld_shared_cache.1 in usr|share|man|man1 */,
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
+               3FC074DF188330C8005F11DD /* base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = base.xcconfig; sourceTree = "<group>"; };
                834A90AB0E1D85D600555761 /* ObjCLegacyAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ObjCLegacyAbstraction.hpp; sourceTree = "<group>"; };
                834A90AC0E1D85D600555761 /* ObjCModernAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ObjCModernAbstraction.hpp; sourceTree = "<group>"; };
                EF799FE9070D27BB00F78484 /* dyld.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; name = dyld.1; path = doc/man/man1/dyld.1; sourceTree = SOURCE_ROOT; };
                EF799FEE070D27BB00F78484 /* dlopen.3 */ = {isa = PBXFileReference; explicitFileType = text.man; fileEncoding = 30; name = dlopen.3; path = doc/man/man3/dlopen.3; sourceTree = SOURCE_ROOT; };
                EF799FEF070D27BB00F78484 /* dlsym.3 */ = {isa = PBXFileReference; explicitFileType = text.man; fileEncoding = 30; name = dlsym.3; path = doc/man/man3/dlsym.3; sourceTree = SOURCE_ROOT; };
                EF799FF0070D27BB00F78484 /* dyld.3 */ = {isa = PBXFileReference; explicitFileType = text.man; fileEncoding = 30; name = dyld.3; path = doc/man/man3/dyld.3; sourceTree = SOURCE_ROOT; };
-               F906E2230639E96400B13DB2 /* dyld_debug.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = dyld_debug.c; path = src/dyld_debug.c; sourceTree = "<group>"; };
                F913FAD90630A8AE00B7AE9D /* dyldAPIsInLibSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = dyldAPIsInLibSystem.cpp; path = src/dyldAPIsInLibSystem.cpp; sourceTree = "<group>"; };
                F918691408B16D2500E0F9DB /* dyld-interposing.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = "dyld-interposing.h"; path = "include/mach-o/dyld-interposing.h"; sourceTree = "<group>"; };
                F93666DF163B4C42002ECADA /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
                F94DB9030F0A9B1700323715 /* ImageLoaderMachOCompressed.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ImageLoaderMachOCompressed.h; path = src/ImageLoaderMachOCompressed.h; sourceTree = "<group>"; };
                F95C95160E994796007B7CB8 /* MachOTrie.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MachOTrie.hpp; sourceTree = "<group>"; };
                F976F548127B90F8004BA2A5 /* dyld.order */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = dyld.order; path = src/dyld.order; sourceTree = "<group>"; };
+               F97988FA187F706600EC2C8E /* dyld.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = dyld.xcconfig; sourceTree = "<group>"; };
+               F97988FB187F707A00EC2C8E /* libdyld.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = libdyld.xcconfig; sourceTree = "<group>"; };
                F981BB8B170FC24400A686D6 /* dyldSyscallInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dyldSyscallInterface.h; path = src/dyldSyscallInterface.h; sourceTree = "<group>"; };
                F98935B90A9A412B00FB6228 /* MachOBinder.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = MachOBinder.hpp; sourceTree = "<group>"; };
                F98935BA0A9A412B00FB6228 /* MachORebaser.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = MachORebaser.hpp; sourceTree = "<group>"; };
                F9ED4C870630A72200DF4E74 = {
                        isa = PBXGroup;
                        children = (
+                               3FC074DF188330C8005F11DD /* base.xcconfig */,
+                               F97988FA187F706600EC2C8E /* dyld.xcconfig */,
+                               F97988FB187F707A00EC2C8E /* libdyld.xcconfig */,
                                F9ED4CBB0630A7AA00DF4E74 /* src */,
                                F9ED4CC30630A7BE00DF4E74 /* doc */,
                                F9ED4CBE0630A7B100DF4E74 /* include */,
                                F9B01E3D0739ABDE00CF981B /* dyld.exp */,
                                F976F548127B90F8004BA2A5 /* dyld.order */,
                                F9AC7E930B7BB67700FEB38B /* version.c */,
-                               F918691408B16D2500E0F9DB /* dyld-interposing.h */,
                                F9A221E60F3A6D7C00D15F73 /* dyldLibSystemGlue.c */,
-                               F906E2230639E96400B13DB2 /* dyld_debug.c */,
                                F9A6D6E2116F9DF20051CC16 /* threadLocalVariables.c */,
                                F9A6D70B116FBBD10051CC16 /* threadLocalHelpers.s */,
                        );
                F9ED4CBE0630A7B100DF4E74 /* include */ = {
                        isa = PBXGroup;
                        children = (
+                               F918691408B16D2500E0F9DB /* dyld-interposing.h */,
                                F98D274C0AA79D7400416316 /* dyld_images.h */,
                                F9ED4CE80630A80600DF4E74 /* dyld_gdb.h */,
                                F9ED4CE90630A80600DF4E74 /* dyld_priv.h */,
                };
 /* End PBXGroup section */
 
-/* Begin PBXHeadersBuildPhase section */
-               F9D1000E14D8D0BA00099D91 /* Headers */ = {
-                       isa = PBXHeadersBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-/* End PBXHeadersBuildPhase section */
-
 /* Begin PBXNativeTarget section */
                F93937310A94FAF700070A07 /* update_dyld_shared_cache */ = {
                        isa = PBXNativeTarget;
                        isa = PBXNativeTarget;
                        buildConfigurationList = F9D1001714D8D0F100099D91 /* Build configuration list for PBXNativeTarget "dsc_extractor" */;
                        buildPhases = (
-                               F9D1000E14D8D0BA00099D91 /* Headers */,
                                F9D1000F14D8D0BA00099D91 /* Sources */,
                                F9D1001014D8D0BA00099D91 /* Frameworks */,
                        );
                                F9D050C811DD701A00FB0A29 /* configure archives */,
                                F9ED4C950630A76000DF4E74 /* Sources */,
                                F907E2490FA6469000BFEDBD /* install iPhone file */,
+                               F9213B3F18BFC9CB001CB6E8 /* simulator entitlement */,
                                F99B8EB60FEC236500701838 /* suppress macosx dyld_shared_cache_util */,
                        );
                        buildRules = (
                        buildConfigurationList = F9D8C7E1087B087300E93EFB /* Build configuration list for PBXNativeTarget "libdyld.dylib" */;
                        buildPhases = (
                                F9ED4C9C0630A76B00DF4E74 /* Sources */,
+                               F959621018849DF20003E4D4 /* add dyld symlink */,
                        );
                        buildRules = (
                                F921D31E070376F1000D1056 /* PBXBuildRule */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/bash;
-                       shellScript = "echo \"\" > ${DERIVED_FILE_DIR}/dyld_cache_config.h\n\nif [ -n \"${ARM_SDK}\" ]; then\n\techo -n \"#define ARM_SHARED_REGION_START \"  >> ${DERIVED_FILE_DIR}/dyld_cache_config.h\n\tawk '/define SHARED_REGION_BASE_ARM[ \\t]/ { print $3;}' \"${ARM_SDK}/usr/include/mach/shared_region.h\" >> ${DERIVED_FILE_DIR}/dyld_cache_config.h\n\techo \"\"  >> ${DERIVED_FILE_DIR}/dyld_cache_config.h\n\n\techo -n \"#define ARM_SHARED_REGION_SIZE \"  >> ${DERIVED_FILE_DIR}/dyld_cache_config.h\n\tawk '/define SHARED_REGION_SIZE_ARM[ \\t]/ { print $3;}' \"${ARM_SDK}/usr/include/mach/shared_region.h\" >> ${DERIVED_FILE_DIR}/dyld_cache_config.h\n\techo \"\"  >> ${DERIVED_FILE_DIR}/dyld_cache_config.h\nelse\n\tif [ -z ${RC_PURPLE} ]; then \n\t\techo \"#define ARM_SHARED_REGION_START 0x30000000 \" >> ${DERIVED_FILE_DIR}/dyld_cache_config.h\n\t\techo \"#define ARM_SHARED_REGION_SIZE  0x10000000 \" >> ${DERIVED_FILE_DIR}/dyld_cache_config.h\n\tfi\nfi\n\n";
+                       shellScript = "echo \"\" > ${DERIVED_FILE_DIR}/dyld_cache_config.h\n\nif [ -n \"${ARM_SDK}\" ]; then\n\techo -n \"#define ARM_SHARED_REGION_START \"  >> ${DERIVED_FILE_DIR}/dyld_cache_config.h\n\tawk '/define SHARED_REGION_BASE_ARM[ \\t]/ { print $3;}' \"${ARM_SDK}/usr/include/mach/shared_region.h\" >> ${DERIVED_FILE_DIR}/dyld_cache_config.h\n\techo \"\"  >> ${DERIVED_FILE_DIR}/dyld_cache_config.h\n\n\techo -n \"#define ARM_SHARED_REGION_SIZE \"  >> ${DERIVED_FILE_DIR}/dyld_cache_config.h\n\tawk '/define SHARED_REGION_SIZE_ARM[ \\t]/ { print $3;}' \"${ARM_SDK}/usr/include/mach/shared_region.h\" >> ${DERIVED_FILE_DIR}/dyld_cache_config.h\n\techo \"\"  >> ${DERIVED_FILE_DIR}/dyld_cache_config.h\n\n\techo -n \"#define ARM64_SHARED_REGION_START \"  >> ${DERIVED_FILE_DIR}/dyld_cache_config.h\n\tawk '/define SHARED_REGION_BASE_ARM64/ { print $3;}' \"${ARM_SDK}/usr/include/mach/shared_region.h\" >> ${DERIVED_FILE_DIR}/dyld_cache_config.h\n\techo \"\"  >> ${DERIVED_FILE_DIR}/dyld_cache_config.h\n\n\techo -n \"#define ARM64_SHARED_REGION_SIZE \"  >> ${DERIVED_FILE_DIR}/dyld_cache_config.h\n\tawk '/define SHARED_REGION_SIZE_ARM64/ { print $3;}' \"${ARM_SDK}/usr/include/mach/shared_region.h\" >> ${DERIVED_FILE_DIR}/dyld_cache_config.h\n\techo \"\"  >> ${DERIVED_FILE_DIR}/dyld_cache_config.h\nelse\n\tif [ -z ${RC_PURPLE} ]; then \n\t\techo \"#define ARM_SHARED_REGION_START    0x20000000 \" >> ${DERIVED_FILE_DIR}/dyld_cache_config.h\n\t\techo \"#define ARM_SHARED_REGION_SIZE     0x20000000 \" >> ${DERIVED_FILE_DIR}/dyld_cache_config.h\n\t\techo \"#define ARM64_SHARED_REGION_START 0x180000000 \" >> ${DERIVED_FILE_DIR}/dyld_cache_config.h\n\t\techo \"#define ARM64_SHARED_REGION_SIZE   0x20000000 \" >> ${DERIVED_FILE_DIR}/dyld_cache_config.h\n\tfi\nfi\n\n";
                        showEnvVarsInLog = 0;
                };
-               F991E3030FF1A4EC0082CCC9 /* do not install duplicates */ = {
+               F9213B3F18BFC9CB001CB6E8 /* simulator entitlement */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 8;
                        files = (
                        );
                        inputPaths = (
                        );
-                       name = "do not install duplicates";
+                       name = "simulator entitlement";
                        outputPaths = (
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                        shellPath = /bin/sh;
-                       shellScript = "if [ \"${INSTALL_LOCATION}\" = \"\" ] \nthen\n     # on iOS, libdyld builds arm libdsc.a and u_d_s_c builds intel libdsc.a\n     # on MacOSX, to avoid collision, u_d_s_c does not install libdsc.a\n\trm -rf ${DSTROOT}/usr/local/include\n\trm -rf ${DSTROOT}/usr/local/lib\nfi\n\nif [ -n \"${RC_PURPLE}\" ]\nthen\n    mkdir -p \"${DSTROOT}/${DEVELOPER_DIR}/Platforms/iPhoneOS.platform/usr/lib\"\n    mv \"${DSTROOT}/${DEVELOPER_DIR}/Platforms/iPhoneOS.platform/usr/local/lib/dsc_extractor.bundle\" \"${DSTROOT}/${DEVELOPER_DIR}/Platforms/iPhoneOS.platform/usr/lib/dsc_extractor.bundle\"\nfi";
+                       shellScript = "if [ \"${PLATFORM_NAME}\" = \"iphonesimulator\" ]\nthen\n    /usr/bin/codesign --force --sign - --entitlements ${SRCROOT}/dyld_sim-entitlements.plist ${INSTALL_DIR}/dyld_sim\nfi\n";
                        showEnvVarsInLog = 0;
                };
-               F99B8EB60FEC236500701838 /* suppress macosx dyld_shared_cache_util */ = {
+               F959621018849DF20003E4D4 /* add dyld symlink */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 8;
                        files = (
                        );
                        inputPaths = (
                        );
-                       name = "suppress macosx dyld_shared_cache_util";
+                       name = "add dyld symlink";
                        outputPaths = (
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                        shellPath = /bin/sh;
-                       shellScript = "# iPhone wants a copy of dyld_shared_cache_util on the device\n# MacOSX does not need a copy because update_dyld_shared_cache target already installed a copy\nif [ \"${PLATFORM_NAME}\" = \"macosx\" ] \nthen\n\trm -rf ${DSTROOT}/usr/local\nfi\n";
+                       shellScript = "if [ \"${PLATFORM_NAME}\" = \"iphonesimulator\" ]\nthen\n\tcd ${DSTROOT}/${INSTALL_PATH}\n\tln -s libdyld.dylib libdyld_sim.dylib\nfi\n";
                        showEnvVarsInLog = 0;
                };
-               F9D050C811DD701A00FB0A29 /* configure archives */ = {
+               F991E3030FF1A4EC0082CCC9 /* do not install duplicates */ = {
                        isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 12;
+                       buildActionMask = 8;
                        files = (
                        );
                        inputPaths = (
                        );
-                       name = "configure archives";
+                       name = "do not install duplicates";
                        outputPaths = (
-                               "$(DERIVED_SOURCES_DIR)/archives.txt",
                        );
-                       runOnlyForDeploymentPostprocessing = 0;
+                       runOnlyForDeploymentPostprocessing = 1;
                        shellPath = /bin/sh;
-                       shellScript = "# link with all .a files in /usr/local/lib/dyld\nls -1 ${SDKROOT}/usr/local/lib/dyld/*.a > ${DERIVED_SOURCES_DIR}/archives.txt \n\n# link with crash report archive if it exists\nif [ -f ${SDKROOT}/usr/local/lib/libCrashReporterClient.a ]\nthen\n  echo \\\"${SDKROOT}/usr/local/lib/libCrashReporterClient.a\\\" >> ${DERIVED_SOURCES_DIR}/archives.txt \nfi\n\n";
+                       shellScript = "if [ \"${INSTALL_LOCATION}\" = \"\" ] \nthen\n     # on iOS, libdyld builds arm libdsc.a and u_d_s_c builds intel libdsc.a\n     # on MacOSX, to avoid collision, u_d_s_c does not install libdsc.a\n\trm -rf ${DSTROOT}/usr/local/include\n\trm -rf ${DSTROOT}/usr/local/lib\nfi\n\nif [ -n \"${RC_PURPLE}\" ]\nthen\t\n    mkdir -p \"${DSTROOT}${INSTALL_PATH_PREFIX}/${INSTALL_LOCATION}/usr/lib\"\n    mv \"${DSTROOT}${INSTALL_PATH_PREFIX}/${INSTALL_LOCATION}/usr/local/lib/dsc_extractor.bundle\" \"${DSTROOT}${INSTALL_PATH_PREFIX}/${INSTALL_LOCATION}/usr/lib/dsc_extractor.bundle\"\nfi";
                        showEnvVarsInLog = 0;
                };
-               F9F479FE152A63F2008F75C2 /* simulator clean up */ = {
+               F99B8EB60FEC236500701838 /* suppress macosx dyld_shared_cache_util */ = {
                        isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
+                       buildActionMask = 8;
                        files = (
                        );
                        inputPaths = (
                        );
-                       name = "simulator clean up";
+                       name = "suppress macosx dyld_shared_cache_util";
                        outputPaths = (
                        );
+                       runOnlyForDeploymentPostprocessing = 1;
+                       shellPath = /bin/sh;
+                       shellScript = "# iPhone wants a copy of dyld_shared_cache_util on the device\n# MacOSX does not need a copy because update_dyld_shared_cache target already installed a copy\nif [ \"${PLATFORM_NAME}\" = \"macosx\" ] \nthen\n\trm -rf ${DSTROOT}/usr/local\nfi\n";
+                       showEnvVarsInLog = 0;
+               };
+               F9D050C811DD701A00FB0A29 /* configure archives */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 12;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       name = "configure archives";
+                       outputPaths = (
+                               "$(DERIVED_SOURCES_DIR)/archives.txt",
+                       );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/sh;
-                       shellScript = "# simulator needs just headers and dylib\nif [ \"${PLATFORM_NAME}\" = \"iphonesimulator\" ] \nthen\n\tmkdir -p ${DSTROOT}/${SDKROOT}/usr/lib/system/\n\tmv ${DSTROOT}/usr/lib/system/libdyld_sim.dylib   ${DSTROOT}/${SDKROOT}/usr/lib/system/\n\tmkdir -p ${DSTROOT}/${SDKROOT}/usr/local/include/mach-o\n\tmv ${DSTROOT}/usr/local/include/mach-o/dsc_iterator.h   ${DSTROOT}/${SDKROOT}/usr/local/include/mach-o/dsc_iterator.h\n\trm -rf ${DSTROOT}/usr/\n\tmkdir ${DSTROOT}/${SDKROOT}/usr/lib/system/host\n\tln -s /usr/lib/system/libdyld.dylib ${DSTROOT}/${SDKROOT}/usr/lib/system/host/libdyld.dylib\n\tinstall_name_tool -change /usr/lib/system/libdyld.dylib /usr/lib/system/host/libdyld.dylib ${DSTROOT}/${SDKROOT}/usr/lib/system/libdyld_sim.dylib\nfi\n";
+                       shellScript = "# link with all .a files in /usr/local/lib/dyld\nls -1 ${SDKROOT}/usr/local/lib/dyld/*.a > ${DERIVED_SOURCES_DIR}/archives.txt \n\n# link with crash report archive if it exists\nif [ -f ${SDKROOT}/usr/local/lib/libCrashReporterClient.a ]\nthen\n  echo \\\"${SDKROOT}/usr/local/lib/libCrashReporterClient.a\\\" >> ${DERIVED_SOURCES_DIR}/archives.txt \nfi\n\n";
                        showEnvVarsInLog = 0;
                };
 /* End PBXShellScriptBuildPhase section */
                                F9BA514B0ECE4F4200D1D62E /* dyld_stub_binder.s in Sources */,
                                F9A221E70F3A6D7C00D15F73 /* dyldLibSystemGlue.c in Sources */,
                                F913FADA0630A8AE00B7AE9D /* dyldAPIsInLibSystem.cpp in Sources */,
-                               F906E2240639E96400B13DB2 /* dyld_debug.c in Sources */,
                                F9A6D6E4116F9DF20051CC16 /* threadLocalVariables.c in Sources */,
                                F9A6D70C116FBBD10051CC16 /* threadLocalHelpers.s in Sources */,
                                F9D49CCC1458B95200F86ADD /* start_glue.s in Sources */,
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_OPTIMIZATION_LEVEL = 0;
                                INSTALLHDRS_COPY_PHASE = YES;
-                               INSTALL_PATH_PREFIX = "$(INSTALL_PATH_PREFIX_$(PLATFORM_NAME))";
-                               INSTALL_PATH_PREFIX_iphonesimulator = "$(SDKROOT)";
                                PRODUCT_NAME = libdyld;
                        };
                        name = Debug;
                                COPY_PHASE_STRIP = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                INSTALLHDRS_COPY_PHASE = YES;
-                               INSTALL_PATH_PREFIX = "$(INSTALL_PATH_PREFIX_$(PLATFORM_NAME))";
-                               INSTALL_PATH_PREFIX_iphonesimulator = "$(SDKROOT)";
                                PRODUCT_NAME = libdyld;
                                ZERO_LINK = NO;
                        };
                                GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
                                GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
                                HEADER_SEARCH_PATHS = "$(SRCROOT)/include";
-                               INSTALL_PATH = "$(INSTALL_LOCATION)/usr/$(LOCAL)/bin";
+                               INSTALL_PATH_ACTUAL = "$(INSTALL_LOCATION)/usr/$(LOCAL)/bin";
                                LOCAL = "$(LOCAL_$(RC_TARGET_CONFIG))";
                                LOCAL_iPhone = local;
                                OTHER_CPLUSPLUSFLAGS = (
                                GCC_MODEL_TUNING = G5;
                                GCC_OPTIMIZATION_LEVEL = 0;
                                GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
-                               INSTALL_PATH = "$(INSTALL_LOCATION)/usr/local/bin";
+                               INSTALL_PATH_ACTUAL = "$(INSTALL_LOCATION)/usr/local/bin";
                                PRODUCT_NAME = dyld_shared_cache_util;
                        };
                        name = Debug;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
-                               INSTALL_PATH = "$(INSTALL_LOCATION)/usr/local/bin";
+                               INSTALL_PATH_ACTUAL = "$(INSTALL_LOCATION)/usr/local/bin";
                                PRODUCT_NAME = dyld_shared_cache_util;
                                SKIP_INSTALL = NO;
                        };
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
                                GCC_OPTIMIZATION_LEVEL = 0;
-                               INSTALL_PATH = "$(INSTALL_LOCATION)/usr/local/lib";
+                               INSTALL_PATH_ACTUAL = "$(INSTALL_LOCATION)/usr/local/lib";
                                MACH_O_TYPE = mh_bundle;
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                DYLIB_CURRENT_VERSION = "";
                                EXECUTABLE_EXTENSION = bundle;
                                GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
-                               INSTALL_PATH = "$(INSTALL_LOCATION)/usr/local/lib";
+                               INSTALL_PATH_ACTUAL = "$(INSTALL_LOCATION)/usr/local/lib";
                                MACH_O_TYPE = mh_bundle;
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                };
                F9D8C7DE087B087300E93EFB /* Debug */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = F97988FA187F706600EC2C8E /* dyld.xcconfig */;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               ARCHS = "$(ARCHS_STANDARD_64_BIT)";
-                               BASE_ADDRESS_armv4t = 0x2fe00000;
-                               BASE_ADDRESS_armv5 = 0x2fe00000;
-                               BASE_ADDRESS_armv6 = 0x2fe00000;
-                               BASE_ADDRESS_armv7 = 0x2fe00000;
-                               BASE_ADDRESS_armv7f = 0x2fe00000;
-                               BASE_ADDRESS_armv7k = 0x2fe00000;
-                               BASE_ADDRESS_armv7s = 0x2fe00000;
-                               BASE_ADDRESS_i386 = 0x8fe00000;
-                               BASE_ADDRESS_ppc = 0x8fe00000;
-                               BASE_ADDRESS_x86_64 = 0x7fff5fc00000;
+                               ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
                                CLANG_CXX_LIBRARY = "libc++";
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                DEAD_CODE_STRIPPING = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
-                               ENTRY_iphoneos = "-Wl,-e,__dyld_start";
-                               ENTRY_iphonesimulator = "-Wl,-e,_start_sim";
-                               ENTRY_macosx = "-Wl,-e,__dyld_start";
-                               EXPORTED_SYMBOLS_FILE = "$(EXPORTS_$(PLATFORM_NAME))";
-                               EXPORTS_iphoneos = "$(SRCROOT)/src/dyld.exp";
-                               EXPORTS_iphonesimulator = "$(SRCROOT)/src/dyld_sim.exp";
-                               EXPORTS_macosx = "$(SRCROOT)/src/dyld.exp";
                                GCC_C_LANGUAGE_STANDARD = c99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_ENABLE_BUILTIN_FUNCTIONS = NO;
                                        ./include,
                                        "./launch-cache",
                                );
-                               INSTALL_PATH = /usr/lib;
                                LD_GENERATE_MAP_FILE = YES;
                                OTHER_CFLAGS = "";
                                OTHER_CPLUSPLUSFLAGS = (
                                        "$(OTHER_CFLAGS)",
                                );
                                OTHER_LDFLAGS = (
-                                       "-seg1addr",
-                                       "$(BASE_ADDRESS_$(CURRENT_ARCH))",
+                                       "-Wl,-seg1addr,$(BASE_ADDRESS)",
                                        "@$(DERIVED_SOURCES_DIR)/archives.txt",
                                        "-nostdlib",
                                        "-Wl,-dylinker",
                                        "-Wl,-dylinker_install_name,/usr/lib/dyld",
                                        "-stdlib=libc++",
-                                       "$(ALIGNMENT_$(CURRENT_ARCH))",
-                                       "$(ENTRY_$(PLATFORM_NAME))",
+                                       "$(ALIGNMENT)",
+                                       "$(ENTRY)",
                                );
-                               PRODUCT_NAME = "$(PRODUCT_NAME_$(PLATFORM_NAME))";
-                               PRODUCT_NAME_iphoneos = dyld;
-                               PRODUCT_NAME_iphonesimulator = dyld_sim;
-                               PRODUCT_NAME_macosx = dyld;
                                STRIPFLAGS = "-S";
                                UNSTRIPPED_PRODUCT = NO;
                                VERSIONING_SYSTEM = "apple-generic";
                };
                F9D8C7E0087B087300E93EFB /* Release */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = F97988FA187F706600EC2C8E /* dyld.xcconfig */;
                        buildSettings = {
-                               ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
-                               BASE_ADDRESS_armv4t = 0x2fe00000;
-                               BASE_ADDRESS_armv5 = 0x2fe00000;
-                               BASE_ADDRESS_armv6 = 0x2fe00000;
-                               BASE_ADDRESS_armv7 = 0x2fe00000;
-                               BASE_ADDRESS_armv7f = 0x2fe00000;
-                               BASE_ADDRESS_armv7k = 0x2fe00000;
-                               BASE_ADDRESS_armv7s = 0x2fe00000;
-                               BASE_ADDRESS_i386 = 0x8fe00000;
-                               BASE_ADDRESS_ppc = 0x8fe00000;
-                               BASE_ADDRESS_x86_64 = 0x7fff5fc00000;
                                CLANG_CXX_LIBRARY = "libc++";
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                DEAD_CODE_STRIPPING = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               ENTRY_iphoneos = "-Wl,-e,__dyld_start";
-                               ENTRY_iphonesimulator = "-Wl,-e,_start_sim";
-                               ENTRY_macosx = "-Wl,-e,__dyld_start";
-                               EXPORTED_SYMBOLS_FILE = "$(EXPORTS_$(PLATFORM_NAME))";
-                               EXPORTS_iphoneos = "$(SRCROOT)/src/dyld.exp";
-                               EXPORTS_iphonesimulator = "$(SRCROOT)/src/dyld_sim.exp";
-                               EXPORTS_macosx = "$(SRCROOT)/src/dyld.exp";
                                GCC_C_LANGUAGE_STANDARD = c99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_ENABLE_CPP_RTTI = NO;
                                        ./include,
                                        "./launch-cache",
                                );
-                               INSTALL_PATH = /usr/lib;
                                LD_GENERATE_MAP_FILE = YES;
                                ORDER_FILE = "$(SRCROOT)/src/dyld.order";
                                "OTHER_CFLAGS[arch=armv6]" = "-mthumb";
                                        "$(OTHER_CFLAGS)",
                                );
                                OTHER_LDFLAGS = (
-                                       "-seg1addr",
-                                       "$(BASE_ADDRESS_$(CURRENT_ARCH))",
+                                       "-Wl,-seg1addr,$(BASE_ADDRESS)",
                                        "@$(DERIVED_SOURCES_DIR)/archives.txt",
                                        "-nostdlib",
                                        "-Wl,-dylinker",
                                        "-Wl,-dylinker_install_name,/usr/lib/dyld",
                                        "-stdlib=libc++",
-                                       "$(ALIGNMENT_$(CURRENT_ARCH))",
-                                       "$(ENTRY_$(PLATFORM_NAME))",
+                                       "$(ALIGNMENT)",
+                                       "$(ENTRY)",
                                );
-                               PRODUCT_NAME = "$(PRODUCT_NAME_$(PLATFORM_NAME))";
-                               PRODUCT_NAME_iphoneos = dyld;
-                               PRODUCT_NAME_iphonesimulator = dyld_sim;
-                               PRODUCT_NAME_macosx = dyld;
                                STRIPFLAGS = "-S";
                                UNSTRIPPED_PRODUCT = NO;
                                VERSIONING_SYSTEM = "apple-generic";
                };
                F9D8C7E2087B087300E93EFB /* Debug */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = F97988FB187F707A00EC2C8E /* libdyld.xcconfig */;
                        buildSettings = {
                                ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
                                DEAD_CODE_STRIPPING = YES;
                                EXECUTABLE_PREFIX = lib;
-                               EXPORT_OPTIONS_iphonesimulator = "-exported_symbols_list $(SRCROOT)/src/libdyld_sim.exp";
                                GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_ENABLE_CPP_EXCEPTIONS = NO;
                                GCC_ENABLE_CPP_RTTI = NO;
                                GCC_OPTIMIZATION_LEVEL = 0;
                                GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
                                HEADER_SEARCH_PATHS = "$(SRCROOT)/include";
-                               INSTALL_PATH = /usr/lib/system;
-                               LIBSYSTEM_LIBS = "$(LIBSYSTEM_LIBS_$(PLATFORM_NAME))";
-                               LIBSYSTEM_LIBS_iphoneos = "-Wl,-upward-lsystem_platform -Wl,-upward-lsystem_malloc -Wl,-upward-lsystem_c -Wl,-upward-lsystem_pthread -Wl,-upward-llaunch -Wl,-upward-lsystem_blocks -Wl,-upward-lsystem_kernel";
-                               LIBSYSTEM_LIBS_iphonesimulator = "-Wl,-upward-lsystem_sim_c  -Wl,-upward-lSystem -Wl,-reexport_library,/usr/lib/system/libdyld.dylib -Wl,-allow_simulator_linking_to_macosx_dylibs";
-                               LIBSYSTEM_LIBS_macosx = "-Wl,-upward-lsystem_platform -Wl,-upward-lsystem_malloc -Wl,-upward-lsystem_c -Wl,-upward-lsystem_pthread -Wl,-upward-llaunch -Wl,-upward-lsystem_blocks -Wl,-upward-lsystem_kernel";
+                               INSTALLHDRS_COPY_PHASE = YES;
                                OTHER_LDFLAGS = (
                                        "-nostdlib",
                                        "$(LIBSYSTEM_LIBS)",
                                        "-umbrella",
                                        System,
-                                       "$(EXPORT_OPTIONS_$(PLATFORM_NAME))",
                                        "-L$(SDKROOT)/usr/lib/system",
                                );
-                               PRODUCT_NAME = "$(PRODUCT_NAME_$(PLATFORM_NAME))";
-                               PRODUCT_NAME_iphoneos = dyld;
-                               PRODUCT_NAME_iphonesimulator = dyld_sim;
-                               PRODUCT_NAME_macosx = dyld;
+                               PRODUCT_NAME = dyld;
+                               SKIP_INSTALL = NO;
                                WARNING_CFLAGS = (
                                        "-Wmost",
                                        "-Wno-four-char-constants",
                };
                F9D8C7E4087B087300E93EFB /* Release */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = F97988FB187F707A00EC2C8E /* libdyld.xcconfig */;
                        buildSettings = {
-                               ARCHS = (
-                                       x86_64,
-                                       i386,
-                               );
                                COPY_PHASE_STRIP = YES;
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                DEAD_CODE_STRIPPING = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                DYLIB_CURRENT_VERSION = "$(RC_ProjectSourceVersion)";
                                EXECUTABLE_PREFIX = lib;
-                               EXPORT_OPTIONS_iphonesimulator = "-exported_symbols_list $(SRCROOT)/src/libdyld_sim.exp";
                                GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_ENABLE_CPP_EXCEPTIONS = NO;
                                GCC_ENABLE_CPP_RTTI = NO;
                                GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
                                HEADER_SEARCH_PATHS = "$(SRCROOT)/include";
                                INSTALLHDRS_COPY_PHASE = YES;
-                               INSTALL_PATH = /usr/lib/system;
-                               LIBSYSTEM_LIBS = "$(LIBSYSTEM_LIBS_$(PLATFORM_NAME))";
-                               LIBSYSTEM_LIBS_iphoneos = "-Wl,-upward-lsystem_platform -Wl,-upward-lsystem_malloc -Wl,-upward-lsystem_c -Wl,-upward-lsystem_pthread -Wl,-upward-llaunch -Wl,-upward-lsystem_blocks -Wl,-upward-lsystem_kernel";
-                               LIBSYSTEM_LIBS_iphonesimulator = "-Wl,-upward-lsystem_sim_c  -Wl,-upward-lSystem -Wl,-reexport_library,/usr/lib/system/libdyld.dylib -Wl,-allow_simulator_linking_to_macosx_dylibs";
-                               LIBSYSTEM_LIBS_macosx = "-Wl,-upward-lsystem_platform -Wl,-upward-lsystem_malloc -Wl,-upward-lsystem_c -Wl,-upward-lsystem_pthread -Wl,-upward-llaunch -Wl,-upward-lsystem_blocks -Wl,-upward-lsystem_kernel";
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-fno-exceptions",
                                        "$(OTHER_CFLAGS)",
                                        "$(LIBSYSTEM_LIBS)",
                                        "-umbrella",
                                        System,
-                                       "$(EXPORT_OPTIONS_$(PLATFORM_NAME))",
                                        "-L$(SDKROOT)/usr/lib/system",
                                );
-                               PRODUCT_NAME = "$(PRODUCT_NAME_$(PLATFORM_NAME))";
-                               PRODUCT_NAME_iphoneos = dyld;
-                               PRODUCT_NAME_iphonesimulator = dyld_sim;
-                               PRODUCT_NAME_macosx = dyld;
+                               PRODUCT_NAME = dyld;
                                SEPARATE_STRIP = YES;
+                               SKIP_INSTALL = NO;
                                STRIP_INSTALLED_PRODUCT = YES;
                                VERSIONING_SYSTEM = "apple-generic";
                                WARNING_CFLAGS = (
                };
                F9D8C7EA087B087300E93EFB /* Debug */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = 3FC074DF188330C8005F11DD /* base.xcconfig */;
                        buildSettings = {
                                CLANG_CXX_LIBRARY = "compiler-default";
                        };
                };
                F9D8C7EC087B087300E93EFB /* Release */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = 3FC074DF188330C8005F11DD /* base.xcconfig */;
                        buildSettings = {
                                CLANG_CXX_LIBRARY = "compiler-default";
                        };
                                GCC_MODEL_TUNING = G5;
                                GCC_OPTIMIZATION_LEVEL = 0;
                                GCC_SYMBOLS_PRIVATE_EXTERN = YES;
-                               INSTALL_PATH = /usr/local/lib;
+                               INSTALL_PATH_ACTUAL = /usr/local/lib;
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                        "$(OTHER_CFLAGS)",
                                GCC_WARN_UNINITIALIZED_AUTOS = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
                                INSTALLHDRS_COPY_PHASE = YES;
-                               INSTALL_PATH = "$(INSTALL_LOCATION)/usr/local/lib";
+                               INSTALL_PATH_ACTUAL = "$(INSTALL_LOCATION)/usr/local/lib";
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                        "$(OTHER_CFLAGS)",
diff --git a/dyld_sim-entitlements.plist b/dyld_sim-entitlements.plist
new file mode 100644 (file)
index 0000000..0509fb2
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>com.apple.private.dyld_sim</key>
+       <true/>
+</dict>
+</plist>
index 642ca42f96b0e474ea1b570f189d91ebffe05e5a..ce411476b8d6ce1562163626cd592511eea956e8 100644 (file)
@@ -93,12 +93,6 @@ extern int _NSGetExecutablePath(char* buf, uint32_t* bufsize)                 __
 
 
 
-/*
- * _dyld_moninit() is a private interface between dyld and libSystem.
- */
-extern void _dyld_moninit(void (*monaddition)(char *lowpc, char *highpc))    __OSX_AVAILABLE_STARTING(__MAC_10_1, __IPHONE_2_0);
-
-
 
 
 
index 49d5775c5a4c1586e8c386d4783a9e7fca304cba..24208db58d08c5ad3f917a6aa531b2ce77e6fb7e 100644 (file)
@@ -40,12 +40,6 @@ extern "C" {
 //
 extern int _dyld_func_lookup(const char* dyld_func_name, void **address);
 
-
-//
-// _dyld_moninit() is a private interface between libSystem.dylib and dyld
-//
-extern void _dyld_moninit(void (*monaddition)(char *lowpc, char *highpc));
-
 //
 // private interface between libSystem.dylib and dyld
 //
@@ -185,6 +179,7 @@ extern const char* dyld_image_path_containing_address(const void* addr);
 #define DYLD_MACOSX_VERSION_10_7               0x000A0700
 #define DYLD_MACOSX_VERSION_10_8               0x000A0800
 #define DYLD_MACOSX_VERSION_10_9               0x000A0900
+#define DYLD_MACOSX_VERSION_10_10              0x000A0A00
 
 #define DYLD_IOS_VERSION_2_0           0x00020000
 #define DYLD_IOS_VERSION_2_1           0x00020100
@@ -201,6 +196,8 @@ extern const char* dyld_image_path_containing_address(const void* addr);
 #define DYLD_IOS_VERSION_6_0           0x00060000
 #define DYLD_IOS_VERSION_6_1           0x00060100
 #define DYLD_IOS_VERSION_7_0           0x00070000
+#define DYLD_IOS_VERSION_7_1           0x00070100
+#define DYLD_IOS_VERSION_8_0           0x00080000
 
 //
 // This is finds the SDK version a binary was built against.
@@ -240,15 +237,14 @@ extern uint32_t dyld_get_program_min_os_version();
 
 
 
-#if __IPHONE_OS_VERSION_MIN_REQUIRED   
 //
 // Returns if any OS dylib has overridden its copy in the shared cache
 //
 // Exists in iPhoneOS 3.1 and later 
+// Exists in Mac OS X 10.10 and later
 extern bool dyld_shared_cache_some_image_overridden();
-#endif
 
-       
+
        
 //
 // Returns if the process is setuid or is code signed with entitlements.
@@ -264,6 +260,20 @@ extern bool dyld_process_is_restricted();
 #define NSLINKMODULE_OPTION_CAN_UNLOAD                  0x20
 
 
+//
+// Update all bindings on specified image. 
+// Looks for uses of 'replacement' and changes it to 'replacee'.
+// NOTE: this is less safe than using static interposing via DYLD_INSERT_LIBRARIES
+// because the running program may have already copy the pointer values to other
+// locations that dyld does not know about.
+//
+struct dyld_interpose_tuple {
+       const void* replacement;
+       const void* replacee;
+};
+extern void dyld_dynamic_interpose(const struct mach_header* mh, const struct dyld_interpose_tuple array[], size_t count);
+
+
 
 #if __cplusplus
 }
index e26825d27436b5e4aa26c9e7fc1a0cca1a1d7422..fe3eea443f3969d41ebd781503a70d3a3730b67d 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -48,6 +48,11 @@ struct arm
        
 };
 
+struct arm64
+{
+       typedef Pointer64<LittleEndian>         P;
+
+};
 
 
 
index 8786e6adda91d54f49bb0376f52cf93e04347153..1d73d74dea3f5a302833aa40fa7b9a173a8e0a1a 100644 (file)
@@ -127,7 +127,7 @@ public:
        typedef _E                      E;
        
        static uint64_t getP(const uint_t& from)                                INLINE { return _E::get32(from); }
-       static void             setP(uint_t& into, uint64_t value)              INLINE { _E::set32(into, value); }
+       static void             setP(uint_t& into, uint64_t value)              INLINE { _E::set32(into, (uint32_t)value); }
 
     // Round to a P-size boundary
     template <typename T>
index 6f377270ac7d9a96de04190fd56516ffaaa5f29b..2b8a3ac5f95ba2ee082f311cb5060f3687f5f8e1 100644 (file)
@@ -286,10 +286,12 @@ Binder<A>::Binder(const MachOLayoutAbstraction& layout, uint64_t dyldBaseAddress
 template <> uint8_t    Binder<x86>::pointerRelocSize()   { return 2; }
 template <> uint8_t    Binder<x86_64>::pointerRelocSize() { return 3; }
 template <> uint8_t    Binder<arm>::pointerRelocSize() { return 2; }
+template <> uint8_t    Binder<arm64>::pointerRelocSize() { return 3; }
 
 template <> uint8_t    Binder<x86>::pointerRelocType()   { return GENERIC_RELOC_VANILLA; }
 template <> uint8_t    Binder<x86_64>::pointerRelocType() { return X86_64_RELOC_UNSIGNED; }
 template <> uint8_t    Binder<arm>::pointerRelocType() { return ARM_RELOC_VANILLA; }
+template <> uint8_t    Binder<arm64>::pointerRelocType() { return ARM64_RELOC_UNSIGNED; }
 
 
 template <typename A>
@@ -1140,7 +1142,28 @@ typename A::P::uint_t Binder<A>::findLazyPointerFor(const char* symbolName)
                }
                cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
        } 
+
+       if ( log ) fprintf(stderr, "not found shared lazy pointer for %s in %s, checking for re-export symbol\n", symbolName, this->getDylibID());
+       for (typename std::vector<SymbolReExport>::iterator it=fReExportedSymbols.begin(); it != fReExportedSymbols.end(); ++it) {
+               if ( strcmp(it->exportName, symbolName) != 0 )
+                       continue;
+
+               if ( it->dylibOrdinal <= 0 ) 
+                       throw "bad mach-o binary, special library ordinal not allowed in re-exported symbols in dyld shared cache";
+               
+               Binder<A>* binder = fDependentDylibs[it->dylibOrdinal-1].binder;
+               return binder->findLazyPointerFor(it->importName);
+       }
+
+       if ( log ) fprintf(stderr, "not found shared lazy pointer for %s in %s, checking re-export dylibs\n", symbolName, this->getDylibID());
+       for (typename std::vector<BinderAndReExportFlag>::iterator it = fDependentDylibs.begin(); it != fDependentDylibs.end(); ++it) {
+               if ( it->reExport ) {
+                       pint_t result = it->binder->findLazyPointerFor(symbolName);
+                       if ( result != 0 )
+                               return result;
+               }
+       }
+
        if ( log ) fprintf(stderr, "NOT found shared lazy pointer for %s in %s\n", symbolName, this->getDylibID());
     return 0;
 }
@@ -1155,7 +1178,7 @@ void Binder<A>::optimize()
             it->client->optimizeStub(it->symbolName, lpVMAddr);
         }
         else {
-            fprintf(stderr, "not able to optimize lazy pointer for %s in %s\n", it->symbolName, it->client->getDylibID());
+                       fprintf(stderr, "not able to optimize lazy pointer for %s in %s\n", it->symbolName, it->client->getDylibID());
         }
         
     }
index 6314caacedefe3951242b56fd45dfe6b82fc7ac7..7a65370a64b6e92c7e5731a2fc174f3312db650b 100644 (file)
@@ -61,6 +61,15 @@ struct uuid_command {
 #ifndef CPU_SUBTYPE_ARM_V7S
        #define CPU_SUBTYPE_ARM_V7S                     ((cpu_subtype_t) 11)
 #endif
+#ifndef CPU_SUBTYPE_ARM64_ALL
+       #define CPU_SUBTYPE_ARM64_ALL           ((cpu_subtype_t) 0)
+#endif
+#ifndef CPU_TYPE_ARM64
+       #define CPU_TYPE_ARM64                          ((cpu_type_t) (CPU_TYPE_ARM | CPU_ARCH_ABI64))
+#endif
+
+#define ARM64_RELOC_UNSIGNED            0 // for pointers
+
 
 #ifndef LC_LOAD_UPWARD_DYLIB
        #define LC_LOAD_UPWARD_DYLIB (0x23|LC_REQ_DYLD) /* load of dylib whose initializers run later */
@@ -85,6 +94,9 @@ struct uuid_command {
        #define LC_DYLIB_CODE_SIGN_DRS 0x2B
 #endif
 
+#ifndef CPU_SUBTYPE_X86_64_H
+       #define CPU_SUBTYPE_X86_64_H            ((cpu_subtype_t) 8) 
+#endif 
 
 
 #include "FileAbstraction.hpp"
index dbcbe76d1e3811f3a426d0c05ac1e2d96248cc63..4d90a1ef3e8aee43dbd135ba208e131d44dc9c63 100644 (file)
@@ -69,11 +69,11 @@ public:
        struct Segment
        {
        public:
-                                       Segment(uint64_t addr, uint64_t vmsize, uint64_t offset, uint64_t file_size, 
+                                       Segment(uint64_t addr, uint64_t vmsize, uint64_t offset, uint64_t file_size, uint64_t align,
                                                        uint32_t prot, const char* segName) : fOrigAddress(addr), fOrigSize(vmsize),
                                                        fOrigFileOffset(offset),  fOrigFileSize(file_size), fOrigPermissions(prot), 
-                                                       fSize(vmsize), fFileOffset(offset), fFileSize(file_size), fPermissions(prot),
-                                                       fNewAddress(0), fMappedAddress(NULL) {
+                                                       fSize(vmsize), fFileOffset(offset), fFileSize(file_size), fAlignment(align),
+                                                       fPermissions(prot), fNewAddress(0), fMappedAddress(NULL) {
                                                                strlcpy(fOrigName, segName, 16);
                                                        }
                                                        
@@ -85,6 +85,7 @@ public:
                bool            readable() const        { return fPermissions & VM_PROT_READ; }
                bool            writable() const        { return fPermissions & VM_PROT_WRITE; }
                bool            executable() const      { return fPermissions & VM_PROT_EXECUTE; }
+               uint64_t        alignment() const       { return fAlignment; }
                const char* name() const                { return fOrigName; }
                uint64_t        newAddress() const      { return fNewAddress; }
                void*           mappedAddress() const                   { return fMappedAddress; }
@@ -105,6 +106,7 @@ public:
                uint64_t                fSize;
                uint64_t                fFileOffset;
                uint64_t                fFileSize;
+               uint64_t                fAlignment;
                uint32_t                fPermissions;
                uint64_t                fNewAddress;
                void*                   fMappedAddress;
@@ -134,11 +136,13 @@ public:
        virtual bool                                                            hasMainExecutableLookupLinkage() const = 0;
        virtual bool                                                            isTwoLevelNamespace() const     = 0;
        virtual bool                                                            hasDyldInfo() const     = 0;
+       virtual bool                                                            hasMultipleReadWriteSegments() const = 0;
        virtual uint32_t                                                        getNameFileOffset() const = 0;
        virtual time_t                                                          getLastModTime() const = 0;
        virtual ino_t                                                           getInode() const = 0;
        virtual std::vector<Segment>&                           getSegments() = 0;
        virtual const std::vector<Segment>&                     getSegments() const = 0;
+       virtual const Segment*                                          getSegment(const char* name) const = 0;
        virtual const std::vector<Library>&                     getLibraries() const = 0;
        virtual uint64_t                                                        getBaseAddress() const = 0;
        virtual uint64_t                                                        getVMSize() const = 0;
@@ -180,11 +184,13 @@ public:
        virtual bool                                                            hasMainExecutableLookupLinkage() const { return fMainExecutableLookupLinkage; }
        virtual bool                                                            isTwoLevelNamespace() const     { return (fFlags & MH_TWOLEVEL); }
        virtual bool                                                            hasDyldInfo() const             { return fHasDyldInfo; }
+       virtual bool                                                            hasMultipleReadWriteSegments() const { return fHasTooManyWritableSegments; }
        virtual uint32_t                                                        getNameFileOffset() const{ return fNameFileOffset; }
        virtual time_t                                                          getLastModTime() const  { return fMTime; }
        virtual ino_t                                                           getInode() const                { return fInode; }
        virtual std::vector<Segment>&                           getSegments()                   { return fSegments; }
        virtual const std::vector<Segment>&                     getSegments() const             { return fSegments; }
+       virtual const Segment*                                          getSegment(const char* name) const;
        virtual const std::vector<Library>&                     getLibraries() const    { return fLibraries; }
        virtual uint64_t                                                        getBaseAddress() const  { return fLowSegment->address(); }
        virtual uint64_t                                                        getVMSize() const               { return fVMSize; }
@@ -203,6 +209,11 @@ private:
        typedef typename A::P::E                                E;
        typedef typename A::P::uint_t                   pint_t;
        
+       uint64_t                                                                        segmentSize(const macho_segment_command<typename A::P>* segCmd) const;
+       uint64_t                                                                        segmentFileSize(const macho_segment_command<typename A::P>* segCmd) const;
+       uint64_t                                                                        segmentAlignment(const macho_segment_command<typename A::P>* segCmd) const;
+       bool                                                                            validReadWriteSeg(const Segment& seg) const;
+       
        static cpu_type_t                                                       arch();
 
        const char*                                                                     fPath;
@@ -231,6 +242,7 @@ private:
        bool                                                                            fMainExecutableLookupLinkage;
        bool                                                                            fIsDylib;
        bool                                                                            fHasDyldInfo;
+       bool                                                                            fHasTooManyWritableSegments;
        mutable const uint8_t*                                          fDyldInfoExports;
        uuid_t                                                                          fUUID;
 };
@@ -282,14 +294,20 @@ const MachOLayoutAbstraction* UniversalMachOLayout::getSlice(ArchPair ap) const
                if ( layout->getArchPair().arch == ap.arch ) {
             switch ( ap.arch ) {
                 case CPU_TYPE_ARM:
-                    if ( layout->getArchPair().subtype == ap.subtype ) 
+                               case CPU_TYPE_X86_64:
+                   if ( (layout->getArchPair().subtype & ~CPU_SUBTYPE_MASK) == (ap.subtype & ~CPU_SUBTYPE_MASK) )
                         return layout;
                     break;
-                default:
+                 default:
                     return layout;
             }
         }
        }
+       // if requesting x86_64h and it did not exist, try x86_64 as a fallback
+       if ((ap.arch == CPU_TYPE_X86_64) && (ap.subtype == CPU_SUBTYPE_X86_64_H)) {
+               ap.subtype = CPU_SUBTYPE_X86_64_ALL;
+               return this->getSlice(ap);
+       }
        return NULL;
 }
 
@@ -385,6 +403,9 @@ UniversalMachOLayout::UniversalMachOLayout(const char* path, const std::set<Arch
                                                        case CPU_TYPE_ARM:
                                                                fLayouts.push_back(new MachOLayout<arm>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
                                                                break;
+                                                       case CPU_TYPE_ARM64:
+                                                               fLayouts.push_back(new MachOLayout<arm64>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
+                                                               break;
                                                        default:
                                                                throw "unknown slice in fat file";
                                                }
@@ -397,7 +418,7 @@ UniversalMachOLayout::UniversalMachOLayout(const char* path, const std::set<Arch
                }
                else {
                        try {
-if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_I386)) {
+                               if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_I386)) {
                                        if ( requestedSlice(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) ) 
                                                fLayouts.push_back(new MachOLayout<x86>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
                                }
@@ -409,6 +430,10 @@ if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt3
                                        if ( requestedSlice(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) ) 
                                                fLayouts.push_back(new MachOLayout<arm>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
                                }
+                               else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_ARM64)) {
+                                       if ( requestedSlice(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) ) 
+                                               fLayouts.push_back(new MachOLayout<arm64>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
+                               }
                                else {
                                        throw "unknown file format";
                                }
@@ -425,11 +450,68 @@ if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt3
 }
 
 
+template <typename A>
+uint64_t MachOLayout<A>::segmentSize(const macho_segment_command<typename A::P>* segCmd) const
+{
+       // <rdar://problem/13089366> segments may have 16KB alignment padding at end, if so we can remove that in cache
+       if ( segCmd->nsects() > 0 ) {
+               const macho_section<P>* const sectionsStart = (macho_section<P>*)((uint8_t*)segCmd + sizeof(macho_segment_command<P>));
+               const macho_section<P>* const lastSection = &sectionsStart[segCmd->nsects()-1];
+               uint64_t endSectAddr = lastSection->addr() + lastSection->size();
+               uint64_t endSectAddrPage = (endSectAddr + 4095) & (-4096);
+               if ( endSectAddrPage < (segCmd->vmaddr() + segCmd->vmsize()) ) {
+                       uint64_t size =  endSectAddrPage - segCmd->vmaddr();
+                       //if ( size != segCmd->vmsize() )
+                       //      fprintf(stderr, "trim %s size=0x%08llX instead of 0x%08llX for %s\n", 
+                       //              segCmd->segname(), size, segCmd->vmsize(), getFilePath());
+                       return size;
+               }
+       }
+       return segCmd->vmsize();
+}
+
+template <typename A>
+uint64_t MachOLayout<A>::segmentAlignment(const macho_segment_command<typename A::P>* segCmd) const
+{
+       int p2align = 12;
+       if ( segCmd->nsects() > 0 ) {
+               const macho_section<P>* const sectionsStart = (macho_section<P>*)((uint8_t*)segCmd + sizeof(macho_segment_command<P>));
+               const macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()-1];
+               for (const macho_section<P>*  sect=sectionsStart; sect < sectionsEnd; ++sect) {
+                       if ( sect->align() > p2align )
+                               p2align = sect->align();
+               }
+       }
+       return (1 << p2align);
+}
+
+template <typename A>
+uint64_t MachOLayout<A>::segmentFileSize(const macho_segment_command<typename A::P>* segCmd) const
+{
+       // <rdar://problem/13089366> segments may have 16KB alignment padding at end, if so we can remove that in cache
+       if ( segCmd->nsects() > 0 ) {
+               uint64_t endOffset = segCmd->fileoff();
+               const macho_section<P>* const sectionsStart = (macho_section<P>*)((uint8_t*)segCmd + sizeof(macho_segment_command<P>));
+               const macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
+               for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+                       if ( sect->offset() != 0 )
+                               endOffset = sect->offset() + sect->size();
+               }
+               uint64_t size = (endOffset - segCmd->fileoff() + 4095) & (-4096);
+               //if ( size != segCmd->filesize() )
+               //      fprintf(stderr, "trim %s filesize=0x%08llX instead of 0x%08llX for %s\n", 
+               //              segCmd->segname(), size, segCmd->filesize(), getFilePath());
+               return size;
+       }
+       return segCmd->filesize();
+}
+
+
 template <typename A>
 MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char* path, ino_t inode, time_t modTime, uid_t uid)
  : fPath(path), fOffset(offset), fArchPair(0,0), fMTime(modTime), fInode(inode), fHasSplitSegInfo(false), fRootOwned(uid==0),
    fShareableLocation(false), fDynamicLookupLinkage(false), fMainExecutableLookupLinkage(false), fIsDylib(false), 
-       fHasDyldInfo(false), fDyldInfoExports(NULL)
+       fHasDyldInfo(false), fHasTooManyWritableSegments(false), fDyldInfoExports(NULL)
 {
        fDylibID.name = NULL;
        fDylibID.currentVersion = 0;
@@ -493,9 +575,9 @@ MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char*
                                break;
                        case macho_segment_command<P>::CMD:
                                {
-                                       macho_segment_command<P>* segCmd = (macho_segment_command<P>*)cmd;
-                                       fSegments.push_back(Segment(segCmd->vmaddr(), segCmd->vmsize(), segCmd->fileoff(), 
-                                                               segCmd->filesize(), segCmd->initprot(), segCmd->segname()));
+                                       const macho_segment_command<P>* segCmd = (macho_segment_command<P>*)cmd;
+                                       fSegments.push_back(Segment(segCmd->vmaddr(), segmentSize(segCmd), segCmd->fileoff(), 
+                                                               segmentFileSize(segCmd), segmentAlignment(segCmd), segCmd->initprot(), segCmd->segname()));
                                }
                                break;
                        case LC_SYMTAB:
@@ -543,6 +625,9 @@ MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char*
                        if ( (fLowWritableSegment == NULL) || (seg.address() < fLowWritableSegment->address()) )
                                fLowWritableSegment = &seg;
                        fVMWritablSize += seg.size();
+                       if ( !validReadWriteSeg(seg) ) {
+                               fHasTooManyWritableSegments = true;
+                       }
                }
                else {
                        if ( (fLowReadOnlySegment == NULL) || (seg.address() < fLowReadOnlySegment->address()) )
@@ -552,7 +637,7 @@ MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char*
        }
        if ( (highSegment != NULL) && (fLowSegment != NULL) )
                fVMSize = (highSegment->address() + highSegment->size() - fLowSegment->address() + 4095) & (-4096);                     
-       
+
        // scan undefines looking, for magic ordinals
        if ( (symbolTableCmd != NULL) && (dynamicSymbolTableCmd != NULL) ) {
                const macho_nlist<P>* symbolTable = (macho_nlist<P>*)((uint8_t*)machHeader + symbolTableCmd->symoff());
@@ -578,6 +663,19 @@ MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char*
 template <> cpu_type_t MachOLayout<x86>::arch()     { return CPU_TYPE_I386; }
 template <> cpu_type_t MachOLayout<x86_64>::arch()  { return CPU_TYPE_X86_64; }
 template <> cpu_type_t MachOLayout<arm>::arch()                { return CPU_TYPE_ARM; }
+template <> cpu_type_t MachOLayout<arm64>::arch()      { return CPU_TYPE_ARM64; }
+
+template <>
+bool MachOLayout<x86>::validReadWriteSeg(const Segment& seg) const
+{
+       return (strcmp(seg.name(), "__DATA") == 0) || (strcmp(seg.name(), "__OBJC") == 0);
+}
+
+template <typename A>
+bool MachOLayout<A>::validReadWriteSeg(const Segment& seg) const
+{
+       return (strcmp(seg.name(), "__DATA") == 0);
+}
 
 
 template <>
@@ -598,6 +696,18 @@ bool MachOLayout<A>::isSplitSeg() const
        return false;
 }
 
+template <typename A>
+const MachOLayoutAbstraction::Segment* MachOLayout<A>::getSegment(const char* name) const
+{
+       for(std::vector<Segment>::const_iterator it = fSegments.begin(); it != fSegments.end(); ++it) {
+               const Segment& seg = *it;
+               if ( strcmp(seg.name(), name) == 0 )
+                       return &seg;
+       }
+       return NULL;
+}
+
+
 
 #endif // __MACHO_LAYOUT__
 
index 4493cc3f2abb04b21c451faf7a40e8e971431f56..ac80cd07e314f6f9563ee86cf6c4ba93d24d2e22 100644 (file)
@@ -93,6 +93,7 @@ private:
        void                                                                            doRebase(int segIndex, uint64_t segOffset, uint8_t type, std::vector<void*>& pointersInData);
        void                                                                            adjustSegmentLoadCommand(macho_segment_command<P>* seg);
        pint_t                                                                          getSlideForVMAddress(pint_t vmaddress);
+       pint_t                                                                          maskedVMAddress(pint_t vmaddress);
        pint_t*                                                                         mappedAddressForVMAddress(pint_t vmaddress);
        pint_t*                                                                         mappedAddressForRelocAddress(pint_t r_address);
        void                                                                            adjustRelocBaseAddresses();
@@ -172,6 +173,7 @@ Rebaser<A>::Rebaser(const MachOLayoutAbstraction& layout)
 template <> cpu_type_t Rebaser<x86>::getArchitecture()    const { return CPU_TYPE_I386; }
 template <> cpu_type_t Rebaser<x86_64>::getArchitecture() const { return CPU_TYPE_X86_64; }
 template <> cpu_type_t Rebaser<arm>::getArchitecture() const { return CPU_TYPE_ARM; }
+template <> cpu_type_t Rebaser<arm64>::getArchitecture() const { return CPU_TYPE_ARM64; }
 
 template <typename A>
 bool Rebaser<A>::unequalSlides() const
@@ -301,33 +303,46 @@ void Rebaser<A>::adjustLoadCommands()
        }
 }
 
+template <>
+uint64_t Rebaser<arm64>::maskedVMAddress(pint_t vmaddress)
+{
+       return (vmaddress & 0x0FFFFFFFFFFFFFFF);
+}
+
+template <typename A>
+typename A::P::uint_t Rebaser<A>::maskedVMAddress(pint_t vmaddress)
+{
+       return vmaddress;
+}
 
 
 template <typename A>
 typename A::P::uint_t Rebaser<A>::getSlideForVMAddress(pint_t vmaddress)
 {
+       pint_t vmaddr = this->maskedVMAddress(vmaddress);
        const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
        for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
                const MachOLayoutAbstraction::Segment& seg = *it;
-               if ( (seg.address() <= vmaddress) && (seg.size() != 0) && ((vmaddress < (seg.address()+seg.size())) || (seg.address() == vmaddress)) ) {
+               if ( (seg.address() <= vmaddr) && (seg.size() != 0) && ((vmaddr < (seg.address()+seg.size())) || (seg.address() == vmaddr)) ) {
                        return seg.newAddress() - seg.address();
                }
        }
-       throwf("vm address 0x%08llX not found", (uint64_t)vmaddress);
+       throwf("vm address 0x%08llX not found", (uint64_t)vmaddr);
 }
 
 
 template <typename A>
 typename A::P::uint_t* Rebaser<A>::mappedAddressForVMAddress(pint_t vmaddress)
 {
+       pint_t vmaddr = this->maskedVMAddress(vmaddress);
        const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
        for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
                const MachOLayoutAbstraction::Segment& seg = *it;
-               if ( (seg.address() <= vmaddress) && (vmaddress < (seg.address()+seg.size())) ) {
-                       return (pint_t*)((vmaddress - seg.address()) + (uint8_t*)seg.mappedAddress());
+               if ( (seg.address() <= vmaddr) && (vmaddr < (seg.address()+seg.size())) ) {
+                       return (pint_t*)((vmaddr - seg.address()) + (uint8_t*)seg.mappedAddress());
                }
        }
-       throwf("mappedAddressForVMAddress(0x%08llX) not found", (uint64_t)vmaddress);
+       throwf("mappedAddressForVMAddress(0x%08llX) not found", (uint64_t)vmaddr);
 }
 
 template <typename A>
@@ -630,7 +645,17 @@ void Rebaser<A>::doCodeUpdate(uint8_t kind, uint64_t address, int64_t codeToData
                                A::P::E::set32(*p, newInstruction);
                        }
                        break;
-               case 3: // used only for ppc, an instruction that sets the hi16 of a register
+               case 3: // used for arm64 ADRP
+                       p = (uint32_t*)mappedAddressForVMAddress(address);
+                       instruction = A::P::E::get32(*p);
+                       if ( (instruction & 0x9F000000) == 0x90000000 ) {
+                               // codeToDataDelta is always a multiple of 4096, so only top 4 bits of lo16 will ever need adjusting
+                               value64 = ((instruction & 0x60000000) >> 17) | ((instruction & 0x00FFFFE0) << 9);
+                               value64 += codeToDataDelta;
+                               instruction = (instruction & 0x9F00001F) | ((value64 << 17) & 0x60000000) | ((value64 >> 9) & 0x00FFFFE0);
+                               A::P::E::set32(*p, instruction);
+                       }
+                       break;
                default:
                        throwf("invalid kind=%d in split seg info", kind);
        }
@@ -710,8 +735,11 @@ void Rebaser<A>::adjustCode()
                        const MachOLayoutAbstraction::Segment& dataSeg = *it;
                        if ( strcmp(dataSeg.name(), "__IMPORT") == 0 )
                                codeToImportDelta = (dataSeg.newAddress() - codeSeg.newAddress()) - (dataSeg.address() - codeSeg.address());
-                       else if ( dataSeg.writable() ) 
+                       else if ( dataSeg.writable() ) {
+                               if ( (strcmp(dataSeg.name(), "__DATA") != 0) && (strcmp(dataSeg.name(), "__OBJC") != 0) )
+                                       throwf("only one rw segment named '__DATA' can be used in dylibs placed in the dyld shared cache (%s)", fLayout.getFilePath());
                                codeToDataDelta = (dataSeg.newAddress() - codeSeg.newAddress()) - (dataSeg.address() - codeSeg.address());
+                       }
                }
                // decompress and call doCodeUpdate() on each address
                for(const uint8_t* p = infoStart; (*p != 0) && (p < infoEnd);) {
index 05a8e070387fbee0682a8f9ed5b9e39dcf9062e3..7720b11d11a23e5116b942f3a424588bc7f92c74 100644 (file)
@@ -25,6 +25,7 @@
 #define __MACH_O_TRIE__
 
 #include <algorithm>
+#include <vector>
 
 #include "MachOFileAbstraction.hpp"
 
@@ -245,12 +246,19 @@ inline uint64_t read_uleb128(const uint8_t*& p, const uint8_t* end) {
        int              bit = 0;
        do {
                if (p == end)
+#if __EXCEPTIONS
                        throw "malformed uleb128 extends beyond trie";
-
+#else
+                       return result;
+#endif
                uint64_t slice = *p & 0x7f;
 
                if (bit >= 64 || slice << bit >> bit != slice)
+#if __EXCEPTIONS
                        throw "uleb128 too big for 64-bits";
+#else
+                       return result;
+#endif
                else {
                        result |= (slice << bit);
                        bit += 7;
@@ -321,7 +329,11 @@ static inline void processExportNode(const uint8_t* const start, const uint8_t*
                                                                        std::vector<EntryWithOffset>& output) 
 {
        if ( p >= end )
+#if __EXCEPTIONS
                throw "malformed trie, node past end";
+#else
+               return;
+#endif
        const uint8_t terminalSize = read_uleb128(p, end);
        const uint8_t* children = p + terminalSize;
        if ( terminalSize != 0 ) {
index 41419a88300d452c965b1d706a6986b9800e987c..e41749d60381ce4c4f36e4f2651889859e12bbae 100644 (file)
@@ -177,8 +177,6 @@ class objc_method_list_t {
     uint32_t count;
     objc_method_t<A> first;
 
-    // use newMethodList instead
-    void* operator new (size_t) { return NULL; }
     void* operator new (size_t, void* buf) { return buf; }
 
 public:
@@ -238,12 +236,46 @@ public:
                        uint32_t newEntsize = sizeof(objc_method_t<A>))
         : entsize(newEntsize), count(newCount) 
     { }
+
+private:
+    // use newMethodList instead
+    void* operator new (size_t);
+};
+
+
+// Ivar offset variables are 64-bit on x86_64 and 32-bit everywhere else.
+
+template <typename A>
+class objc_ivar_offset_t {
+    typedef typename A::P::uint_t pint_t;
+    typename A::P::uint_t ptr;  // uint32_t *
+
+    uint32_t& offset(SharedCache<A> *cache) const { return *(uint32_t *)cache->mappedAddressForVMAddress(A::P::getP(ptr)); }
+
+public:
+    bool hasOffset() const { return A::P::getP(ptr) != 0; }
+    pint_t getOffset(SharedCache<A> *cache) const { return A::P::E::get32(offset(cache)); }
+    void setOffset(SharedCache<A> *cache, pint_t newOffset) { A::P::E::set32(offset(cache), newOffset); }
+};
+
+template <>
+class objc_ivar_offset_t<x86_64> {
+    typedef x86_64 A;
+    typedef typename A::P::uint_t pint_t;
+    typename A::P::uint_t ptr;  // uint64_t *
+
+    uint64_t& offset(SharedCache<A> *cache) const { return *(uint64_t *)cache->mappedAddressForVMAddress(A::P::getP(ptr)); }
+
+public:
+    bool hasOffset() const { return A::P::getP(ptr) != 0; }
+    pint_t getOffset(SharedCache<A> *cache) const { return A::P::E::get64(offset(cache)); }
+    void setOffset(SharedCache<A> *cache, pint_t newOffset) { A::P::E::set64(offset(cache), newOffset); }
 };
 
 template <typename A>
 class objc_ivar_t {
     typedef typename A::P::uint_t pint_t;
-    typename A::P::uint_t offset;  // A::P *
+    objc_ivar_offset_t<A> offset;  // uint32_t *  (uint64_t * on x86_64)
     typename A::P::uint_t name;    // const char *
     typename A::P::uint_t type;    // const char *
     uint32_t alignment; 
@@ -252,9 +284,9 @@ class objc_ivar_t {
 public:
     const char * getName(SharedCache<A> *cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); }
 
-    bool hasOffset() const { return A::P::getP(offset) != 0; }
-    pint_t getOffset(SharedCache<A> *cache) const { return A::P::getP(*(pint_t * const)cache->mappedAddressForVMAddress(A::P::getP(offset))); }
-    void setOffset(SharedCache<A> *cache, pint_t newOffset) { A::P::setP(*(pint_t *)cache->mappedAddressForVMAddress(A::P::getP(offset)), newOffset); }
+    bool hasOffset() const { return offset.hasOffset(); }
+    pint_t getOffset(SharedCache<A> *cache) const { return offset.getOffset(cache); }
+    void setOffset(SharedCache<A> *cache, pint_t newOffset) { offset.setOffset(cache, newOffset); }
     
     uint32_t getAlignment()
     {
@@ -270,8 +302,6 @@ class objc_ivar_list_t {
     uint32_t count;
     objc_ivar_t<A> first;
 
-    // use newIvarList instead
-    void* operator new (size_t) { return NULL; }
     void* operator new (size_t, void* buf) { return buf; }
 
 public:
@@ -310,7 +340,9 @@ public:
                          uint32_t newEntsize = sizeof(objc_ivar_t<A>))
         : entsize(newEntsize), count(newCount) 
     { }
-
+private:
+       // use newIvarList instead
+    void* operator new (size_t);
 };
 
 
@@ -334,8 +366,6 @@ class objc_property_list_t {
     uint32_t count;
     objc_property_t<A> first;
 
-    // use newPropertyList instead
-    void* operator new (size_t) { return NULL; }
     void* operator new (size_t, void* buf) { return buf; }
 
 public:
@@ -391,7 +421,9 @@ public:
                          uint32_t newEntsize = sizeof(objc_property_t<A>))
         : entsize(newEntsize), count(newCount) 
     { }
-
+private:
+    // use newPropertyList instead
+    void* operator new (size_t);
 };
 
 template <typename A>
@@ -422,8 +454,6 @@ class objc_protocol_list_t {
     pint_t count;
     pint_t list[0];
 
-    // use newProtocolList instead
-    void* operator new (size_t) { return NULL; }
     void* operator new (size_t, void* buf) { return buf; }
 
 public:
@@ -470,7 +500,9 @@ public:
     }
 
     objc_protocol_list_t(uint32_t newCount) : count(newCount) { }
-
+private:
+    // use newProtocolList instead
+    void* operator new (size_t);
 };
 
 
index 4f68041027f87f496c832bb0e0bef5e0284c16a6..b1fb172a4478cca18e8e4864cbc865fa0f92e030 100644 (file)
 
 #include "dsc_iterator.h"
 #include "dsc_extractor.h"
+#include "MachOTrie.hpp"
 
 #include <vector>
+#include <set>
 #include <map>
 #include <unordered_map>
 #include <algorithm>
@@ -76,9 +78,27 @@ public:
 };
 typedef std::unordered_map<const char*, std::vector<seg_info>, CStringHash, CStringEquals> NameToSegments;
 
+// Filter to find individual symbol re-exports in trie
+class NotReExportSymbol {
+public:
+       NotReExportSymbol(const std::set<int> &rd) :_reexportDeps(rd) {}
+       bool operator()(const mach_o::trie::Entry &entry) const {
+               if ( (entry.flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) != EXPORT_SYMBOL_FLAGS_KIND_REGULAR )
+                       return true;
+               if ( (entry.flags & EXPORT_SYMBOL_FLAGS_REEXPORT) == 0 )
+                       return true;
+               // If the symbol comes from a dylib that is re-exported, this is not an individual symbol re-export
+               if ( _reexportDeps.count(entry.other) != 0 )
+                       return true;
+               return false;
+       }
+private:
+       const std::set<int> &_reexportDeps;
+};
+
 
 template <typename A>
-int optimize_linkedit(macho_header<typename A::P>* mh, uint32_t textOffsetInCache, const void* mapped_cache, uint64_t* newSize) 
+int optimize_linkedit(macho_header<typename A::P>* mh, uint64_t textOffsetInCache, const void* mapped_cache, uint64_t* newSize) 
 {
        typedef typename A::P P;
        typedef typename A::P::E E;
@@ -97,8 +117,14 @@ int optimize_linkedit(macho_header<typename A::P>* mh, uint32_t textOffsetInCach
        macho_dysymtab_command<P>*      dynamicSymTab = NULL;
        macho_linkedit_data_command<P>* functionStarts = NULL;
        macho_linkedit_data_command<P>* dataInCode = NULL;
+       uint32_t exportsTrieOffset = 0;
+       uint32_t exportsTrieSize = 0;
+       std::set<int> reexportDeps;
+       int depIndex = 0;
        for (uint32_t i = 0; i < cmd_count; ++i) {
-               if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+               switch ( cmd->cmd() ) {
+               case macho_segment_command<P>::CMD:
+                       {
                        // update segment/section file offsets
                        macho_segment_command<P>* segCmd = (macho_segment_command<P>*)cmd;
                        segCmd->set_fileoff(cumulativeFileSize);
@@ -106,16 +132,20 @@ int optimize_linkedit(macho_header<typename A::P>* mh, uint32_t textOffsetInCach
                        macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
                        for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
                                if ( sect->offset() != 0 )
-                                       sect->set_offset(cumulativeFileSize+sect->addr()-segCmd->vmaddr());
+                                       sect->set_offset((uint32_t)(cumulativeFileSize+sect->addr()-segCmd->vmaddr()));
                        }
                        if ( strcmp(segCmd->segname(), "__LINKEDIT") == 0 ) {
                                linkEditSegCmd = segCmd;
                        }
                        cumulativeFileSize += segCmd->filesize();
-               }
-               else if ( cmd->cmd() == LC_DYLD_INFO_ONLY ) {
+                       }
+                       break;
+               case LC_DYLD_INFO_ONLY:
+                       {
                        // zero out all dyld info
                        macho_dyld_info_command<P>* dyldInfo = (macho_dyld_info_command<P>*)cmd;
+                       exportsTrieOffset = dyldInfo->export_off();
+                       exportsTrieSize = dyldInfo->export_size();
                        dyldInfo->set_rebase_off(0);
                        dyldInfo->set_rebase_size(0);
                        dyldInfo->set_bind_off(0);
@@ -126,18 +156,29 @@ int optimize_linkedit(macho_header<typename A::P>* mh, uint32_t textOffsetInCach
                        dyldInfo->set_lazy_bind_size(0);
                        dyldInfo->set_export_off(0);
                        dyldInfo->set_export_size(0);
-               }
-               else if ( cmd->cmd() == LC_SYMTAB ) {
+                       }
+                       break;
+               case LC_SYMTAB:
                        symtab = (macho_symtab_command<P>*)cmd;
-               }
-               else if ( cmd->cmd() == LC_DYSYMTAB ) {
+                       break;
+               case LC_DYSYMTAB:
                        dynamicSymTab = (macho_dysymtab_command<P>*)cmd;
-               }
-               else if ( cmd->cmd() == LC_FUNCTION_STARTS ) {
+                       break;
+               case LC_FUNCTION_STARTS:
                        functionStarts = (macho_linkedit_data_command<P>*)cmd;
-               }
-               else if ( cmd->cmd() == LC_DATA_IN_CODE ) {
+                       break;
+               case LC_DATA_IN_CODE:
                        dataInCode = (macho_linkedit_data_command<P>*)cmd;
+                       break;
+               case LC_LOAD_DYLIB:
+               case LC_LOAD_WEAK_DYLIB:
+               case LC_REEXPORT_DYLIB:
+               case LC_LOAD_UPWARD_DYLIB:
+                       ++depIndex;
+                       if ( cmd->cmd() == LC_REEXPORT_DYLIB ) {
+                               reexportDeps.insert(depIndex);
+                       }
+                       break;
                }
                cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
        }
@@ -156,26 +197,35 @@ int optimize_linkedit(macho_header<typename A::P>* mh, uint32_t textOffsetInCach
                return -1;
        }
 
-       const uint32_t newFunctionStartsOffset = linkEditSegCmd->fileoff();
+       const uint64_t newFunctionStartsOffset = linkEditSegCmd->fileoff();
        uint32_t functionStartsSize = 0;
        if ( functionStarts != NULL ) {
                // copy function starts from original cache file to new mapped dylib file
                functionStartsSize = functionStarts->datasize();
                memcpy((char*)mh + newFunctionStartsOffset, (char*)mapped_cache + functionStarts->dataoff(), functionStartsSize);
        }
-       const uint32_t newDataInCodeOffset = (newFunctionStartsOffset + functionStartsSize + sizeof(pint_t) - 1) & (-sizeof(pint_t)); // pointer align
+       const uint64_t newDataInCodeOffset = (newFunctionStartsOffset + functionStartsSize + sizeof(pint_t) - 1) & (-sizeof(pint_t)); // pointer align
        uint32_t dataInCodeSize = 0;
        if ( dataInCode != NULL ) {
                // copy data-in-code info from original cache file to new mapped dylib file
                dataInCodeSize = dataInCode->datasize();
                memcpy((char*)mh + newDataInCodeOffset, (char*)mapped_cache + dataInCode->dataoff(), dataInCodeSize);
        }
-       
+
+       std::vector<mach_o::trie::Entry> exports;
+       if ( exportsTrieSize != 0 ) {
+               const uint8_t* exportsStart = ((uint8_t*)mapped_cache) + exportsTrieOffset; 
+               const uint8_t* exportsEnd = &exportsStart[exportsTrieSize];
+               mach_o::trie::parseTrie(exportsStart, exportsEnd, exports);
+               exports.erase(std::remove_if(exports.begin(), exports.end(), NotReExportSymbol(reexportDeps)), exports.end());
+       }
+
        // look for local symbol info in unmapped part of shared cache
        dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)mapped_cache;
        macho_nlist<P>* localNlists = NULL;
        uint32_t localNlistCount = 0;
        const char* localStrings = NULL;
+       const char* localStringsEnd = NULL;
        if ( header->mappingOffset() > offsetof(dyld_cache_header,localSymbolsSize) ) {
                dyldCacheLocalSymbolsInfo<E>* localInfo = (dyldCacheLocalSymbolsInfo<E>*)(((uint8_t*)mapped_cache) + header->localSymbolsOffset());
                dyldCacheLocalSymbolEntry<E>* entries = (dyldCacheLocalSymbolEntry<E>*)(((uint8_t*)mapped_cache) + header->localSymbolsOffset() + localInfo->entriesOffset());
@@ -187,11 +237,11 @@ int optimize_linkedit(macho_header<typename A::P>* mh, uint32_t textOffsetInCach
                                localNlistCount = entries[i].nlistCount();
                                localNlists = &allLocalNlists[localNlistStart];
                                localStrings = ((char*)localInfo) + localInfo->stringsOffset();
+                               localStringsEnd = &localStrings[localInfo->stringsSize()];
                                break;
                        }
                }
        }
-       
        // compute number of symbols in new symbol table
        const macho_nlist<P>* const mergedSymTabStart = (macho_nlist<P>*)(((uint8_t*)mapped_cache) + symtab->symoff());
        const macho_nlist<P>* const mergedSymTabend = &mergedSymTabStart[symtab->nsyms()];
@@ -206,14 +256,18 @@ int optimize_linkedit(macho_header<typename A::P>* mh, uint32_t textOffsetInCach
                }
        }
        
+       // add room for N_INDR symbols for re-exported symbols
+       newSymCount += exports.size();
+
        // copy symbol entries and strings from original cache file to new mapped dylib file
-       const uint32_t newSymTabOffset = (newDataInCodeOffset + dataInCodeSize + sizeof(pint_t) - 1) & (-sizeof(pint_t)); // pointer align
-       const uint32_t newIndSymTabOffset = newSymTabOffset + newSymCount*sizeof(macho_nlist<P>);
-       const uint32_t newStringPoolOffset = newIndSymTabOffset + dynamicSymTab->nindirectsyms()*sizeof(uint32_t);
+       const uint64_t newSymTabOffset = (newDataInCodeOffset + dataInCodeSize + sizeof(pint_t) - 1) & (-sizeof(pint_t)); // pointer align
+       const uint64_t newIndSymTabOffset = newSymTabOffset + newSymCount*sizeof(macho_nlist<P>);
+       const uint64_t newStringPoolOffset = newIndSymTabOffset + dynamicSymTab->nindirectsyms()*sizeof(uint32_t);
        macho_nlist<P>* const newSymTabStart = (macho_nlist<P>*)(((uint8_t*)mh) + newSymTabOffset);
        char* const newStringPoolStart = (char*)mh + newStringPoolOffset;
        const uint32_t* mergedIndSymTab = (uint32_t*)((char*)mapped_cache + dynamicSymTab->indirectsymoff());
        const char* mergedStringPoolStart = (char*)mapped_cache + symtab->stroff();
+       const char* mergedStringPoolEnd = &mergedStringPoolStart[symtab->strsize()];
        macho_nlist<P>* t = newSymTabStart;
        int poolOffset = 0;
        uint32_t symbolsCopied = 0;
@@ -224,8 +278,28 @@ int optimize_linkedit(macho_header<typename A::P>* mh, uint32_t textOffsetInCach
                        continue;
                *t = *s;
                t->set_n_strx(poolOffset);
-               strcpy(&newStringPoolStart[poolOffset], &mergedStringPoolStart[s->n_strx()]);
-               poolOffset += (strlen(&newStringPoolStart[poolOffset]) + 1);
+               const char* symName = &mergedStringPoolStart[s->n_strx()];
+               if ( symName > mergedStringPoolEnd )
+                       symName = "<corrupt symbol name>";
+               strcpy(&newStringPoolStart[poolOffset], symName);
+               poolOffset += (strlen(symName) + 1);
+               ++t;
+               ++symbolsCopied;
+       }
+       // <rdar://problem/16529213> recreate N_INDR symbols in extracted dylibs for debugger
+       for (std::vector<mach_o::trie::Entry>::iterator it = exports.begin(); it != exports.end(); ++it) {
+               strcpy(&newStringPoolStart[poolOffset], it->name);
+               t->set_n_strx(poolOffset);
+               poolOffset += (strlen(it->name) + 1);
+               t->set_n_type(N_INDR | N_EXT);
+               t->set_n_sect(0);
+               t->set_n_desc(0);
+               const char* importName = it->importName;
+               if ( *importName == '\0' )
+                       importName = it->name;
+               strcpy(&newStringPoolStart[poolOffset], importName);
+               t->set_n_value(poolOffset);
+               poolOffset += (strlen(importName) + 1);
                ++t;
                ++symbolsCopied;
        }
@@ -236,6 +310,8 @@ int optimize_linkedit(macho_header<typename A::P>* mh, uint32_t textOffsetInCach
                // copy local symbols
                for (uint32_t i=0; i < localNlistCount; ++i) {
                        const char* localName = &localStrings[localNlists[i].n_strx()];
+                       if ( localName > localStringsEnd )
+                               localName = "<corrupt local symbol name>";
                        *t = localNlists[i];
                        t->set_n_strx(poolOffset);
                        strcpy(&newStringPoolStart[poolOffset], localName);
@@ -259,22 +335,22 @@ int optimize_linkedit(macho_header<typename A::P>* mh, uint32_t textOffsetInCach
        
        // update load commands
        if ( functionStarts != NULL ) {
-               functionStarts->set_dataoff(newFunctionStartsOffset);
+               functionStarts->set_dataoff((uint32_t)newFunctionStartsOffset);
                functionStarts->set_datasize(functionStartsSize);
        }
        if ( dataInCode != NULL ) {
-               dataInCode->set_dataoff(newDataInCodeOffset);
+               dataInCode->set_dataoff((uint32_t)newDataInCodeOffset);
                dataInCode->set_datasize(dataInCodeSize);
        }
        symtab->set_nsyms(symbolsCopied);
-       symtab->set_symoff(newSymTabOffset);
-       symtab->set_stroff(newStringPoolOffset);
+       symtab->set_symoff((uint32_t)newSymTabOffset);
+       symtab->set_stroff((uint32_t)newStringPoolOffset);
        symtab->set_strsize(poolOffset);
        dynamicSymTab->set_extreloff(0);
        dynamicSymTab->set_nextrel(0);
        dynamicSymTab->set_locreloff(0);
        dynamicSymTab->set_nlocrel(0);
-       dynamicSymTab->set_indirectsymoff(newIndSymTabOffset);
+       dynamicSymTab->set_indirectsymoff((uint32_t)newIndSymTabOffset);
        linkEditSegCmd->set_filesize(symtab->stroff()+symtab->strsize() - linkEditSegCmd->fileoff());
        linkEditSegCmd->set_vmsize( (linkEditSegCmd->filesize()+4095) & (-4096) );
        
@@ -348,8 +424,8 @@ size_t dylib_maker(const void* mapped_cache, std::vector<uint8_t> &dylib_data, c
     FA->align                                   = OSSwapHostToBigInt32(12);
     
        // Write regular segments into the buffer
-       uint32_t                totalSize           = 0;
-    uint32_t                           textOffsetInCache       = 0;
+       uint64_t                totalSize           = 0;
+    uint64_t                           textOffsetInCache       = 0;
        for( std::vector<seg_info>::const_iterator it=segments.begin(); it != segments.end(); ++it) {
         
         if(strcmp(it->segName, "__TEXT") == 0 ) {
@@ -364,7 +440,7 @@ size_t dylib_maker(const void* mapped_cache, std::vector<uint8_t> &dylib_data, c
                 
                 if(   afa->cputype == FA->cputype
                    && afa->cpusubtype == FA->cpusubtype) {
-                    fprintf(stderr, "arch already exists in fat dylib\n");
+                    //fprintf(stderr, "arch already exists in fat dylib\n");
                     dylib_data.resize(offsetInFatFile);
                     return offsetInFatFile;
                 }
@@ -422,6 +498,8 @@ int dyld_shared_cache_extract_dylibs_progress(const char* shared_cache_file_path
                dylib_create_func = dylib_maker<x86>;
        else if ( strcmp((char*)mapped_cache, "dyld_v1  x86_64") == 0 ) 
                dylib_create_func = dylib_maker<x86_64>;
+       else if ( strcmp((char*)mapped_cache, "dyld_v1 x86_64h") == 0 ) 
+               dylib_create_func = dylib_maker<x86_64>;
        else if ( strcmp((char*)mapped_cache, "dyld_v1   armv5") == 0 ) 
                dylib_create_func = dylib_maker<arm>;
        else if ( strcmp((char*)mapped_cache, "dyld_v1   armv6") == 0 ) 
@@ -430,6 +508,8 @@ int dyld_shared_cache_extract_dylibs_progress(const char* shared_cache_file_path
                dylib_create_func = dylib_maker<arm>;
        else if ( strncmp((char*)mapped_cache, "dyld_v1  armv7", 14) == 0 ) 
                dylib_create_func = dylib_maker<arm>;
+       else if ( strcmp((char*)mapped_cache, "dyld_v1   arm64") == 0 ) 
+               dylib_create_func = dylib_maker<arm64>;
        else {
                fprintf(stderr, "Error: unrecognized dyld shared cache magic.\n");
         munmap(mapped_cache, statbuf.st_size);
@@ -438,7 +518,7 @@ int dyld_shared_cache_extract_dylibs_progress(const char* shared_cache_file_path
 
        // iterate through all images in cache and build map of dylibs and segments
        __block NameToSegments  map;
-       __block int                             result              = dyld_shared_cache_iterate(mapped_cache, statbuf.st_size, ^(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo) {
+       __block int                             result              = dyld_shared_cache_iterate(mapped_cache, (uint32_t)statbuf.st_size, ^(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo) {
         map[dylibInfo->path].push_back(seg_info(segInfo->name, segInfo->fileOffset, segInfo->fileSize));
     });
 
@@ -454,11 +534,10 @@ int dyld_shared_cache_extract_dylibs_progress(const char* shared_cache_file_path
     dispatch_queue_t        process_queue       = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
     dispatch_queue_t        writer_queue        = dispatch_queue_create("dyld writer queue", 0);
     
-       __block int             cumulativeResult    = 0;
        __block unsigned        count               = 0;
     
        for ( NameToSegments::iterator it = map.begin(); it != map.end(); ++it) {
-        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
+               dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
         dispatch_group_async(group, process_queue, ^{
             
             char    dylib_path[PATH_MAX];
@@ -474,7 +553,7 @@ int dyld_shared_cache_extract_dylibs_progress(const char* shared_cache_file_path
             int fd = ::open(dylib_path, O_CREAT | O_EXLOCK | O_RDWR, 0644);
             if ( fd == -1 ) {
                 fprintf(stderr, "can't open or create dylib file %s, errnor=%d\n", dylib_path, errno);
-                cumulativeResult    = -1;
+                result    = -1;
                 return;
             }
             
@@ -482,7 +561,7 @@ int dyld_shared_cache_extract_dylibs_progress(const char* shared_cache_file_path
             if (fstat(fd, &statbuf)) {
                 fprintf(stderr, "Error: stat failed for dyld file %s, errnor=%d\n", dylib_path, errno);
                 close(fd);
-                cumulativeResult    = -1;
+                result    = -1;
                 return;
             }
             
@@ -490,21 +569,21 @@ int dyld_shared_cache_extract_dylibs_progress(const char* shared_cache_file_path
             if(pread(fd, &vec->front(), vec->size(), 0) != (long)vec->size()) {
                 fprintf(stderr, "can't read dylib file %s, errnor=%d\n", dylib_path, errno);
                 close(fd);
-                cumulativeResult    = -1;
+                result    = -1;
                 return;
             }
             
             const size_t    offset  = dylib_create_func(mapped_cache, *vec, it->second);
             
             dispatch_group_async(group, writer_queue, ^{
-                progress(count++, map.size());
+                progress(count++, (unsigned)map.size());
                 
                 if(offset != vec->size()) {
                     //Write out the first page, and everything after offset
                     if(   pwrite(fd, &vec->front(), 4096, 0) == -1 
                        || pwrite(fd, &vec->front() + offset, vec->size() - offset, offset) == -1) {
                         fprintf(stderr, "error writing, errnor=%d\n", errno);
-                        cumulativeResult    = -1;
+                        result    = -1;
                     }
                 }
                 
@@ -520,7 +599,7 @@ int dyld_shared_cache_extract_dylibs_progress(const char* shared_cache_file_path
     dispatch_release(writer_queue);
     
     munmap(mapped_cache, statbuf.st_size);
-       return cumulativeResult;
+       return result;
 }
 
 
index d57be709102c2072238293c664fa271cc4866ff3..477894b8e12d78f6bc338f04fc8e32ba649dd8fd 100644 (file)
@@ -35,7 +35,6 @@
 #include "CacheFileAbstraction.hpp"
 
 
-
 namespace dyld {
 
 
@@ -47,7 +46,7 @@ namespace dyld {
                const dyldCacheFileMapping<E>* mappings = (dyldCacheFileMapping<E>*)&cache[header->mappingOffset()];
                for (uint32_t i=0; i < header->mappingCount(); ++i) {
                        if ( (mappings[i].address() <= addr) &&  (addr < (mappings[i].address() + mappings[i].size())) ) {
-                               uint32_t cacheOffset = mappings[i].file_offset() + addr - mappings[i].address();
+                               uint64_t cacheOffset = mappings[i].file_offset() + addr - mappings[i].address();
                                const uint8_t* result =  &cache[cacheOffset];
                                if ( result < cacheEnd )
                                        return result;
@@ -60,17 +59,19 @@ namespace dyld {
 
        // call the callback block on each segment in this image                                                          
        template <typename A>
-       int walkSegments(const uint8_t* cache, const uint8_t* cacheEnd, const uint8_t* firstSeg, const char* dylibPath, const uint8_t* machHeader, 
+       int walkSegments(const uint8_t* cache, const uint8_t* cacheEnd, const uint8_t* firstSeg, const char* dylibPath, uint64_t inode,uint64_t modTime, const uint8_t* machHeader, 
                                                                                        void (^callback)(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo)) 
        {
                typedef typename A::P           P;      
                typedef typename A::P::E        E;      
                dyld_shared_cache_dylib_info    dylibInfo;
                dyld_shared_cache_segment_info  segInfo;
-               dylibInfo.version = 1;
+               dylibInfo.version = 2;
                dylibInfo.isAlias = (dylibPath < (char*)firstSeg); // paths for aliases are store between cache header and first segment
                dylibInfo.machHeader = machHeader;
                dylibInfo.path = dylibPath;
+               dylibInfo.inode = inode;
+               dylibInfo.modTime = modTime;
                const macho_header<P>* mh = (const macho_header<P>*)machHeader;
                const macho_load_command<P>* const cmds = (macho_load_command<P>*)(machHeader + sizeof(macho_header<P>));
                if ( (machHeader+ mh->sizeofcmds()) > cacheEnd )
@@ -154,6 +155,8 @@ namespace dyld {
                const uint8_t* firstSeg = NULL;
                for (uint32_t i=0; i < header->imagesCount(); ++i) {
                        const char* dylibPath  = (char*)cache + dylibs[i].pathFileOffset();
+                       uint64_t inode = dylibs[i].inode();
+                       uint64_t modTime = dylibs[i].modTime();
                        if ( (const uint8_t*)dylibPath > cacheEnd )
                                return -1;
                        const uint8_t* machHeader = mappedAddress<E>(cache, cacheEnd, dylibs[i].address());
@@ -163,7 +166,7 @@ namespace dyld {
                                return -1;
                        if ( firstSeg == NULL )
                                firstSeg = machHeader;
-                       int result = walkSegments<A>(cache, cacheEnd, firstSeg, dylibPath, machHeader, callback);
+                       int result = walkSegments<A>(cache, cacheEnd, firstSeg, dylibPath, inode, modTime, machHeader, callback);
                        if ( result != 0 )
                                return result;
                }
@@ -184,6 +187,8 @@ extern int dyld_shared_cache_iterate(const void* shared_cache_file, uint32_t sha
                        return dyld::walkImages<x86>(cache, shared_cache_size, callback);
        else if ( strcmp((char*)cache, "dyld_v1  x86_64") == 0 ) 
                        return dyld::walkImages<x86_64>(cache, shared_cache_size, callback);
+       else if ( strcmp((char*)cache, "dyld_v1 x86_64h") == 0 ) 
+                       return dyld::walkImages<x86_64>(cache, shared_cache_size, callback);
        else if ( strcmp((char*)cache, "dyld_v1   armv5") == 0 ) 
                        return dyld::walkImages<arm>(cache, shared_cache_size, callback);
        else if ( strcmp((char*)cache, "dyld_v1   armv6") == 0 ) 
@@ -192,6 +197,8 @@ extern int dyld_shared_cache_iterate(const void* shared_cache_file, uint32_t sha
                        return dyld::walkImages<arm>(cache, shared_cache_size, callback);
        else if ( strncmp((char*)cache, "dyld_v1  armv7", 14) == 0 ) 
                        return dyld::walkImages<arm>(cache, shared_cache_size, callback);
+       else if ( strcmp((char*)cache, "dyld_v1   arm64") == 0 ) 
+                       return dyld::walkImages<arm64>(cache, shared_cache_size, callback);
        else
                return -1;
 }
index b08eecc5bff4c956bc6939006e7d6b6b548c5863..6c75d0e1ee5fe4910ed5f98e608bbea4b611da29 100644 (file)
 #include <uuid/uuid.h>
 
 struct dyld_shared_cache_dylib_info {
-       uint32_t                version;                // initial version 1
+       uint32_t                version;                // current version 2
+       // following fields all exist in version 1
        uint32_t                isAlias;                // this is alternate path (symlink)
        const void*             machHeader;             // of dylib in mapped cached file
        const char*             path;                   // of dylib
        const uuid_t*   uuid;                   // of dylib, or NULL is missing
-       // above fields all exist in version 1
+       // following fields all exist in version 2
+       uint64_t                inode;                  // of dylib file or path hash
+       uint64_t                modTime;                // of dylib file
 };
 typedef struct dyld_shared_cache_dylib_info dyld_shared_cache_dylib_info;
 
index 9d4686ac348acad3e5cd319d5f2e37636a1fd186..be6aa654dedab8ef6b8dff0cf95d049dd25e57ca 100644 (file)
 #include <sys/syslimits.h>
 #include <mach-o/arch.h>
 #include <mach-o/loader.h>
+#include <mach/mach.h>
 
 #include <map>
+#include <vector>
 
 #include "dsc_iterator.h"
 #include "dyld_cache_format.h"
@@ -42,7 +44,6 @@
 #include "MachOFileAbstraction.hpp"
 #include "CacheFileAbstraction.hpp"
 
-
 enum Mode {
        modeNone,
        modeList,
@@ -50,7 +51,8 @@ enum Mode {
        modeDependencies,
        modeSlideInfo,
        modeLinkEdit,
-       modeInfo
+       modeInfo,
+       modeSize
 };
 
 struct Options {
@@ -60,22 +62,48 @@ struct Options {
        bool            printUUIDs;
        bool            printVMAddrs;
     bool               printDylibVersions;
+       bool            printInodes;
+};
+
+struct TextInfo {
+       uint64_t                textSize;
+       const char*             path;
+};
+
+struct TextInfoSorter {
+       bool operator()(const TextInfo& left, const TextInfo& right) {
+               return (left.textSize > right.textSize);
+       }
 };
 
 struct Results {
        std::map<uint32_t, const char*> pageToContent;
        uint64_t                                                linkeditBase;
        bool                                                    dependentTargetFound;
+       std::vector<TextInfo>                   textSegments;
 };
 
 
 
-
-
 void usage() {
        fprintf(stderr, "Usage: dyld_shared_cache_util -list [ -uuid ] [-vmaddr] | -dependents <dylib-path> [ -versions ] | -linkedit | -map [ shared-cache-file ] | -slide_info | -info\n");
 }
 
+#if __x86_64__
+static bool isHaswell()
+{
+       // check system is capable of running x86_64h code
+       struct host_basic_info info;
+       mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
+       mach_port_t hostPort = mach_host_self();
+       kern_return_t result = host_info(hostPort, HOST_BASIC_INFO, (host_info_t)&info, &count);
+       mach_port_deallocate(mach_task_self(), hostPort);
+       if ( result != KERN_SUCCESS )
+               return false;
+       return ( info.cpu_subtype == CPU_SUBTYPE_X86_64_H );
+}
+#endif
+
 /*
  * Get the path to the native shared cache for this host
  */
@@ -83,19 +111,24 @@ static const char* default_shared_cache_path() {
 #if __i386__
        return MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "i386";
 #elif __x86_64__ 
-       return MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "x86_64";
+       if ( isHaswell() )
+               return MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "x86_64h";
+       else
+               return MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "x86_64";
 #elif __ARM_ARCH_5TEJ__ 
        return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv5";
 #elif __ARM_ARCH_6K__ 
        return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv6";
+#elif __ARM_ARCH_7K__ 
+       return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv7k";
 #elif __ARM_ARCH_7A__ 
        return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv7";
 #elif __ARM_ARCH_7F__ 
        return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv7f";
 #elif __ARM_ARCH_7S__ 
        return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv7s";
-#elif __ARM_ARCH_7K__ 
-       return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv7k";
+#elif __arm64__ 
+       return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "arm64";
 #else
        #error unsupported architecture
 #endif
@@ -173,6 +206,8 @@ void print_list(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared
 
        if ( options.printVMAddrs )
                printf("0x%08llX ", segInfo->address);
+       if ( options.printInodes )
+               printf("0x%08llX 0x%08llX ", dylibInfo->inode, dylibInfo->modTime);
        if ( options.printUUIDs ) {
                if ( dylibInfo->uuid != NULL ) {
                        const uint8_t* uuid = (uint8_t*)dylibInfo->uuid;;
@@ -192,6 +227,23 @@ void print_list(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared
 }
 
 
+template <typename A>
+void collect_size(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo, 
+                                                                                                                                               const Options& options, Results& results) 
+{
+       if ( strcmp(segInfo->name, "__TEXT") != 0 )
+               return;
+       if ( dylibInfo->isAlias )
+               return;
+               
+       TextInfo info;
+       info.textSize = segInfo->fileSize;
+       info.path = dylibInfo->path;
+       results.textSegments.push_back(info);
+       size_t size = segInfo->fileSize;
+}
+
+
 
 
 static void add_linkedit(uint32_t pageStart, uint32_t pageEnd, const char* message, Results& results) 
@@ -279,7 +331,7 @@ void print_map(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_
 
 static void checkMode(Mode mode) {
        if ( mode != modeNone ) {
-               fprintf(stderr, "Error: select one of: -list, -dependents, -info, -slide_info, -linkedit, or -map\n");
+               fprintf(stderr, "Error: select one of: -list, -dependents, -info, -slide_info, -linkedit, -map, or -size\n");
                usage();
                exit(1);
        }
@@ -294,6 +346,7 @@ int main (int argc, const char* argv[]) {
     options.printUUIDs = false;
        options.printVMAddrs = false;
     options.printDylibVersions = false;
+       options.printInodes = false;
     options.dependentsOfPath = NULL;
     
     for (uint32_t i = 1; i < argc; i++) {
@@ -328,9 +381,16 @@ int main (int argc, const char* argv[]) {
                        else if (strcmp(opt, "-map") == 0) {
                                checkMode(options.mode);
                                options.mode = modeMap;
+            } 
+                       else if (strcmp(opt, "-size") == 0) {
+                               checkMode(options.mode);
+                               options.mode = modeSize;
             } 
                        else if (strcmp(opt, "-uuid") == 0) {
                 options.printUUIDs = true;
+            } 
+                       else if (strcmp(opt, "-inode") == 0) {
+                options.printInodes = true;
             } 
                        else if (strcmp(opt, "-versions") == 0) {
                 options.printDylibVersions = true;
@@ -430,11 +490,16 @@ int main (int argc, const char* argv[]) {
                const dyldCacheFileMapping<LittleEndian>* mappings = (dyldCacheFileMapping<LittleEndian>*)((char*)options.mappedCache + header->mappingOffset());
                for (uint32_t i=0; i < header->mappingCount(); ++i) {
                        if ( mappings[i].init_prot() & VM_PROT_EXECUTE )
-                               printf("    __TEXT     %lluMB\n", mappings[i].size()/(1024*1024));
+                               printf("    __TEXT      %3lluMB,  0x%08llX -> 0x%08llX\n", mappings[i].size()/(1024*1024), mappings[i].address(), mappings[i].address() + mappings[i].size());
                        else if ( mappings[i]. init_prot() & VM_PROT_WRITE )
-                               printf("    __DATA      %lluMB\n", mappings[i].size()/(1024*1024));
+                               printf("    __DATA      %3lluMB,  0x%08llX -> 0x%08llX\n", mappings[i].size()/(1024*1024), mappings[i].address(), mappings[i].address() + mappings[i].size());
                        else if ( mappings[i].init_prot() & VM_PROT_READ )
-                               printf("    __LINKEDIT  %lluMB\n", mappings[i].size()/(1024*1024));
+                               printf("    __LINKEDIT  %3lluMB,  0x%08llX -> 0x%08llX\n", mappings[i].size()/(1024*1024), mappings[i].address(), mappings[i].address() + mappings[i].size());
+               }
+               if ( header->codeSignatureOffset() != 0 ) {
+                       uint64_t size = statbuf.st_size - header->codeSignatureOffset(); 
+                       uint64_t csAddr = mappings[header->mappingCount()-1].address() + mappings[header->mappingCount()-1].size();
+                               printf("    code sign   %3lluMB,  0x%08llX -> 0x%08llX\n", size/(1024*1024), csAddr, csAddr + size);
                }
        }
        else {
@@ -453,13 +518,17 @@ int main (int argc, const char* argv[]) {
                                case modeLinkEdit:
                                        callback = process_linkedit<x86>;
                                        break;
+                               case modeSize:
+                                       callback = collect_size<x86>;
+                                       break;
                                case modeNone:
                                case modeInfo:
                                case modeSlideInfo:
                                        break;
                        }
                }               
-               else if ( strcmp((char*)options.mappedCache, "dyld_v1  x86_64") == 0 ) {
+               else if (  (strcmp((char*)options.mappedCache, "dyld_v1  x86_64") == 0)
+                               || (strcmp((char*)options.mappedCache, "dyld_v1 x86_64h") == 0) ) {
                        switch ( options.mode ) {
                                case modeList:
                                        callback = print_list<x86_64>;
@@ -473,6 +542,9 @@ int main (int argc, const char* argv[]) {
                                case modeLinkEdit:
                                        callback = process_linkedit<x86_64>;
                                        break;
+                               case modeSize:
+                                       callback = collect_size<x86_64>;
+                                       break;
                                case modeNone:
                                case modeInfo:
                                case modeSlideInfo:
@@ -494,6 +566,32 @@ int main (int argc, const char* argv[]) {
                                case modeLinkEdit:
                                        callback = process_linkedit<arm>;
                                        break;
+                               case modeSize:
+                                       callback = collect_size<arm>;
+                                       break;
+                               case modeNone:
+                               case modeInfo:
+                               case modeSlideInfo:
+                                       break;
+                       }
+               }               
+               else if ( strcmp((char*)options.mappedCache, "dyld_v1   arm64") == 0 ) {
+                       switch ( options.mode ) {
+                               case modeList:
+                                       callback = print_list<arm64>;
+                                       break;
+                               case modeMap:
+                                       callback = print_map<arm64>;
+                                       break;
+                               case modeDependencies:
+                                       callback = print_dependencies<arm64>;
+                                       break;
+                               case modeLinkEdit:
+                                       callback = process_linkedit<arm64>;
+                                       break;
+                               case modeSize:
+                                       callback = collect_size<arm64>;
+                                       break;
                                case modeNone:
                                case modeInfo:
                                case modeSlideInfo:
@@ -504,10 +602,10 @@ int main (int argc, const char* argv[]) {
                        fprintf(stderr, "Error: unrecognized dyld shared cache magic.\n");
                        exit(1);
                }
-                               
+               
                __block Results results;
                results.dependentTargetFound = false;
-               int iterateResult = dyld_shared_cache_iterate(options.mappedCache, statbuf.st_size, 
+               int iterateResult = dyld_shared_cache_iterate(options.mappedCache, (uint32_t)statbuf.st_size, 
                                                                                   ^(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo ) {
                                                                                           (callback)(dylibInfo, segInfo, options, results);
                                                                                   });
@@ -522,6 +620,12 @@ int main (int argc, const char* argv[]) {
                                printf("0x%08X %s\n", it->first, it->second);
                        }
                }
+               else if ( options.mode == modeSize ) {
+                       std::sort(results.textSegments.begin(), results.textSegments.end(), TextInfoSorter()); 
+                       for (std::vector<TextInfo>::iterator it = results.textSegments.begin(); it != results.textSegments.end(); ++it) {
+                               printf(" 0x%08llX  %s\n", it->textSize, it->path);
+                       }
+               }
                
                if ( (options.mode == modeDependencies) && options.dependentsOfPath && !results.dependentTargetFound) {
                        fprintf(stderr, "Error: could not find '%s' in the shared cache at\n  %s\n", options.dependentsOfPath, sharedCachePath);
index 73cb11474a2a83cc4fcda9e68d7ecfbb0daa8bbf..cc6dc0c46d2cbb910a998d4d8620817cc28b21ed 100644 (file)
@@ -128,7 +128,7 @@ public:
        static void                     findSharedDylibs(ArchPair ap);
        static ArchGraph*       graphForArchPair(ArchPair ap) { return fgPerArchGraph[ap]; }
        static void                     setFileSystemRoot(const char* root) { fgFileSystemRoot = root; }
-       static void                     setFileSystemOverlay(const char* overlay) { fgFileSystemOverlay = overlay; }
+       static void                     setFileSystemOverlay(const std::vector<const char*>& overlays);
        static const char*      archName(ArchPair ap);
        
        ArchPair                                                                                        getArchPair() { return fArchPair; }
@@ -170,7 +170,7 @@ private:
 
        static std::map<ArchPair, ArchGraph*>   fgPerArchGraph;
        static const char*                                              fgFileSystemRoot;
-       static const char*                                              fgFileSystemOverlay;
+       static std::vector<const char*>                 fgFileSystemOverlays;
        
        ArchPair                                                                        fArchPair;
        std::set<DependencyNode*>                                       fRoots;
@@ -180,7 +180,7 @@ private:
 };
 std::map<ArchPair, ArchGraph*>         ArchGraph::fgPerArchGraph;
 const char*                                                    ArchGraph::fgFileSystemRoot = "";
-const char*                                                    ArchGraph::fgFileSystemOverlay = "";
+std::vector<const char*>                       ArchGraph::fgFileSystemOverlays;
 
 void ArchGraph::addArchPair(ArchPair ap)
 {
@@ -188,18 +188,26 @@ void ArchGraph::addArchPair(ArchPair ap)
        fgPerArchGraph[ap] = new ArchGraph(ap);
 }
 
+void ArchGraph::setFileSystemOverlay(const std::vector<const char*>& overlays) 
+{ 
+       for (std::vector<const char*>::const_iterator it=overlays.begin(); it != overlays.end(); ++it) 
+               fgFileSystemOverlays.push_back(*it);
+}
+
 void ArchGraph::addRoot(const char* vpath, const std::set<ArchPair>& onlyArchs)
 {
        //fprintf(stderr, "addRoot(%s)\n", vpath);
        char completePath[MAXPATHLEN];
        const char* path = NULL;
        // check -overlay path first
-       if ( fgFileSystemOverlay[0] != '\0' ) {
-               strcpy(completePath, fgFileSystemOverlay);
+       for (std::vector<const char*>::const_iterator it=fgFileSystemOverlays.begin(); it != fgFileSystemOverlays.end(); ++it) {
+               strcpy(completePath, *it);
                strcat(completePath, vpath);    // assumes vpath starts with '/'
                struct stat stat_buf;
-               if ( stat(completePath, &stat_buf) == 0 )
+               if ( stat(completePath, &stat_buf) == 0 ) {
                        path = completePath;
+                       break;
+               }
        }
        // if not found in overlay, check for -root
        if ( (path == NULL) && (fgFileSystemRoot[0] != '\0') ) {
@@ -255,41 +263,42 @@ ArchGraph::DependencyNode* ArchGraph::getNodeForVirtualPath(const char* vpath)
 {
        //fprintf(stderr, "getNodeForVirtualPath(%s)\n", vpath);
        char completePath[MAXPATHLEN];
-       if ( fgFileSystemOverlay[0] != '\0' ) {
+       for (std::vector<const char*>::const_iterator it=fgFileSystemOverlays.begin(); it != fgFileSystemOverlays.end(); ++it) {
+               const char* overlayPath = *it;
                // using -overlay means if /overlay/path/dylib exists use it, otherwise use /path/dylib
-               strcpy(completePath, fgFileSystemOverlay);
+               strcpy(completePath, overlayPath);
                strcat(completePath, vpath);    // assumes vpath starts with '/'
                struct stat stat_buf;
-               if ( stat(completePath, &stat_buf) == 0 )
+               if ( stat(completePath, &stat_buf) == 0 ) {
                        return this->getNode(completePath);
-               else {
-                       // <rdar://problem/9279770> support when install name is a symlink
-                       const char* pathToSymlink = vpath;
-                       if ( fgFileSystemRoot[0] != '\0' ) {
-                               strcpy(completePath, fgFileSystemRoot);
-                               strcat(completePath, vpath);
-                               pathToSymlink = completePath;
-                       }
-                       if ( (lstat(pathToSymlink, &stat_buf) == 0) && S_ISLNK(stat_buf.st_mode) ) {
-                               // requested path did not exist in /overlay, but leaf of path is a symlink in /
-                               char pathInSymLink[MAXPATHLEN];
-                               size_t res = readlink(pathToSymlink, pathInSymLink, sizeof(pathInSymLink));
-                               if ( res != -1 ) {
-                                       pathInSymLink[res] = '\0';
-                                       if ( pathInSymLink[0] != '/' ) {
-                                               char symFullPath[MAXPATHLEN];
-                                               strcpy(symFullPath, vpath);
-                                               char* lastSlash = strrchr(symFullPath, '/');
-                                               if ( lastSlash != NULL ) {
-                                                       strcpy(lastSlash+1, pathInSymLink);
-                                                       // (re)try looking for what symlink points to, but in /overlay
-                                                       return this->getNodeForVirtualPath(symFullPath);
-                                               }
-                                       } 
-                               }
+               }
+               // <rdar://problem/9279770> support when install name is a symlink
+               const char* pathToSymlink = vpath;
+               if ( fgFileSystemRoot[0] != '\0' ) {
+                       strcpy(completePath, fgFileSystemRoot);
+                       strcat(completePath, vpath);
+                       pathToSymlink = completePath;
+               }
+               if ( (lstat(pathToSymlink, &stat_buf) == 0) && S_ISLNK(stat_buf.st_mode) ) {
+                       // requested path did not exist in /overlay, but leaf of path is a symlink in /
+                       char pathInSymLink[MAXPATHLEN];
+                       size_t res = readlink(pathToSymlink, pathInSymLink, sizeof(pathInSymLink));
+                       if ( res != -1 ) {
+                               pathInSymLink[res] = '\0';
+                               if ( pathInSymLink[0] != '/' ) {
+                                       char symFullPath[MAXPATHLEN];
+                                       strcpy(symFullPath, vpath);
+                                       char* lastSlash = strrchr(symFullPath, '/');
+                                       if ( lastSlash != NULL ) {
+                                               strcpy(lastSlash+1, pathInSymLink);
+                                               // (re)try looking for what symlink points to, but in /overlay
+                                               return this->getNodeForVirtualPath(symFullPath);
+                                       }
+                               } 
                        }
                }
        }
+
        if ( fgFileSystemRoot[0] != '\0' ) {
                // using -root means always use /rootpath/usr/lib
                strcpy(completePath, fgFileSystemRoot);
@@ -371,8 +380,12 @@ ArchGraph::DependencyNode* ArchGraph::getNode(const char* path)
                        aliasPath = &realPath[strlen(fgFileSystemRoot)];
                }
                // <rdar://problem/11192810> Too many aliases in -overlay mode
-               if ( (fgFileSystemOverlay != NULL) && (fgFileSystemOverlay[0] != '\0') && (strncmp(realPath, fgFileSystemOverlay, strlen(fgFileSystemOverlay)) == 0) ) {
-                       aliasPath = &realPath[strlen(fgFileSystemOverlay)];
+               for (std::vector<const char*>::const_iterator it=fgFileSystemOverlays.begin(); it != fgFileSystemOverlays.end(); ++it) {
+                       const char* overlayPath = *it;
+                       if ( strncmp(realPath, overlayPath, strlen(overlayPath)) == 0 ) {
+                               aliasPath = &realPath[strlen(overlayPath)];
+                               break;
+                       }
                }
                if ( fAliasesMap.find(aliasPath) == fAliasesMap.end() ) {
                        if ( strcmp(aliasPath, node->getLayout()->getID().name) != 0 ) {
@@ -522,7 +535,12 @@ const char*        ArchGraph::archName(ArchPair ap)
                case CPU_TYPE_I386:
                        return "i386";
                case CPU_TYPE_X86_64:
-                       return "x86_64";
+                       switch ( ap.subtype ) {
+                               case CPU_SUBTYPE_X86_64_H:
+                                       return "x86_64h";
+                               default:
+                                       return "x86_64";
+                       }
                case CPU_TYPE_ARM:
                        switch ( ap.subtype ) {
                                case CPU_SUBTYPE_ARM_V4T:
@@ -544,6 +562,8 @@ const char* ArchGraph::archName(ArchPair ap)
                                default:
                                        return "arm";
                        }
+               case CPU_TYPE_ARM64:
+                       return "arm64";
                default:
                        return "unknown";
        }
@@ -553,18 +573,18 @@ bool ArchGraph::sharable(const MachOLayoutAbstraction* layout, ArchPair ap, char
 {
        if ( ! layout->isTwoLevelNamespace() ) 
                asprintf(msg, "can't put %s in shared cache because it was built -flat_namespace", layout->getID().name);
+       else if ( ! layout->inSharableLocation() )
+               asprintf(msg, "can't put %s in shared cache because its -install_name is not in /usr/lib or /System/Library", layout->getID().name);
        else if ( ! layout->hasSplitSegInfo() ) 
                asprintf(msg, "can't put %s in shared cache because it was not built for %s or later", layout->getID().name, (iPhoneOS ? "iPhoneOS 3.1" : "MacOSX 10.5"));
        else if ( ! layout->isRootOwned() )
                asprintf(msg, "can't put %s in shared cache because it is not owned by root", layout->getID().name);
-       else if ( ! layout->inSharableLocation() )
-               asprintf(msg, "can't put %s in shared cache because it is not in /usr/lib or /System/Library", layout->getID().name);
        else if ( layout->hasDynamicLookupLinkage() )
                asprintf(msg, "can't put %s in shared cache because it was built with '-undefined dynamic_lookup'", layout->getID().name);
        else if ( layout->hasMainExecutableLookupLinkage() )
                asprintf(msg, "can't put %s in shared cache because it was built with '-bundle_loader'", layout->getID().name);
-       //else if ( ! layout->hasDyldInfo() )
-       //      asprintf(msg, "can't put %s in shared cache because it was built for older OS", layout->getID().name);
+       else if ( layout->hasMultipleReadWriteSegments() )
+               asprintf(msg, "can't put %s in shared cache because it has multiple r/w segments", layout->getID().name);
        else
                return true;
        return false;
@@ -638,6 +658,7 @@ public:
        uint32_t        add(const char* str);
        uint32_t        addUnique(const char* str);
        const char* stringAtIndex(uint32_t) const;
+       
 private:
        typedef std::unordered_map<const char*, uint32_t, CStringHash, CStringEquals> StringToOffset;
 
@@ -649,7 +670,7 @@ private:
 
 
 StringPool::StringPool() 
-       : fBufferUsed(0), fBufferAllocated(48*1024*1024)
+       : fBufferUsed(0), fBufferAllocated(64*1024*1024)
 {
        fBuffer = (char*)malloc(fBufferAllocated);
 }
@@ -708,7 +729,7 @@ template <typename A>
 class SharedCache
 {
 public:
-                                                       SharedCache(ArchGraph* graph, const char* rootPath, const char* overlayPath, const char* cacheDir, bool explicitCacheDir,
+                                                       SharedCache(ArchGraph* graph, const char* rootPath, const std::vector<const char*>& overlayPaths, const char* cacheDir, bool explicitCacheDir,
                                                                                        bool alphaSort, bool verify, bool optimize, uint64_t dyldBaseAddress);
        bool                                    update(bool force, bool optimize, bool deleteExistingFirst, int archIndex, 
                                                                                int archCount, bool keepSignatures, bool dontMapLocalSymbols);
@@ -742,8 +763,11 @@ private:
        static uint64_t                 sharedRegionStartReadOnlyAddress(uint64_t, uint64_t);
        static uint64_t                 getWritableSegmentNewAddress(uint64_t proposedNewAddress, uint64_t originalAddress, uint64_t executableSlide);
        static bool                             addCacheSlideInfo();
+       static uint64_t                 pathHash(const char*);
        
        static uint64_t                 pageAlign(uint64_t addr);
+       static uint64_t                 regionAlign(uint64_t addr);
+       static uint64_t                 pageAlign4KB(uint64_t addr);
        void                                    assignNewBaseAddresses(bool verify);
 
        struct LayoutInfo {
@@ -927,40 +951,54 @@ public:
 template <>     cpu_type_t     SharedCache<x86>::arch()        { return CPU_TYPE_I386; }
 template <>     cpu_type_t     SharedCache<x86_64>::arch()     { return CPU_TYPE_X86_64; }
 template <>     cpu_type_t     SharedCache<arm>::arch()        { return CPU_TYPE_ARM; }
+template <>     cpu_type_t     SharedCache<arm64>::arch()      { return CPU_TYPE_ARM64; }
 
 template <>     uint64_t       SharedCache<x86>::sharedRegionStartAddress()                    { return 0x90000000; }
 template <>     uint64_t       SharedCache<x86_64>::sharedRegionStartAddress()                 { return 0x7FFF80000000LL; }
 template <>     uint64_t       SharedCache<arm>::sharedRegionStartAddress()                    { return ARM_SHARED_REGION_START; }
+template <>     uint64_t       SharedCache<arm64>::sharedRegionStartAddress()                  { return ARM64_SHARED_REGION_START; }
 
 template <>     uint64_t       SharedCache<x86>::sharedRegionSize()                                    { return 0x20000000; }
 template <>     uint64_t       SharedCache<x86_64>::sharedRegionSize()                                 { return 0x40000000; }
 template <>     uint64_t       SharedCache<arm>::sharedRegionSize()                                    { return ARM_SHARED_REGION_SIZE; }
+template <>     uint64_t       SharedCache<arm64>::sharedRegionSize()                                  { return ARM64_SHARED_REGION_SIZE; }
 
 template <>     uint64_t       SharedCache<x86>::sharedRegionStartWritableAddress(uint64_t exEnd)                      { return exEnd + 0x04000000; }
 template <>     uint64_t       SharedCache<x86_64>::sharedRegionStartWritableAddress(uint64_t exEnd)           { return 0x7FFF70000000LL; }
 template <>     uint64_t       SharedCache<arm>::sharedRegionStartWritableAddress(uint64_t exEnd)                      { return (exEnd + 16383) & (-16384); }
+template <>     uint64_t       SharedCache<arm64>::sharedRegionStartWritableAddress(uint64_t exEnd)            { return exEnd; }
 
 template <>     uint64_t       SharedCache<x86>::sharedRegionStartReadOnlyAddress(uint64_t wrEnd, uint64_t exEnd)       { return wrEnd + 0x04000000; }
 template <>     uint64_t       SharedCache<x86_64>::sharedRegionStartReadOnlyAddress(uint64_t wrEnd, uint64_t exEnd){ return exEnd; }
 template <>     uint64_t       SharedCache<arm>::sharedRegionStartReadOnlyAddress(uint64_t wrEnd, uint64_t exEnd)       { return (wrEnd + 16383) & (-16384); }
-
+template <>     uint64_t       SharedCache<arm64>::sharedRegionStartReadOnlyAddress(uint64_t wrEnd, uint64_t exEnd) { return (wrEnd + 16383) & (-16384); }
 
 template <>     const char*    SharedCache<x86>::archName()    { return "i386"; }
 template <>     const char*    SharedCache<x86_64>::archName() { return "x86_64"; }
 template <>     const char*    SharedCache<arm>::archName()    { return "arm"; }
+template <>     const char*    SharedCache<arm64>::archName()  { return "arm64"; }
 
 template <>     const char*    SharedCache<x86>::cacheFileSuffix(bool, const char* archName)   { return archName; }
 template <>     const char*    SharedCache<x86_64>::cacheFileSuffix(bool, const char* archName){ return archName; }
 template <>     const char*    SharedCache<arm>::cacheFileSuffix(bool, const char* archName)   { return archName; }
-
+template <>     const char*    SharedCache<arm64>::cacheFileSuffix(bool, const char* archName) { return archName; }
 
 template <>  uint64_t          SharedCache<x86>::pageAlign(uint64_t addr)    { return ( (addr + 4095) & (-4096) ); }
 template <>  uint64_t          SharedCache<x86_64>::pageAlign(uint64_t addr) { return ( (addr + 4095) & (-4096) ); }
 template <>  uint64_t          SharedCache<arm>::pageAlign(uint64_t addr)    { return ( (addr + 4095) & (-4096) ); }
+template <>  uint64_t          SharedCache<arm64>::pageAlign(uint64_t addr)  { return ( (addr + 16383) & (-16384) ); }
 
+template <>  uint64_t          SharedCache<x86>::regionAlign(uint64_t addr)    { return ( (addr + 4095) & (-4096) ); }
+template <>  uint64_t          SharedCache<x86_64>::regionAlign(uint64_t addr) { return ( (addr + 4095) & (-4096) ); }
+template <>  uint64_t          SharedCache<arm>::regionAlign(uint64_t addr)    { return ( (addr + 16383) & (-16384) ); }
+template <>  uint64_t          SharedCache<arm64>::regionAlign(uint64_t addr)  { return ( (addr + 16383) & (-16384) ); }
+
+
+template <typename A>  
+uint64_t SharedCache<A>::pageAlign4KB(uint64_t addr)    { return ( (addr + 4095) & (-4096) ); }
 
 template <typename A>
-SharedCache<A>::SharedCache(ArchGraph* graph, const char* rootPath, const char* overlayPath, const char* cacheDir, bool explicitCacheDir, bool alphaSort, bool verify, bool optimize, uint64_t dyldBaseAddress) 
+SharedCache<A>::SharedCache(ArchGraph* graph, const char* rootPath, const std::vector<const char*>& overlayPaths, const char* cacheDir, bool explicitCacheDir, bool alphaSort, bool verify, bool optimize, uint64_t dyldBaseAddress) 
   : fArchGraph(graph), fVerify(verify), fExistingIsNotUpToDate(true), 
        fCacheFileInFinalLocation(rootPath[0] == '\0'), fCacheFilePath(NULL),
        fExistingCacheForVerification(NULL), fDyldBaseAddress(dyldBaseAddress),
@@ -986,8 +1024,12 @@ SharedCache<A>::SharedCache(ArchGraph* graph, const char* rootPath, const char*
                LayoutInfo temp;
                temp.layout = lib;
                temp.info.address = 0;
-               temp.info.modTime = lib->getLastModTime();
                temp.info.inode = lib->getInode();
+               temp.info.modTime = lib->getLastModTime();
+               if ( iPhoneOS ) {
+                       temp.info.inode = pathHash(lib->getID().name);
+                       temp.info.modTime = 0;
+               }
                temp.info.pathFileOffset = lib->getNameFileOffset();  // for now this is the offset within the dylib
                for(ArchGraph::StringToString::iterator ait = aliases.begin(); ait != aliases.end(); ++ait) {
                        if ( strcmp(ait->second, lib->getID().name) == 0 ) {
@@ -1009,8 +1051,9 @@ SharedCache<A>::SharedCache(ArchGraph* graph, const char* rootPath, const char*
        if ( explicitCacheDir ) {
                fCacheFilePath = strdup(cachePathCanonical);
        }
-       else if ( overlayPath[0] != '\0' ) {
-               strcpy(cachePath, overlayPath);
+       else if ( overlayPaths.size() == 1 ) {
+               // if no -cache_dir and exactly on -overlay, write cache file into that overlay dir
+               strcpy(cachePath, overlayPaths[0]);
                strcat(cachePath, "/");
                strcat(cachePath, cachePathCanonical);
                fCacheFilePath = strdup(cachePath);
@@ -1024,8 +1067,8 @@ SharedCache<A>::SharedCache(ArchGraph* graph, const char* rootPath, const char*
        else {
                fCacheFilePath = strdup(cachePathCanonical);
        }
-       if ( overlayPath[0] != '\0' ) {
-               // in overlay mode if there already is a cache file in the overlay
+       if ( overlayPaths.size() == 1 ) {
+               // in overlay mode if there already is a cache file in the overlay,
                // check if it is up to date.  
                struct stat stat_buf;
                if ( stat(fCacheFilePath, &stat_buf) == 0 ) {
@@ -1082,6 +1125,10 @@ SharedCache<A>::SharedCache(ArchGraph* graph, const char* rootPath, const char*
                        temp.aliases.clear();
                        temp.aliases.push_back(aliasPath);
                        temp.info.pathFileOffset = fHeaderSize; 
+                       if ( iPhoneOS ) {
+                               temp.info.inode = pathHash(aliasPath); 
+                               temp.info.modTime = 0;
+                       }
                        fDylibAliases.push_back(temp);
                        fHeaderSize += strlen(aliasPath)+1;
                }
@@ -1119,6 +1166,15 @@ uint64_t SharedCache<A>::getWritableSegmentNewAddress(uint64_t proposedNewAddres
        return proposedNewAddress;
 }
 
+template <typename A>
+uint64_t SharedCache<A>::pathHash(const char* path)
+{
+       uint64_t sum = 0;
+       for (const char* s=path; *s != '\0'; ++s)
+               sum += sum*4 + *s;
+       return sum;
+}
+       
 
 template <typename A>
 void SharedCache<A>::assignNewBaseAddresses(bool verify)
@@ -1132,6 +1188,8 @@ void SharedCache<A>::assignNewBaseAddresses(bool verify)
                        MachOLayoutAbstraction::Segment& seg = segs[i];
                        seg.reset();
                        if ( seg.executable() && !seg.writable() ) {
+                               // <rdar://problem/15947734> Some dylib require extra alignment
+                               currentExecuteAddress = (currentExecuteAddress + seg.alignment() - 1) & (-seg.alignment());
                                // __TEXT segment
                                if ( it->info.address == 0 )
                                        it->info.address = currentExecuteAddress;
@@ -1140,6 +1198,8 @@ void SharedCache<A>::assignNewBaseAddresses(bool verify)
                        }
                }
        }
+       // align __TEXT region
+       currentExecuteAddress = regionAlign(currentExecuteAddress);
 
        // layout DATA for dylibs
        const uint64_t startWritableAddress = sharedRegionStartWritableAddress(currentExecuteAddress);
@@ -1154,10 +1214,13 @@ void SharedCache<A>::assignNewBaseAddresses(bool verify)
                                        throw "found writable and executable segment";
                                // __DATA segment
                                seg.setNewAddress(currentWritableAddress);
-                               currentWritableAddress = pageAlign(seg.newAddress() + seg.size());
+                               // <rdar://problem/13089366> always 4KB align data pages to allow padding to be removed
+                               currentWritableAddress = pageAlign4KB(seg.newAddress() + seg.size());
                        }
                }
        }
+       // align __DATA region
+       currentWritableAddress = regionAlign(currentWritableAddress);
 
        // layout all read-only (but not LINKEDIT) segments
        const uint64_t startReadOnlyAddress = sharedRegionStartReadOnlyAddress(currentWritableAddress, currentExecuteAddress);
@@ -1175,6 +1238,7 @@ void SharedCache<A>::assignNewBaseAddresses(bool verify)
        }       
 
        // layout all LINKEDIT segments at end of all read-only segments
+       currentReadOnlyAddress = regionAlign(currentReadOnlyAddress); // <rdar://problem/16491435>
        fLinkEditsStartAddress = currentReadOnlyAddress;
        fFirstLinkEditSegment = NULL;
        for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
@@ -1283,7 +1347,7 @@ bool SharedCache<A>::notUpToDate(const void* cache, unsigned int aliasCount)
        strcpy(&temp[15-strlen(archPairName)], archPairName);
        if ( strcmp(header->magic(), temp) != 0 ) {
                if ( fVerify ) {
-                       fprintf(stderr, "update_dyld_shared_cache[%u] cannot verify %s because current cache file has invalid header\n", getpid(), archName());
+                       fprintf(stderr, "update_dyld_shared_cache[%u] cannot verify %s because current cache file has invalid header\n", getpid(), archPairName);
                        return false;
                }
                else {
@@ -1294,11 +1358,11 @@ bool SharedCache<A>::notUpToDate(const void* cache, unsigned int aliasCount)
        // not valid if count of images does not match current images needed
        if ( header->imagesCount() != (fDylibs.size()+aliasCount) ) {
                if ( fVerify ) {
-                       fprintf(stderr, "update_dyld_shared_cache[%u] cannot verify %s because current cache file contains a different set of dylibs\n", getpid(), archName());
+                       fprintf(stderr, "update_dyld_shared_cache[%u] cannot verify %s because current cache file contains a different set of dylibs\n", getpid(), archPairName);
                        return false;
                }
                else {
-                       fprintf(stderr, "update_dyld_shared_cache[%u] updating %s cache because current cache file contains a different set of dylibs\n", getpid(), archName());
+                       fprintf(stderr, "update_dyld_shared_cache[%u] updating %s cache because current cache file contains a different set of dylibs\n", getpid(), archPairName);
                        return true;
                }
        }
@@ -1317,7 +1381,7 @@ bool SharedCache<A>::notUpToDate(const void* cache, unsigned int aliasCount)
                        if ( fVerify ) {
                                if ( cacheEntry->pathFileOffset() > textSize ) {
                                        throwf("update_dyld_shared_cache[%u]: for arch=%s, image entries corrupt, bad path offset in %s\n", 
-                                                               getpid(), archName(), it->layout->getID().name);
+                                                               getpid(), archPairName, it->layout->getID().name);
                                }
                                // in -verify mode, just match by path and warn if file looks different
                                if ( strcmp((char*)cache+cacheEntry->pathFileOffset(), it->layout->getID().name) == 0 ) {
@@ -1325,7 +1389,7 @@ bool SharedCache<A>::notUpToDate(const void* cache, unsigned int aliasCount)
                                        sortingMap[it->layout] = cacheEntry-imagesStart;
                                        if ( (cacheEntry->inode() != it->info.inode) || (cacheEntry->modTime() != it->info.modTime) ) {
                                                fprintf(stderr, "update_dyld_shared_cache[%u] warning: for arch=%s, %s has changed since cache was built\n", 
-                                                               getpid(), archName(), it->layout->getID().name);
+                                                               getpid(), archPairName, it->layout->getID().name);
                                        }
                                        break;
                                }
@@ -1346,10 +1410,10 @@ bool SharedCache<A>::notUpToDate(const void* cache, unsigned int aliasCount)
                }
                if ( !found ) {
                        if ( fVerify ) {
-                               throwf("update_dyld_shared_cache[%u] can't verify %s cache because %s is not in existing cache\n", getpid(), archName(), it->layout->getID().name);
+                               throwf("update_dyld_shared_cache[%u] can't verify %s cache because %s is not in existing cache\n", getpid(), archPairName, it->layout->getID().name);
                        }
                        else {
-                               fprintf(stderr, "update_dyld_shared_cache[%u] updating %s cache because dylib at %s has changed\n", getpid(), archName(), it->layout->getID().name);
+                               fprintf(stderr, "update_dyld_shared_cache[%u] updating %s cache because dylib at %s has changed\n", getpid(), archPairName, it->layout->getID().name);
                                return true;
                        }
                }
@@ -1762,7 +1826,7 @@ void LinkEditOptimizer<A>::copyIndirectSymbolTable(uint32_t& offset)
 }
 
 template <typename A>
-void LinkEditOptimizer<A>::updateLoadCommands(uint64_t newVMAddress, uint64_t size, uint32_t stringPoolOffset, 
+void LinkEditOptimizer<A>::updateLoadCommands(uint64_t newVMAddress, uint64_t leSize, uint32_t stringPoolOffset, 
                                                                                                uint32_t linkEditsFileOffset, bool keepSignatures)
 {
        // set LINKEDIT segment commmand to new merged LINKEDIT
@@ -1774,16 +1838,31 @@ void LinkEditOptimizer<A>::updateLoadCommands(uint64_t newVMAddress, uint64_t si
                        macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
                        if ( strcmp(seg->segname(), "__LINKEDIT") == 0 ) {
                                seg->set_vmaddr(newVMAddress);
-                               seg->set_vmsize(size);
-                               seg->set_filesize(size);
+                               seg->set_vmsize(leSize);
+                               seg->set_filesize(leSize);
                                seg->set_fileoff(linkEditsFileOffset);
                        }
-                       // don't alter __TEXT until <rdar://problem/7022345> is fixed
-                       else if ( strcmp(seg->segname(), "__TEXT") != 0 ) {
-                               // update all other segments fileoff to be offset from start of cache file
+                       else {
                                pint_t oldFileOff = seg->fileoff();
-                               seg->set_fileoff(fSharedCache.cacheFileOffsetForVMAddress(seg->vmaddr()));
+                               // don't alter __TEXT until <rdar://problem/7022345> is fixed
+                               if ( strcmp(seg->segname(), "__TEXT") != 0 ) {
+                                       // update all other segments fileoff to be offset from start of cache file
+                                       seg->set_fileoff(fSharedCache.cacheFileOffsetForVMAddress(seg->vmaddr()));
+                               }
                                pint_t fileOffsetDelta = seg->fileoff() - oldFileOff;
+                               const MachOLayoutAbstraction::Segment* layoutSeg = fLayout.getSegment(seg->segname());
+                               if ( layoutSeg != NULL ) {
+                                       //if ( seg->filesize() != layoutSeg->fileSize() ) {
+                                       //      fprintf(stderr, "LC filesize=0x%08llX, trimmed seg file size=0x%08llX, seg=%s, path=%s\n", 
+                                       //                                      seg->filesize(), layoutSeg->fileSize(), seg->segname(), fLayout.getFilePath());
+                                       //}
+                                       //if ( seg->vmsize() != layoutSeg->size() ) {
+                                       //      fprintf(stderr, "LC   vmsize=0x%08llX, trimmed seg      size=0x%08llX, seg=%s, path=%s\n", 
+                                       //                                      seg->vmsize(), layoutSeg->size(), seg->segname(), fLayout.getFilePath());
+                                       //}
+                                       seg->set_vmsize(layoutSeg->size());
+                                       seg->set_filesize(layoutSeg->fileSize());
+                               }
                                // update all sections in this segment
                                macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)seg + sizeof(macho_segment_command<P>));
                                macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
@@ -1986,7 +2065,7 @@ uint8_t* SharedCache<A>::optimizeLINKEDIT(bool keepSignatures, bool dontMapLocal
 
        // update load commands so that all dylibs shared different areas of the same LINKEDIT segment
        for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
-               (*it)->updateLoadCommands(fLinkEditsStartAddress, fLinkEditsTotalUnoptimizedSize, fOffsetOfOldStringPoolInCombinedLinkedit, linkEditsFileOffset, keepSignatures);
+               (*it)->updateLoadCommands(fLinkEditsStartAddress, fLinkEditsTotalOptimizedSize, fOffsetOfOldStringPoolInCombinedLinkedit, linkEditsFileOffset, keepSignatures);
        }
 
        //fprintf(stderr, "fLinkEditsTotalUnoptimizedSize=%llu, fLinkEditsTotalOptimizedSize=%u\n", fLinkEditsTotalUnoptimizedSize, fLinkEditsTotalOptimizedSize);
@@ -2008,10 +2087,10 @@ uint8_t* SharedCache<A>::optimizeLINKEDIT(bool keepSignatures, bool dontMapLocal
                                seg.setFileOffset(linkEditsFileOffset);
                        }
                }
-       }
-       
+       }       
+               
        // return new end of cache
-       return (uint8_t*)fFirstLinkEditSegment->mappedAddress() + fLinkEditsTotalOptimizedSize;
+       return (uint8_t*)fFirstLinkEditSegment->mappedAddress() + regionAlign(fLinkEditsTotalOptimizedSize);
 }
 
 
@@ -2402,7 +2481,7 @@ static bool adhoc_codesign_share_cache(const char* path)
 template <>     bool   SharedCache<x86_64>::addCacheSlideInfo(){ return true; }
 template <>     bool   SharedCache<arm>::addCacheSlideInfo()   { return true; }
 template <>     bool   SharedCache<x86>::addCacheSlideInfo()   { return false; }
-
+template <>     bool   SharedCache<arm64>::addCacheSlideInfo() { return true; } 
 
 
 template <typename A>
@@ -2510,8 +2589,10 @@ bool SharedCache<A>::update(bool force, bool optimize, bool deleteExistingFirst,
                                struct stat stat_buf;
                                if ( fstat(src, &stat_buf) == -1)
                                        throwf("can't stat open file %s, errno=%d", path, errno);
-                               if ( (it->layout->getInode() != stat_buf.st_ino) || (it->layout->getLastModTime() != stat_buf.st_mtime) )
-                                       throwf("file modified during cache creation: %s", path);
+                               if ( (it->layout->getInode() != stat_buf.st_ino) )
+                                       throwf("file inode changed from %llu to %llu during cache creation: %s", it->layout->getInode(), stat_buf.st_ino, path);
+                               else if ( it->layout->getLastModTime() != stat_buf.st_mtime )
+                                       throwf("file mtime changed from 0x%lX to 0x%lX during cache creation: %s", it->layout->getLastModTime(), stat_buf.st_mtime, path);
 
                                if ( verbose )
                                        fprintf(stderr, "update_dyld_shared_cache: copying %s to cache\n", it->layout->getFilePath());
@@ -2624,7 +2705,7 @@ bool SharedCache<A>::update(bool force, bool optimize, bool deleteExistingFirst,
                        if ( optimize ) {
                                //fprintf(stderr, "update_dyld_shared_cache: original cache file size %uMB\n", cacheFileSize/(1024*1024));
                                cacheFileSize = (this->optimizeLINKEDIT(keepSignatures, dontMapLocalSymbols) - inMemoryCache);
-                               //fprintf(stderr, "update_dyld_shared_cache: optimized cache file size %uMB\n", cacheFileSize/(1024*1024));
+                               //fprintf(stderr, "update_dyld_shared_cache: optimized cache file size 0x%08X %uMB\n", cacheFileSize, cacheFileSize/(1024*1024));
                                // update header to reduce mapping size
                                dyldCacheHeader<E>* cacheHeader = (dyldCacheHeader<E>*)inMemoryCache;
                                dyldCacheFileMapping<E>* mappings = (dyldCacheFileMapping<E>*)&inMemoryCache[sizeof(dyldCacheHeader<E>)];
@@ -2704,7 +2785,7 @@ bool SharedCache<A>::update(bool force, bool optimize, bool deleteExistingFirst,
                                }
                                slideInfo->set_entries_count(entry_count);
        
-                               int slideInfoPageSize = pageAlign(slideInfo->entries_offset() + entry_count*entry_size);
+                               int slideInfoPageSize = regionAlign(slideInfo->entries_offset() + entry_count*entry_size);
                                cacheFileSize += slideInfoPageSize;
                        
                                // update mappings to increase RO size
@@ -2725,19 +2806,6 @@ bool SharedCache<A>::update(bool force, bool optimize, bool deleteExistingFirst,
                                memcpy(&inMemoryCache[cacheHeader->slideInfoOffset()], slideInfo, slideInfoPageSize);   
                        }
                        
-                       // make sure after all optimizations, that whole cache file fits into shared region address range
-                       {
-                               dyldCacheHeader<E>* cacheHeader = (dyldCacheHeader<E>*)inMemoryCache;
-                               dyldCacheFileMapping<E>* mappings = (dyldCacheFileMapping<E>*)&inMemoryCache[cacheHeader->mappingOffset()];
-                               for (int i=0; i < cacheHeader->mappingCount(); ++i) {
-                                       uint64_t endAddr = mappings[i].address() + mappings[i].size();
-                                       if ( endAddr > (sharedRegionStartAddress() + sharedRegionSize()) ) {
-                                               throwf("update_dyld_shared_cache[%u] for arch=%s, shared cache will not fit in address space: 0x%llX\n",
-                                                       getpid(), fArchGraph->archName(), endAddr);
-                                       }
-                               }
-                       }
-                       
                        // append local symbol info in an unmapped region
                        if ( dontMapLocalSymbols ) {
                                uint32_t spaceAtEnd = allocatedCacheSize - cacheFileSize;
@@ -2773,7 +2841,7 @@ bool SharedCache<A>::update(bool force, bool optimize, bool deleteExistingFirst,
                                
                                // update state
                                fUnmappedLocalSymbolsSize = pageAlign(stringsOffset + stringsSize);
-                               cacheFileSize = localSymbolsOffset + fUnmappedLocalSymbolsSize;
+                               cacheFileSize = regionAlign(localSymbolsOffset + fUnmappedLocalSymbolsSize);
                                
                                // update header to show location of slidePointers
                                dyldCacheHeader<E>* cacheHeader = (dyldCacheHeader<E>*)inMemoryCache;
@@ -2782,6 +2850,21 @@ bool SharedCache<A>::update(bool force, bool optimize, bool deleteExistingFirst,
                                cacheHeader->set_codeSignatureOffset(cacheFileSize);
                        }
                        
+                       // make sure after all optimizations, that whole cache file fits into shared region address range
+                       {
+                               dyldCacheHeader<E>* cacheHeader = (dyldCacheHeader<E>*)inMemoryCache;
+                               dyldCacheFileMapping<E>* mappings = (dyldCacheFileMapping<E>*)&inMemoryCache[cacheHeader->mappingOffset()];
+                               // <rdar://problem/16128830> incorporate code signature size into overflow check
+                               uint32_t estCodeSigSize = regionAlign(cacheFileSize/200); // guess 0.5% for code signature
+                               for (int i=0; i < cacheHeader->mappingCount(); ++i) {
+                                       uint64_t endAddr = mappings[i].address() + mappings[i].size() + estCodeSigSize;
+                                       if ( endAddr > (sharedRegionStartAddress() + sharedRegionSize()) ) {
+                                               throwf("update_dyld_shared_cache[%u] for arch=%s, shared cache will not fit in shared regionsaddress space.  Overflow amount: %lluKB\n",
+                                                       getpid(), fArchGraph->archName(), (endAddr-(sharedRegionStartAddress() + sharedRegionSize()))/1024);
+                                       }
+                               }
+                       }
+                       
                        // compute UUID of whole cache
                        uint8_t digest[16];
                        CC_MD5(inMemoryCache, cacheFileSize, digest);
@@ -3016,6 +3099,11 @@ bool SharedCache<A>::update(bool force, bool optimize, bool deleteExistingFirst,
                                                                fLinkEditsStartAddress+fOffsetOfOldStringPoolInCombinedLinkedit,
                                                                fLinkEditsStartAddress+fOffsetOfOldStringPoolInCombinedLinkedit+fSizeOfOldStringPoolInCombinedLinkedit);                                
                                        
+                                       dyldCacheHeader<E>* cacheHeader = (dyldCacheHeader<E>*)inMemoryCache;
+                                       if ( cacheHeader->slideInfoSize() != 0 ) {
+                                               fprintf(fmap, " linkedit   %4lluKB kernel slide info\n", (cacheHeader->slideInfoSize())/1024);                          
+                                       }
+
                                        fprintf(fmap, "unmapped -- %4uMB local symbol info\n", fUnmappedLocalSymbolsSize/(1024*1024));                                  
                                        
                                        uint64_t endMappingAddr = fMappings[2].sfm_address + fMappings[2].sfm_size;
@@ -3126,16 +3214,7 @@ static void parsePathsFile(const char* filePath, std::vector<const char*>& paths
                                                *last = '\0';
                                                --last;
                                        }
-                                       // <rdar://problem/8305479> images in shared cache are bound against different IOKit than found at runtime
-                                       // HACK:  Just ignore the known bad IOKit
-                                       if ( strcmp(symbolStart, "/System/Library/Frameworks/IOKit.framework/IOKit") == 0 ) {
-                                               // Disable warning because after three years <rdar://problem/7089957> has still not been fixed...
-                                               //fprintf(stderr, "update_dyld_shared_cache: warning, ignoring /System/Library/Frameworks/IOKit.framework/IOKit\n");
-                                               //warnings.push_back("update_dyld_shared_cache: warning, ignoring /System/Library/Frameworks/IOKit.framework/IOKit\n");
-                                       }
-                                       else {
-                                               paths.push_back(symbolStart);
-                                       }
+                                       paths.push_back(symbolStart);
                                        symbolStart = NULL;
                                        state = lineStart;
                                }
@@ -3151,11 +3230,11 @@ static void parsePathsFile(const char* filePath, std::vector<const char*>& paths
 
 
 
-static void setSharedDylibs(const char* rootPath, const char* overlayPath, const std::set<ArchPair>& onlyArchs, std::vector<const char*> rootsPaths)
+static void setSharedDylibs(const char* rootPath, const std::vector<const char*>& overlayPaths, const std::set<ArchPair>& onlyArchs, std::vector<const char*> rootsPaths)
 {
        // set file system root
        ArchGraph::setFileSystemRoot(rootPath);
-       ArchGraph::setFileSystemOverlay(overlayPath);
+       ArchGraph::setFileSystemOverlay(overlayPaths);
 
        // initialize all architectures requested
        for(std::set<ArchPair>::iterator a = onlyArchs.begin(); a != onlyArchs.end(); ++a)
@@ -3171,7 +3250,7 @@ static void setSharedDylibs(const char* rootPath, const char* overlayPath, const
 }
 
 
-static void scanForSharedDylibs(const char* rootPath, const char* overlayPath, const char* dirOfPathFiles, const std::set<ArchPair>& onlyArchs)
+static void scanForSharedDylibs(const char* rootPath, const std::vector<const char*>& overlayPaths, const char* dirOfPathFiles, const std::set<ArchPair>& onlyArchs)
 {
        char rootDirOfPathFiles[strlen(rootPath)+strlen(dirOfPathFiles)+2];
        // in -root mode, look for roots in /rootpath/var/db/dyld
@@ -3216,14 +3295,14 @@ static void scanForSharedDylibs(const char* rootPath, const char* overlayPath, c
        
        if ( rootsPaths.size() == 0 )
                fprintf(stderr, "update_dyld_shared_cache: warning, no entries found in shared_region_roots\n");
-       setSharedDylibs(rootPath, overlayPath, onlyArchs, rootsPaths);
+       setSharedDylibs(rootPath, overlayPaths, onlyArchs, rootsPaths);
 }
 
-static void setSharedDylibs(const char* rootPath, const char* overlayPath, const char* pathsFile, const std::set<ArchPair>& onlyArchs)
+static void setSharedDylibs(const char* rootPath, const std::vector<const char*>& overlayPaths, const char* pathsFile, const std::set<ArchPair>& onlyArchs)
 {
        std::vector<const char*> rootsPaths;
        parsePathsFile(pathsFile, rootsPaths);
-       setSharedDylibs(rootPath, overlayPath, onlyArchs, rootsPaths);
+       setSharedDylibs(rootPath, overlayPaths, onlyArchs, rootsPaths);
 }
 
 
@@ -3270,7 +3349,7 @@ static void deleteOrphanTempCacheFiles()
 
 
 
-static bool updateSharedeCacheFile(const char* rootPath, const char* overlayPath, const char* cacheDir, bool explicitCacheDir, const std::set<ArchPair>& onlyArchs, 
+static bool updateSharedeCacheFile(const char* rootPath, const std::vector<const char*>& overlayPaths, const char* cacheDir, bool explicitCacheDir, const std::set<ArchPair>& onlyArchs, 
                                                                        bool force, bool alphaSort, bool optimize, bool deleteExistingFirst, bool verify, bool keepSignatures, bool dontMapLocalSymbols)
 {
        bool didUpdate = false;
@@ -3298,19 +3377,25 @@ static bool updateSharedeCacheFile(const char* rootPath, const char* overlayPath
                switch ( a->arch ) {
                        case CPU_TYPE_I386:
                                {
-                                       SharedCache<x86> cache(ArchGraph::graphForArchPair(*a), rootPath, overlayPath, cacheDir, explicitCacheDir, alphaSort, verify, optimize, dyldBaseAddress);
+                                       SharedCache<x86> cache(ArchGraph::graphForArchPair(*a), rootPath, overlayPaths, cacheDir, explicitCacheDir, alphaSort, verify, optimize, dyldBaseAddress);
                                        didUpdate |= cache.update(force, optimize, deleteExistingFirst, index, archCount, keepSignatures, dontMapLocalSymbols);
                                }
                                break;
                        case CPU_TYPE_X86_64:
                                {
-                                       SharedCache<x86_64> cache(ArchGraph::graphForArchPair(*a), rootPath, overlayPath, cacheDir, explicitCacheDir, alphaSort, verify, optimize, dyldBaseAddress);
+                                       SharedCache<x86_64> cache(ArchGraph::graphForArchPair(*a), rootPath, overlayPaths, cacheDir, explicitCacheDir, alphaSort, verify, optimize, dyldBaseAddress);
                                        didUpdate |= cache.update(force, optimize, deleteExistingFirst, index, archCount, keepSignatures, dontMapLocalSymbols);
                                }
                                break;
                        case CPU_TYPE_ARM:
                                {
-                                       SharedCache<arm> cache(ArchGraph::graphForArchPair(*a), rootPath, overlayPath, cacheDir, explicitCacheDir, alphaSort, verify, optimize, dyldBaseAddress);
+                                       SharedCache<arm> cache(ArchGraph::graphForArchPair(*a), rootPath, overlayPaths, cacheDir, explicitCacheDir, alphaSort, verify, optimize, dyldBaseAddress);
+                                       didUpdate |= cache.update(force, optimize, deleteExistingFirst, index, archCount, keepSignatures, dontMapLocalSymbols);
+                               }
+                               break;
+                       case CPU_TYPE_ARM64:
+                               {
+                                       SharedCache<arm64> cache(ArchGraph::graphForArchPair(*a), rootPath, overlayPaths, cacheDir, explicitCacheDir, alphaSort, verify, optimize, dyldBaseAddress);
                                        didUpdate |= cache.update(force, optimize, deleteExistingFirst, index, archCount, keepSignatures, dontMapLocalSymbols);
                                }
                                break;
@@ -3334,7 +3419,7 @@ int main(int argc, const char* argv[])
 {
        std::set<ArchPair> onlyArchs;
        const char* rootPath = "";
-       const char* overlayPath = "";
+       std::vector<const char*> overlayPaths;
        const char* dylibListFile = NULL;
        bool force = false;
        bool alphaSort = false;
@@ -3343,6 +3428,7 @@ int main(int argc, const char* argv[])
        bool keepSignatures = false;
        bool explicitCacheDir = false;
        bool dontMapLocalSymbols = false;
+       bool relaunchForHaswell = false;
        const char* cacheDir = NULL;
        
        try {
@@ -3389,9 +3475,10 @@ int main(int argc, const char* argv[])
                                                throw "-root missing path argument";
                                }
                                else if ( strcmp(arg, "-overlay") == 0 ) {
-                                       overlayPath = argv[++i];
-                                       if ( overlayPath == NULL )
+                                       const char* path = argv[++i];
+                                       if ( path == NULL )
                                                throw "-overlay missing path argument";
+                                       overlayPaths.push_back(path);
                                }
                                else if ( strcmp(arg, "-cache_dir") == 0 ) {
                                        cacheDir = argv[++i];
@@ -3405,6 +3492,8 @@ int main(int argc, const char* argv[])
                                                onlyArchs.insert(ArchPair(CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL));
                                        else if ( strcmp(arch, "x86_64") == 0 )
                                                onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL));
+                                       else if ( strcmp(arch, "x86_64h") == 0 )
+                                               onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_H));
                                        else if ( strcmp(arch, "armv4t") == 0 )
                                                onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V4T));
                                        else if ( strcmp(arch, "armv5") == 0 )
@@ -3419,12 +3508,15 @@ int main(int argc, const char* argv[])
                                                onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7K));
                                        else if ( strcmp(arch, "armv7s") == 0 )
                                                onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7S));
+                                       else if ( strcmp(arch, "arm64") == 0 )
+                                               onlyArchs.insert(ArchPair(CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_ALL));
                                        else 
                                                throwf("unknown architecture %s", arch);
                                }
                                else if ( strcmp(arg, "-universal_boot") == 0 ) {
                                        onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL));
                                        onlyArchs.insert(ArchPair(CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL));
+                                       relaunchForHaswell = true;
                                }
                                else {
                                        usage();
@@ -3447,11 +3539,11 @@ int main(int argc, const char* argv[])
                }
                
                // strip tailing slashes on -overlay
-               if ( overlayPath[0] != '\0' ) {
+               for (std::vector<const char*>::iterator it=overlayPaths.begin(); it != overlayPaths.end(); ++it) {
                        char realOverlayPath[MAXPATHLEN];
-                       if ( realpath(overlayPath, realOverlayPath) == NULL )
-                               throwf("realpath() failed on %s\n", overlayPath);
-                       overlayPath = strdup(realOverlayPath);
+                       if ( realpath(*it, realOverlayPath) == NULL )
+                               throwf("realpath() failed on %s\n", *it);
+                       *it = strdup(realOverlayPath);
                }
 
                // set default location to write cache dir
@@ -3470,8 +3562,20 @@ int main(int argc, const char* argv[])
                        #if __i386__ || __x86_64__
                                onlyArchs.insert(ArchPair(CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL));
                                // check system is capable of running 64-bit programs
-                               if ( (sysctlbyname("hw.optional.x86_64", &available, &len, NULL, 0) == 0) && available )
-                                       onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL));
+                               if ( (sysctlbyname("hw.optional.x86_64", &available, &len, NULL, 0) == 0) && available ) {
+                                       // check system is capable of running x86_64h code
+                                       struct host_basic_info info;
+                                       mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
+                                       mach_port_t hostPort = mach_host_self();
+                                       kern_return_t result = host_info(hostPort, HOST_BASIC_INFO, (host_info_t)&info, &count);
+                                       mach_port_deallocate(mach_task_self(), hostPort);
+                                       if ( result != KERN_SUCCESS )
+                                               throw "host_info() failed";
+                                       if ( info.cpu_subtype == CPU_SUBTYPE_X86_64_H )
+                                               onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_H));
+                                       else
+                                               onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_ALL));
+                               }
                        #else
                                #error unsupported architecture
                        #endif
@@ -3483,10 +3587,10 @@ int main(int argc, const char* argv[])
                
                // build list of shared dylibs
                if ( dylibListFile != NULL )
-                       setSharedDylibs(rootPath, overlayPath, dylibListFile, onlyArchs);
+                       setSharedDylibs(rootPath, overlayPaths, dylibListFile, onlyArchs);
                else
-                       scanForSharedDylibs(rootPath, overlayPath, "/var/db/dyld/shared_region_roots/", onlyArchs);
-               bool didUpdate = updateSharedeCacheFile(rootPath, overlayPath, cacheDir, explicitCacheDir, onlyArchs, force, alphaSort, optimize,
+                       scanForSharedDylibs(rootPath, overlayPaths, "/var/db/dyld/shared_region_roots/", onlyArchs);
+               bool didUpdate = updateSharedeCacheFile(rootPath, overlayPaths, cacheDir, explicitCacheDir, onlyArchs, force, alphaSort, optimize,
                                                                false, verify, keepSignatures, dontMapLocalSymbols);
                                                                
                if ( didUpdate && !iPhoneOS ) {
@@ -3495,14 +3599,32 @@ int main(int argc, const char* argv[])
                                typedef bool (*dscsym_proc_t)(const char *root);
                                dscsym_proc_t proc = (dscsym_proc_t)dlsym(handle, "dscsym_save_nuggets_for_current_caches");
                                const char* nuggetRootPath = "/";
-                               if ( overlayPath[0] != '\0' ) 
-                                       nuggetRootPath = overlayPath;
+                               if ( !overlayPaths.empty() ) 
+                                       nuggetRootPath = overlayPaths[0];
                                else if ( rootPath[0] != '\0' )
                                        nuggetRootPath = rootPath;
                                (*proc)(nuggetRootPath);
                        }
                        dlclose(handle);
                }
+
+               if ( relaunchForHaswell ) {
+                       char cmd[2048];
+                       strlcpy(cmd, argv[0], 2048);
+                       strlcat(cmd, " -arch x86_64h", 2048);
+                       if ( force )
+                               strlcat(cmd, " -force", 2048);
+                       if ( verify )
+                               strlcat(cmd, " -verify", 2048);
+                       if ( alphaSort )
+                               strlcat(cmd, " -sort_by_name", 2048);
+                       if ( (rootPath != NULL) && (rootPath[0] != '\0') ) {
+                               strlcat(cmd, " -root ", 2048);
+                               strlcat(cmd, rootPath, 2048);
+                       }
+                       return system(cmd);
+               }
+
        }
        catch (const char* msg) {
                fprintf(stderr, "update_dyld_shared_cache failed: %s\n", msg);
diff --git a/libdyld.xcconfig b/libdyld.xcconfig
new file mode 100644 (file)
index 0000000..649af26
--- /dev/null
@@ -0,0 +1,8 @@
+
+LIBSYSTEM_LIBS[sdk=*simulator*]     = -Wl,-upward-lsystem_sim_c  -Wl,-upward-lSystem
+LIBSYSTEM_LIBS[sdk=iphoneos*]       = -Wl,-upward-lsystem_platform -Wl,-upward-lsystem_malloc -Wl,-upward-lsystem_c -Wl,-upward-lsystem_pthread -Wl,-upward-llaunch -Wl,-upward-lsystem_blocks -Wl,-upward-lsystem_kernel
+LIBSYSTEM_LIBS[sdk=macosx*]         = -Wl,-upward-lsystem_platform -Wl,-upward-lsystem_malloc -Wl,-upward-lsystem_c -Wl,-upward-lsystem_pthread -Wl,-upward-llaunch -Wl,-upward-lsystem_blocks -Wl,-upward-lsystem_kernel
+
+INSTALL_PATH_ACTUAL = /usr/lib/system
+
+
index 65820ed7b007ef6e498aae63ec1751a35c677a3c..5b297f36c93aed7a95bed83c7b3a8d1b9392a4b3 100644 (file)
@@ -351,6 +351,43 @@ void ImageLoader::applyInterposing(const LinkContext& context)
                this->recursiveApplyInterposing(context);
 }
 
+
+uintptr_t ImageLoader::interposedAddress(const LinkContext& context, uintptr_t address, const ImageLoader* inImage, const ImageLoader* onlyInImage)
+{
+       //dyld::log("interposedAddress(0x%08llX), tupleCount=%lu\n", (uint64_t)address, fgInterposingTuples.size());
+       for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
+               //dyld::log("    interposedAddress: replacee=0x%08llX, replacement=0x%08llX, neverImage=%p, onlyImage=%p, inImage=%p\n", 
+               //                              (uint64_t)it->replacee, (uint64_t)it->replacement,  it->neverImage, it->onlyImage, inImage);
+               // replace all references to 'replacee' with 'replacement'
+               if ( (address == it->replacee) && (inImage != it->neverImage) && ((it->onlyImage == NULL) || (inImage == it->onlyImage)) ) {
+                       if ( context.verboseInterposing ) {
+                               dyld::log("dyld interposing: replace 0x%lX with 0x%lX\n", it->replacee, it->replacement);
+                       }
+                       return it->replacement;
+               }
+       }
+       return address;
+}
+
+void ImageLoader::addDynamicInterposingTuples(const struct dyld_interpose_tuple array[], size_t count)
+{
+       for(size_t i=0; i < count; ++i) {
+               ImageLoader::InterposeTuple tuple;
+               tuple.replacement               = (uintptr_t)array[i].replacement;
+               tuple.neverImage                = NULL;
+               tuple.onlyImage             = this;
+               tuple.replacee                  = (uintptr_t)array[i].replacee;
+               // chain to any existing interpositions
+               for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
+                       if ( (it->replacee == tuple.replacee) && (it->onlyImage == this) ) {
+                               tuple.replacee = it->replacement;
+                       }
+               }
+               ImageLoader::fgInterposingTuples.push_back(tuple);
+       }
+}
+
+
 void ImageLoader::link(const LinkContext& context, bool forceLazysBound, bool preflightOnly, bool neverUnload, const RPathChain& loaderRPaths)
 {
        //dyld::log("ImageLoader::link(%s) refCount=%d, neverUnload=%d\n", this->getPath(), fDlopenReferenceCount, fNeverUnload);
@@ -423,13 +460,39 @@ bool ImageLoader::decrementDlopenReferenceCount()
        return false;
 }
 
+
+// <rdar://problem/14412057> upward dylib initializers can be run too soon
+// To handle dangling dylibs which are upward linked but not downward, all upward linked dylibs
+// have their initialization postponed until after the recursion through downward dylibs
+// has completed.
+void ImageLoader::processInitializers(const LinkContext& context, mach_port_t thisThread,
+                                                                        InitializerTimingList& timingInfo, ImageLoader::UninitedUpwards& images)
+{
+       uint32_t maxImageCount = context.imageCount();
+       ImageLoader::UninitedUpwards upsBuffer[maxImageCount];
+       ImageLoader::UninitedUpwards& ups = upsBuffer[0];
+       ups.count = 0;
+       // Calling recursive init on all images in images list, building a new list of
+       // uninitialized upward dependencies.
+       for (uintptr_t i=0; i < images.count; ++i) {
+               images.images[i]->recursiveInitialization(context, thisThread, timingInfo, ups);
+       }
+       // If any upward dependencies remain, init them.
+       if ( ups.count > 0 )
+               processInitializers(context, thisThread, timingInfo, ups);
+}
+
+
 void ImageLoader::runInitializers(const LinkContext& context, InitializerTimingList& timingInfo)
 {
        uint64_t t1 = mach_absolute_time();
-       mach_port_t this_thread = mach_thread_self();
-       this->recursiveInitialization(context, this_thread, timingInfo);
+       mach_port_t thisThread = mach_thread_self();
+       ImageLoader::UninitedUpwards up;
+       up.count = 1;
+       up.images[0] = this;
+       processInitializers(context, thisThread, timingInfo, up);
        context.notifyBatch(dyld_image_state_initialized);
-       mach_port_deallocate(mach_task_self(), this_thread);
+       mach_port_deallocate(mach_task_self(), thisThread);
        uint64_t t2 = mach_absolute_time();
        fgTotalInitTime += (t2 - t1);
 }
@@ -518,7 +581,6 @@ void ImageLoader::recursiveLoadLibraries(const LinkContext& context, bool prefli
                fState = dyld_image_state_dependents_mapped;
                
                // get list of libraries this image needs
-               //dyld::log("ImageLoader::recursiveLoadLibraries() %ld = %d*%ld\n", fLibrariesCount*sizeof(DependentLibrary), fLibrariesCount, sizeof(DependentLibrary));
                DependentLibraryInfo libraryInfos[fLibraryCount]; 
                this->doGetDependentLibraries(libraryInfos);
                
@@ -601,8 +663,11 @@ void ImageLoader::recursiveLoadLibraries(const LinkContext& context, bool prefli
                                                (*context.setErrorStrings)(dyld_error_kind_dylib_wrong_arch, this->getPath(), requiredLibInfo.name, NULL);
                                        else
                                                (*context.setErrorStrings)(dyld_error_kind_dylib_missing, this->getPath(), requiredLibInfo.name, NULL);
-                                       dyld::throwf("Library not loaded: %s\n  Referenced from: %s\n  Reason: %s", requiredLibInfo.name, this->getRealPath(), msg);
+                                       const char* newMsg = dyld::mkstringf("Library not loaded: %s\n  Referenced from: %s\n  Reason: %s", requiredLibInfo.name, this->getRealPath(), msg);
+                                       free((void*)msg);       // our free() will do nothing if msg is a string literal
+                                       throw newMsg;
                                }
+                               free((void*)msg);       // our free() will do nothing if msg is a string literal
                                // ok if weak library not found
                                dependentLib = NULL;
                                canUsePrelinkingInfo = false;  // this disables all prebinding, we may want to just slam import vectors for this lib to zero
@@ -901,7 +966,8 @@ void ImageLoader::recursiveSpinUnLock()
 }
 
 
-void ImageLoader::recursiveInitialization(const LinkContext& context, mach_port_t this_thread, InitializerTimingList& timingInfo)
+void ImageLoader::recursiveInitialization(const LinkContext& context, mach_port_t this_thread,
+                                                                                 InitializerTimingList& timingInfo, UninitedUpwards& uninitUps)
 {
        recursive_lock lock_info(this_thread);
        recursiveSpinLock(lock_info);
@@ -911,17 +977,18 @@ void ImageLoader::recursiveInitialization(const LinkContext& context, mach_port_
                // break cycles
                fState = dyld_image_state_dependents_initialized-1;
                try {
-                       bool hasUpwards = false;
                        // initialize lower level libraries first
                        for(unsigned int i=0; i < libraryCount(); ++i) {
                                ImageLoader* dependentImage = libImage(i);
                                if ( dependentImage != NULL ) {
-                                       // don't try to initialize stuff "above" me
-                                       bool isUpward = libIsUpward(i);
-                                       if ( (dependentImage->fDepth >= fDepth) && !isUpward ) {
-                                               dependentImage->recursiveInitialization(context, this_thread, timingInfo);
+                                       // don't try to initialize stuff "above" me yet
+                                       if ( libIsUpward(i) ) {
+                                               uninitUps.images[uninitUps.count] = dependentImage;
+                                               uninitUps.count++;
+                                       }
+                                       else if ( dependentImage->fDepth >= fDepth ) {
+                                               dependentImage->recursiveInitialization(context, this_thread, timingInfo, uninitUps);
                                        }
-                                       hasUpwards |= isUpward;
                 }
                        }
                        
@@ -938,18 +1005,6 @@ void ImageLoader::recursiveInitialization(const LinkContext& context, mach_port_
                        // initialize this image
                        bool hasInitializers = this->doInitialization(context);
 
-                       // <rdar://problem/10491874> initialize any upward depedencies
-                       if ( hasUpwards ) {
-                               for(unsigned int i=0; i < libraryCount(); ++i) {
-                                       ImageLoader* dependentImage = libImage(i);
-                                       // <rdar://problem/10643239> ObjC CG hang
-                                       // only init upward lib here if lib is not downwardly referenced somewhere 
-                                       if ( (dependentImage != NULL) && libIsUpward(i) && !dependentImage->isReferencedDownward() ) {
-                                               dependentImage->recursiveInitialization(context, this_thread, timingInfo);
-                                       }
-                               }
-                       }
-            
                        // let anyone know we finished initializing this image
                        fState = dyld_image_state_initialized;
                        oldState = fState;
@@ -984,16 +1039,16 @@ static void printTime(const char* msg, uint64_t partTime, uint64_t totalTime)
                }
        }
        if ( partTime < sUnitsPerSecond ) {
-               uint32_t milliSecondsTimesHundred = (partTime*100000)/sUnitsPerSecond;
-               uint32_t milliSeconds = milliSecondsTimesHundred/100;
-               uint32_t percentTimesTen = (partTime*1000)/totalTime;
+               uint32_t milliSecondsTimesHundred = (uint32_t)((partTime*100000)/sUnitsPerSecond);
+               uint32_t milliSeconds = (uint32_t)(milliSecondsTimesHundred/100);
+               uint32_t percentTimesTen = (uint32_t)((partTime*1000)/totalTime);
                uint32_t percent = percentTimesTen/10;
                dyld::log("%s: %u.%02u milliseconds (%u.%u%%)\n", msg, milliSeconds, milliSecondsTimesHundred-milliSeconds*100, percent, percentTimesTen-percent*10);
        }
        else {
-               uint32_t secondsTimeTen = (partTime*10)/sUnitsPerSecond;
+               uint32_t secondsTimeTen = (uint32_t)((partTime*10)/sUnitsPerSecond);
                uint32_t seconds = secondsTimeTen/10;
-               uint32_t percentTimesTen = (partTime*1000)/totalTime;
+               uint32_t percentTimesTen = (uint32_t)((partTime*1000)/totalTime);
                uint32_t percent = percentTimesTen/10;
                dyld::log("%s: %u.%u seconds (%u.%u%%)\n", msg, seconds, secondsTimeTen-seconds*10, percent, percentTimesTen-percent*10);
        }
index 4e00826c1f334b54fc34500f79b6dc13a78a895c..6f4c3bc6f14b2623771b035212135676ec2329f7 100644 (file)
 #include <vector>
 #include <new>
 
-#if __MAC_OS_X_VERSION_MIN_REQUIRED
+#if __arm__
+ #include <mach/vm_page_size.h>
+#endif
+
+#if __x86_64__ || __i386__
        #include <CrashReporterClient.h>
 #else
        // work around until iOS has CrashReporterClient.h
        #define CRSetCrashLogMessage2(x)
 #endif
 
+#ifndef SHARED_REGION_BASE_ARM64
+       #define SHARED_REGION_BASE_ARM64 0x7FFF80000000LL
+#endif
+
+#ifndef SHARED_REGION_SIZE_ARM64
+       #define SHARED_REGION_SIZE_ARM64 0x10000000LL
+#endif
+
+
 #define LOG_BINDINGS 0
 
 #include "mach-o/dyld_images.h"
@@ -62,6 +75,9 @@
 #elif __arm__
        #define SHARED_REGION_BASE SHARED_REGION_BASE_ARM
        #define SHARED_REGION_SIZE SHARED_REGION_SIZE_ARM
+#elif __arm64__
+       #define SHARED_REGION_BASE SHARED_REGION_BASE_ARM64
+       #define SHARED_REGION_SIZE SHARED_REGION_SIZE_ARM64
 #endif
 
 #ifndef EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
 #if __IPHONE_OS_VERSION_MIN_REQUIRED          
        #define SPLIT_SEG_SHARED_REGION_SUPPORT 0
        #define SPLIT_SEG_DYLIB_SUPPORT                 0
-       #define PREBOUND_IMAGE_SUPPORT                  0
+       #define PREBOUND_IMAGE_SUPPORT                  __arm__
        #define TEXT_RELOC_SUPPORT                              __i386__
-       #define DYLD_SHARED_CACHE_SUPPORT               __arm__
+       #define DYLD_SHARED_CACHE_SUPPORT               (__arm__ || __arm64__)
        #define SUPPORT_OLD_CRT_INITIALIZATION  0
        #define SUPPORT_LC_DYLD_ENVIRONMENT             0
        #define SUPPORT_VERSIONED_PATHS                 0
        #define SUPPORT_CLASSIC_MACHO                   __arm__
-       #define CORESYMBOLICATION_SUPPORT               __arm__
+       #define SUPPORT_ZERO_COST_EXCEPTIONS    (!__USING_SJLJ_EXCEPTIONS__)
        #define INITIAL_IMAGE_COUNT                             256
 #else
        #define SPLIT_SEG_SHARED_REGION_SUPPORT 0
        #define SUPPORT_LC_DYLD_ENVIRONMENT             (__i386__ || __x86_64__)
        #define SUPPORT_VERSIONED_PATHS                 1
        #define SUPPORT_CLASSIC_MACHO                   1
-       #define CORESYMBOLICATION_SUPPORT               1
+       #define SUPPORT_ZERO_COST_EXCEPTIONS    1
        #define INITIAL_IMAGE_COUNT                             200
 #endif
 
@@ -149,6 +165,22 @@ extern "C"         void* xmmap(void* addr, size_t len, int prot, int flags, int fd, off
 #endif
 
 
+#if __arm64__
+       #define dyld_page_trunc(__addr)     (__addr & (-16384))
+       #define dyld_page_round(__addr)     ((__addr + 16383) & (-16384))
+       #define dyld_page_size              16384
+#elif __arm__
+       #define dyld_page_trunc(__addr)     trunc_page_kernel(__addr)
+       #define dyld_page_round(__addr)     round_page_kernel(__addr)
+       #define dyld_page_size              vm_kernel_page_size
+#else
+       #define dyld_page_trunc(__addr)     (__addr & (-4096))
+       #define dyld_page_round(__addr)     ((__addr + 4095) & (-4096))
+       #define dyld_page_size              4096
+#endif
+
+
+
 struct ProgramVars
 {
        const void*             mh;
@@ -246,6 +278,8 @@ public:
                ImageLoader*    mainExecutable;
                const char*             imageSuffix;
                const char**    rootPaths;
+               const dyld_interpose_tuple*     dynamicInterposeArray;
+               size_t                  dynamicInterposeCount;
                PrebindMode             prebindUsage;
                SharedRegionMode sharedRegionMode;
                bool                    dyldLoadedAtSameAddressNeededBySharedCache;
@@ -303,6 +337,12 @@ public:
                }                       images[1];
        };
        
+       struct UninitedUpwards
+       {
+               uintptr_t        count;
+               ImageLoader* images[1];
+       };
+
        
                                                                                // constructor is protected, but anyone can delete an image
        virtual                                                         ~ImageLoader();
@@ -483,8 +523,13 @@ public:
                
                                                                                // if image has a UUID, copy into parameter and return true
        virtual bool                                            getUUID(uuid_t) const = 0;
-       
-       
+
+                                                                               // dynamic interpose values onto this image
+       virtual void                                            dynamicInterpose(const LinkContext& context) = 0;
+
+                                                                               // record interposing for any late binding
+       void                                                            addDynamicInterposingTuples(const struct dyld_interpose_tuple array[], size_t count);
+               
 //
 // A segment is a chunk of an executable file that is mapped into memory.  
 //
@@ -504,7 +549,9 @@ public:
        virtual uintptr_t                                       segActualEndAddress(unsigned int) const = 0;
 
        
+                                                                               // info from LC_VERSION_MIN_MACOSX or LC_VERSION_MIN_IPHONEOS
        virtual uint32_t                                        sdkVersion() const = 0;
+       virtual uint32_t                                        minOSVersion() const = 0;
        
                                                                                // if the image contains interposing functions, register them
        virtual void                                            registerInterposing() = 0;
@@ -571,7 +618,8 @@ public:
        
        struct InterposeTuple { 
                uintptr_t               replacement; 
-               ImageLoader*    replacementImage;       // don't apply replacement to this image
+               ImageLoader*    neverImage;                     // don't apply replacement to this image
+               ImageLoader*    onlyImage;                      // only apply replacement to this image
                uintptr_t               replacee; 
        };
 
@@ -627,7 +675,8 @@ protected:
        void                            recursiveBind(const LinkContext& context, bool forceLazysBound, bool neverUnload);
        void                            recursiveApplyInterposing(const LinkContext& context);
        void                            recursiveGetDOFSections(const LinkContext& context, std::vector<DOFInfo>& dofs);
-       void                            recursiveInitialization(const LinkContext& context, mach_port_t this_thread, ImageLoader::InitializerTimingList&);
+       void                            recursiveInitialization(const LinkContext& context, mach_port_t this_thread,
+                                                                                               ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&);
 
                                                                // fill in information about dependent libraries (array length is fLibraryCount)
        virtual void                            doGetDependentLibraries(DependentLibraryInfo libs[]) = 0;
@@ -679,6 +728,8 @@ protected:
                
        void                                            setFileInfo(dev_t device, ino_t inode, time_t modDate);
        
+       static uintptr_t                        interposedAddress(const LinkContext& context, uintptr_t address, const ImageLoader* notInImage, const ImageLoader* onlyInImage=NULL);
+       
        static uintptr_t                        fgNextPIEDylibAddress;
        static uint32_t                         fgImagesWithUsedPrebinding;
        static uint32_t                         fgImagesUsedFromSharedCache;
@@ -721,6 +772,8 @@ private:
        const ImageLoader::Symbol*      findExportedSymbolInDependentImagesExcept(const char* name, const ImageLoader** dsiStart, 
                                                                                const ImageLoader**& dsiCur, const ImageLoader** dsiEnd, const ImageLoader** foundIn) const;
 
+       void                                            processInitializers(const LinkContext& context, mach_port_t this_thread,
+                                                                                                       InitializerTimingList& timingInfo, ImageLoader::UninitedUpwards& ups);
 
 
        recursive_lock*                         fInitializerRecursiveLock;
index 1f636cb7fa41af46e7f615ab2fd5b3f016a07425..53b0ddd1b21385c14bfead0af01173596d3d1f62 100644 (file)
@@ -109,7 +109,7 @@ ImageLoaderMachO::ImageLoaderMachO(const macho_header* mh, const char* path, uns
                        // ignore zero-sized segments
                        if ( segCmd->vmsize != 0 ) {
                                // record offset of load command
-                               segOffsets[segIndex++] = (uint8_t*)segCmd - fMachOData;
+                               segOffsets[segIndex++] = (uint32_t)((uint8_t*)segCmd - fMachOData);
                        }
                }
                cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
@@ -138,6 +138,16 @@ void ImageLoaderMachO::sniffLoadCommands(const macho_header* mh, const char* pat
        const struct load_command* const endCmds = (struct load_command*)(((uint8_t*)mh) + sizeof(macho_header) + mh->sizeofcmds);
        const struct load_command* cmd = startCmds;
        for (uint32_t i = 0; i < cmd_count; ++i) {
+               uint32_t cmdLength = cmd->cmdsize;
+               if ( cmdLength < 8 ) {
+                       dyld::throwf("malformed mach-o image: load command #%d length (%u) too small in %s",
+                                                                                          i, cmdLength, path);
+               }
+               const struct load_command* const nextCmd = (const struct load_command*)(((char*)cmd)+cmdLength);
+               if ( (nextCmd > endCmds) || (nextCmd < cmd) ) {
+                       dyld::throwf("malformed mach-o image: load command #%d length (%u) would exceed sizeofcmds (%u) in %s",
+                                                                                          i, cmdLength, mh->sizeofcmds, path);
+               }
                switch (cmd->cmd) {
                        case LC_DYLD_INFO:
                        case LC_DYLD_INFO_ONLY:
@@ -160,6 +170,10 @@ void ImageLoaderMachO::sniffLoadCommands(const macho_header* mh, const char* pat
                                        loadCommandSegmentIndex = i;
                                        loadCommandSegmentVMStart = segCmd->vmaddr;
                                        loadCommandSegmentVMEnd   = segCmd->vmaddr + segCmd->vmsize;
+                                       if ( (intptr_t)(segCmd->vmsize) < 0)
+                                               dyld::throwf("malformed mach-o image: segment load command %s size too large", segCmd->segname);
+                                       if ( loadCommandSegmentVMEnd < loadCommandSegmentVMStart )
+                                               dyld::throwf("malformed mach-o image: segment load command %s wraps around address space", segCmd->segname);
                                }
                                break;
                        case LC_SEGMENT_COMMAND_WRONG:
@@ -175,12 +189,7 @@ void ImageLoaderMachO::sniffLoadCommands(const macho_header* mh, const char* pat
                                *codeSigCmd = (struct linkedit_data_command*)cmd; // only support one LC_CODE_SIGNATURE per image
                                break;
                }
-               uint32_t cmdLength = cmd->cmdsize;
-               cmd = (const struct load_command*)(((char*)cmd)+cmdLength);
-               if ( (cmd > endCmds) || (cmd < startCmds) ) {
-                       dyld::throwf("malformed mach-o image: load command #%d length (%u) would exceed sizeofcmds (%u) in %s", 
-                                                       i, cmdLength, mh->sizeofcmds, path);
-               }
+               cmd = nextCmd;
        }
        
        if ( context.codeSigningEnforced && !foundLoadCommandSegment )
@@ -337,7 +346,7 @@ void ImageLoaderMachO::parseLoadCmds()
                        fLinkEditBase = (uint8_t*)(segActualLoadAddress(i) - segFileOffset(i));
 #if TEXT_RELOC_SUPPORT
                // __TEXT segment always starts at beginning of file and contains mach_header and load commands
-               if ( strcmp(segName(i),"__TEXT") == 0 ) {
+               if ( segExecutable(i) ) {
                        if ( segHasRebaseFixUps(i) && (fSlide != 0) )
                                fTextSegmentRebases = true;
                        if ( segHasBindFixUps(i) )
@@ -419,9 +428,9 @@ void ImageLoaderMachO::parseLoadCmds()
                                                else if ( type == S_DTRACE_DOF )
                                                        fHasDOFSections = true;
                                                else if ( isTextSeg && (strcmp(sect->sectname, "__eh_frame") == 0) )
-                                                       fEHFrameSectionOffset = (uint8_t*)sect - fMachOData;
+                                                       fEHFrameSectionOffset = (uint32_t)((uint8_t*)sect - fMachOData);
                                                else if ( isTextSeg && (strcmp(sect->sectname, "__unwind_info") == 0) )
-                                                       fUnwindInfoSectionOffset = (uint8_t*)sect - fMachOData;;
+                                                       fUnwindInfoSectionOffset = (uint32_t)((uint8_t*)sect - fMachOData);
                                        }
                                }
                                break;
@@ -430,7 +439,7 @@ void ImageLoaderMachO::parseLoadCmds()
                                break;
                        case LC_ID_DYLIB:
                                {
-                                       fDylibIDOffset = (uint8_t*)cmd - fMachOData;
+                                       fDylibIDOffset = (uint32_t)((uint8_t*)cmd - fMachOData);
                                }
                                break;
                        case LC_RPATH:
@@ -582,6 +591,7 @@ uintptr_t ImageLoaderMachO::segActualEndAddress(unsigned int segIndex) const
 
 bool ImageLoaderMachO::segHasRebaseFixUps(unsigned int segIndex) const
 {
+#if TEXT_RELOC_SUPPORT
        // scan sections for fix-up bit
        const macho_segment_command* segCmd = segLoadCommand(segIndex);
        const struct macho_section* const sectionsStart = (struct macho_section*)((char*)segCmd + sizeof(struct macho_segment_command));
@@ -590,11 +600,13 @@ bool ImageLoaderMachO::segHasRebaseFixUps(unsigned int segIndex) const
                if ( (sect->flags & S_ATTR_LOC_RELOC) != 0 )
                        return true;
        }
+#endif
        return false;
 }
 
 bool ImageLoaderMachO::segHasBindFixUps(unsigned int segIndex) const
 {
+#if TEXT_RELOC_SUPPORT
        // scan sections for fix-up bit
        const macho_segment_command* segCmd = segLoadCommand(segIndex);
        const struct macho_section* const sectionsStart = (struct macho_section*)((char*)segCmd + sizeof(struct macho_segment_command));
@@ -603,6 +615,7 @@ bool ImageLoaderMachO::segHasBindFixUps(unsigned int segIndex) const
                if ( (sect->flags & S_ATTR_EXT_RELOC) != 0 )
                        return true;
        }
+#endif
        return false;
 }
 
@@ -652,7 +665,7 @@ void ImageLoaderMachO::preFetchDATA(int fd, uint64_t offsetInFat, const LinkCont
                                // prefetch writable segment that have mmap'ed regions
                                radvisory advice;
                                advice.ra_offset = offsetInFat + segFileOffset(i);
-                               advice.ra_count = segFileSize(i);
+                               advice.ra_count = (int)segFileSize(i);
                                // limit prefetch to 1MB (256 pages)
                                if ( advice.ra_count > 1024*1024 )
                                        advice.ra_count = 1024*1024;
@@ -830,14 +843,16 @@ void ImageLoaderMachO::registerInterposing()
                                        for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
                                                if ( ((sect->flags & SECTION_TYPE) == S_INTERPOSING) || ((strcmp(sect->sectname, "__interpose") == 0) && (strcmp(seg->segname, "__DATA") == 0)) ) {
                                                        const InterposeData* interposeArray = (InterposeData*)(sect->addr + fSlide);
-                                                       const unsigned int count = sect->size / sizeof(InterposeData);
-                                                       for (uint32_t i=0; i < count; ++i) {
+                                                       const size_t count = sect->size / sizeof(InterposeData);
+                                                       for (size_t i=0; i < count; ++i) {
                                                                ImageLoader::InterposeTuple tuple;
                                                                tuple.replacement               = interposeArray[i].replacement;
-                                                               tuple.replacementImage  = this;
+                                                               tuple.neverImage                = this;
+                                                               tuple.onlyImage             = NULL;
                                                                tuple.replacee                  = interposeArray[i].replacee;
                                                                // <rdar://problem/7937695> verify that replacement is in this image
                                                                if ( this->containsAddress((void*)tuple.replacement) ) {
+                                                                       // chain to any existing interpositions
                                                                        for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
                                                                                if ( it->replacee == tuple.replacee ) {
                                                                                        tuple.replacee = it->replacement;
@@ -873,6 +888,30 @@ uint32_t ImageLoaderMachO::sdkVersion() const
        return 0;
 }
 
+uint32_t ImageLoaderMachO::minOSVersion(const mach_header* mh)
+{
+       const uint32_t cmd_count = mh->ncmds;
+       const struct load_command* const cmds = (struct load_command*)(((char*)mh) + sizeof(macho_header));
+       const struct load_command* cmd = cmds;
+       const struct version_min_command* versCmd;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               switch ( cmd->cmd ) {
+                       case LC_VERSION_MIN_MACOSX:
+                       case LC_VERSION_MIN_IPHONEOS:
+                               versCmd = (version_min_command*)cmd;
+                               return versCmd->version;
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+       }
+       return 0;
+}
+
+uint32_t ImageLoaderMachO::minOSVersion() const
+{
+       return ImageLoaderMachO::minOSVersion(machHeader());
+}
+
+
 void* ImageLoaderMachO::getThreadPC() const
 {
        const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
@@ -912,6 +951,9 @@ void* ImageLoaderMachO::getMain() const
                        #elif __arm__
                                const arm_thread_state_t* registers = (arm_thread_state_t*)(((char*)cmd) + 16);
                                void* entry = (void*)(registers->__pc + fSlide);
+                       #elif __arm64__
+                               const arm_thread_state64_t* registers = (arm_thread_state64_t*)(((char*)cmd) + 16);
+                               void* entry = (void*)(registers->__pc + fSlide);
                        #else
                                #warning need processor specific code
                        #endif
@@ -1034,7 +1076,7 @@ void ImageLoaderMachO::getRPaths(const LinkContext& context, std::vector<const c
                        case LC_RPATH:
                                const char* pathToAdd = NULL;
                                const char* path = (char*)cmd + ((struct rpath_command*)cmd)->path.offset;
-                               if ( strncmp(path, "@loader_path/", 13) == 0 ) {
+                               if ( (strncmp(path, "@loader_path", 12) == 0) && ((path[12] == '/') || (path[12] == '\0')) ) {
                                        if ( context.processIsRestricted  && (context.mainExecutable == this) ) {
                                                dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @loader_path\n", path, this->getPath());
                                                break;
@@ -1044,14 +1086,13 @@ void ImageLoaderMachO::getRPaths(const LinkContext& context, std::vector<const c
                                                char newRealPath[strlen(resolvedPath) + strlen(path)];
                                                strcpy(newRealPath, resolvedPath);
                                                char* addPoint = strrchr(newRealPath,'/');
-                                               if ( addPoint != NULL )
-                                                       strcpy(&addPoint[1], &path[13]);
-                                               else
-                                                       strcpy(newRealPath, &path[13]);
-                                               pathToAdd = strdup(newRealPath);
+                                               if ( addPoint != NULL ) {
+                                                       strcpy(addPoint, &path[12]);
+                                                       pathToAdd = strdup(newRealPath);
+                                               }
                                        }
                                }
-                               else if ( strncmp(path, "@executable_path/", 17) == 0 ) {
+                               else if ( (strncmp(path, "@executable_path", 16) == 0) && ((path[16] == '/') || (path[16] == '\0')) ) {
                                        if ( context.processIsRestricted ) {
                                                dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @executable_path\n", path, this->getPath());
                                                break;
@@ -1061,11 +1102,10 @@ void ImageLoaderMachO::getRPaths(const LinkContext& context, std::vector<const c
                                                char newRealPath[strlen(resolvedPath) + strlen(path)];
                                                strcpy(newRealPath, resolvedPath);
                                                char* addPoint = strrchr(newRealPath,'/');
-                                               if ( addPoint != NULL )
-                                                       strcpy(&addPoint[1], &path[17]);
-                                               else
-                                                       strcpy(newRealPath, &path[17]);
-                                               pathToAdd = strdup(newRealPath);
+                                               if ( addPoint != NULL ) {
+                                                       strcpy(addPoint, &path[16]);
+                                                       pathToAdd = strdup(newRealPath);
+                                               }
                                        }
                                }
                                else if ( (path[0] != '/') && context.processIsRestricted ) {
@@ -1105,6 +1145,7 @@ void ImageLoaderMachO::getRPaths(const LinkContext& context, std::vector<const c
        }
 }
 
+
 bool ImageLoaderMachO::getUUID(uuid_t uuid) const
 {
        const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
@@ -1184,24 +1225,21 @@ void ImageLoaderMachO::doRebase(const LinkContext& context)
 #if TEXT_RELOC_SUPPORT
 void ImageLoaderMachO::makeTextSegmentWritable(const LinkContext& context, bool writeable)
 {
-       int textSegmentIndex = 0;
        for(unsigned int i=0; i < fSegmentsCount; ++i) {
-               if ( strcmp(segName(i), "__TEXT") == 0 ) {
-                       textSegmentIndex = i;
-                       break;
+               if ( segExecutable(i) ) {
+                       if ( writeable ) {
+                               segMakeWritable(i, context);
+                       }
+                       else {
+                       #if !__i386__ && !__x86_64__
+                               // some processors require range to be invalidated before it is made executable
+                               sys_icache_invalidate((void*)segActualLoadAddress(i), segSize(textSegmentIndex));
+                       #endif
+                               segProtect(i, context);
+                       }
                }
        }
 
-       if ( writeable ) {
-               segMakeWritable(textSegmentIndex, context);
-       }
-       else {
-       #if !__i386__ && !__x86_64__
-               // some processors require range to be invalidated before it is made executable
-               sys_icache_invalidate((void*)segActualLoadAddress(textSegmentIndex), segSize(textSegmentIndex));
-       #endif
-               segProtect(textSegmentIndex, context);
-       }
 }
 #endif
 
@@ -1242,16 +1280,7 @@ uintptr_t ImageLoaderMachO::getSymbolAddress(const Symbol* sym, const ImageLoade
 {
        uintptr_t result = exportedSymbolAddress(context, sym, requestor, runResolver);
        // check for interposing overrides
-       for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
-               // replace all references to 'replacee' with 'replacement'
-               if ( (result == it->replacee) && (requestor != it->replacementImage) ) {
-                       if ( context.verboseInterposing ) {
-                               dyld::log("dyld interposing: replace 0x%lX with 0x%lX in %s\n", 
-                                       it->replacee, it->replacement, this->getPath());
-                       }
-                       result = it->replacement;
-               }
-       }
+       result = interposedAddress(context, result, requestor);
        return result;
 }
 
@@ -1390,11 +1419,13 @@ bool ImageLoaderMachO::findSection(const void* imageInterior, const char** segme
 
 
 void __attribute__((noreturn)) ImageLoaderMachO::throwSymbolNotFound(const LinkContext& context, const char* symbol, 
-                                                                                                                                       const char* referencedFrom, const char* expectedIn)
+                                                                                                                                       const char* referencedFrom, const char* fromVersMismatch,
+                                                                                                                                       const char* expectedIn)
 {
        // record values for possible use by CrashReporter or Finder
        (*context.setErrorStrings)(dyld_error_kind_symbol_missing, referencedFrom, expectedIn, symbol);
-       dyld::throwf("Symbol not found: %s\n  Referenced from: %s\n  Expected in: %s\n", symbol, referencedFrom, expectedIn); 
+       dyld::throwf("Symbol not found: %s\n  Referenced from: %s%s\n  Expected in: %s\n",
+                                       symbol, referencedFrom, fromVersMismatch, expectedIn);
 }
 
 const mach_header* ImageLoaderMachO::machHeader() const
@@ -1462,7 +1493,7 @@ uintptr_t ImageLoaderMachO::bindLocation(const LinkContext& context, uintptr_t l
                        break;
                case BIND_TYPE_TEXT_PCREL32:
                        loc32 = (uint32_t*)locationToFix;
-                       value32 = (uint32_t)newValue - (((uintptr_t)locationToFix) + 4);
+                       value32 = (uint32_t)(newValue - (((uintptr_t)locationToFix) + 4));
                        if ( *loc32 != value32 )
                                *loc32 = value32;
                        break;
@@ -1488,7 +1519,7 @@ uintptr_t ImageLoaderMachO::bindLocation(const LinkContext& context, uintptr_t l
 #endif
 
 struct DATAdyld {
-       void*                   dyldLazyBinder;         // filled in at launch by dyld to point into dyld to &stub_binding_helper_interface
+       void*                   dyldLazyBinder;         // filled in at launch by dyld to point into dyld to &stub_binding_helper
        void*                   dyldFuncLookup;         // filled in at launch by dyld to point into dyld to &_dyld_func_lookup
        // the following only exist in main executables built for 10.5 or later
        ProgramVars             vars;
@@ -1496,7 +1527,6 @@ struct DATAdyld {
 
 // These are defined in dyldStartup.s
 extern "C" void stub_binding_helper();
-extern "C" bool dyld_func_lookup(const char* name, uintptr_t* address);
 
 
 void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext& context)
@@ -1519,13 +1549,15 @@ void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext& context)
                                        for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
                                                if ( strcmp(sect->sectname, "__dyld" ) == 0 ) {
                                                        struct DATAdyld* dd = (struct DATAdyld*)(sect->addr + fSlide);
+                               #if !__arm64__
                                                        if ( sect->size > offsetof(DATAdyld, dyldLazyBinder) ) {
                                                                if ( dd->dyldLazyBinder != (void*)&stub_binding_helper )
                                                                        dd->dyldLazyBinder = (void*)&stub_binding_helper;
                                                        }
+                               #endif // !__arm64__
                                                        if ( sect->size > offsetof(DATAdyld, dyldFuncLookup) ) {
-                                                               if ( dd->dyldFuncLookup != (void*)&dyld_func_lookup )
-                                                                       dd->dyldFuncLookup = (void*)&dyld_func_lookup;
+                                                               if ( dd->dyldFuncLookup != (void*)&_dyld_func_lookup )
+                                                                       dd->dyldFuncLookup = (void*)&_dyld_func_lookup;
                                                        }
                                                        if ( mh->filetype == MH_EXECUTE ) {
                                                                // there are two ways to get the program variables
@@ -1670,8 +1702,8 @@ void ImageLoaderMachO::doModInitFunctions(const LinkContext& context)
                                        const uint8_t type = sect->flags & SECTION_TYPE;
                                        if ( type == S_MOD_INIT_FUNC_POINTERS ) {
                                                Initializer* inits = (Initializer*)(sect->addr + fSlide);
-                                               const uint32_t count = sect->size / sizeof(uintptr_t);
-                                               for (uint32_t i=0; i < count; ++i) {
+                                               const size_t count = sect->size / sizeof(uintptr_t);
+                                               for (size_t i=0; i < count; ++i) {
                                                        Initializer func = inits[i];
                                                        // <rdar://problem/8543820&9228031> verify initializers are in image
                                                        if ( ! this->containsAddress((void*)func) ) {
@@ -1766,8 +1798,8 @@ void ImageLoaderMachO::doTermination(const LinkContext& context)
                                        const uint8_t type = sect->flags & SECTION_TYPE;
                                        if ( type == S_MOD_TERM_FUNC_POINTERS ) {
                                                Terminator* terms = (Terminator*)(sect->addr + fSlide);
-                                               const uint32_t count = sect->size / sizeof(uintptr_t);
-                                               for (uint32_t i=count; i > 0; --i) {
+                                               const size_t count = sect->size / sizeof(uintptr_t);
+                                               for (size_t i=count; i > 0; --i) {
                                                        Terminator func = terms[i-1];
                                                        // <rdar://problem/8543820&9228031> verify terminators are in image
                                                        if ( ! this->containsAddress((void*)func) ) {
@@ -1808,7 +1840,13 @@ intptr_t ImageLoaderMachO::assignSegmentAddresses(const LinkContext& context)
                uintptr_t highAddr = 0;
                for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
                        const uintptr_t segLow = segPreferredLoadAddress(i);
-                       const uintptr_t segHigh = (segLow + segSize(i) + 4095) & -4096;
+                       const uintptr_t segHigh = dyld_page_round(segLow + segSize(i));
+                       if ( segLow < highAddr ) {
+                               if ( dyld_page_size > 4096 )
+                                       dyld::throwf("can't map segments into 16KB pages");
+                               else
+                                       dyld::throwf("overlapping segments");
+                       }
                        if ( segLow < lowAddr )
                                lowAddr = segLow;
                        if ( segHigh > highAddr )
@@ -1845,7 +1883,7 @@ uintptr_t ImageLoaderMachO::reserveAnAddressRange(size_t length, const ImageLoad
        // in PIE programs, load initial dylibs after main executable so they don't have fixed addresses either
        if ( fgNextPIEDylibAddress != 0 ) {
                 // add small (0-3 pages) random padding between dylibs
-               addr = fgNextPIEDylibAddress + (__stack_chk_guard/fgNextPIEDylibAddress & (sizeof(long)-1))*4096;
+               addr = fgNextPIEDylibAddress + (__stack_chk_guard/fgNextPIEDylibAddress & (sizeof(long)-1))*dyld_page_size;
                //dyld::log("padding 0x%08llX, guard=0x%08llX\n", (long long)(addr - fgNextPIEDylibAddress), (long long)(__stack_chk_guard));
                kern_return_t r = vm_alloc(&addr, size, VM_FLAGS_FIXED | VM_MAKE_TAG(VM_MEMORY_DYLIB));
                if ( r == KERN_SUCCESS ) {
@@ -1877,8 +1915,12 @@ void ImageLoaderMachO::mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInF
 {
        // find address range for image
        intptr_t slide = this->assignSegmentAddresses(context);
-       if ( context.verboseMapping )
-               dyld::log("dyld: Mapping %s\n", this->getPath());
+       if ( context.verboseMapping ) {
+               if ( offsetInFat != 0 )
+                       dyld::log("dyld: Mapping %s (slice offset=%llu)\n", this->getPath(), (unsigned long long)offsetInFat);
+               else
+                       dyld::log("dyld: Mapping %s\n", this->getPath());
+       }
        // map in all segments
        for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
                vm_offset_t fileOffset = segFileOffset(i) + offsetInFat;
@@ -1888,7 +1930,6 @@ void ImageLoaderMachO::mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInF
                if ( !segUnaccessible(i) ) {
                        // If has text-relocs, don't set x-bit initially.
                        // Instead set it later after text-relocs have been done.
-                       // The iPhone OS does not like it when you make executable code writable.
                        if ( segExecutable(i) && !(segHasRebaseFixUps(i) && (slide != 0)) )
                                protection   |= PROT_EXEC;
                        if ( segReadable(i) )
index 6d5c7442c2bab8c3ba6059be5ce9e08f3037ce57..4505d63990b58ad8f70caeefe4d3952d8b92f0be 100644 (file)
@@ -101,9 +101,11 @@ public:
        virtual uintptr_t                                       segActualEndAddress(unsigned int) const;
        virtual void                                            registerInterposing();
        virtual uint32_t                                        sdkVersion() const;
+       virtual uint32_t                                        minOSVersion() const;
                        
        
        static void                                                     printStatistics(unsigned int imageCount, const InitializerTimingList&);
+       static  uint32_t                                        minOSVersion(const mach_header*);
        
 protected:
                                                ImageLoaderMachO(const ImageLoaderMachO&);
@@ -176,7 +178,8 @@ protected:
                        void            mapSegments(const void* memoryImage, uint64_t imageLen, const LinkContext& context);
                        void            UnmapSegments();
                        void            __attribute__((noreturn)) throwSymbolNotFound(const LinkContext& context, const char* symbol, 
-                                                                                                                                       const char* referencedFrom, const char* expectedIn);
+                                                                                                                                       const char* referencedFrom, const char* fromVersMismatch,
+                                                                                                                                       const char* expectedIn);
                        void            doImageInit(const LinkContext& context);
                        void            doModInitFunctions(const LinkContext& context);
                        void            setupLazyPointerHandler(const LinkContext& context);
index 3eed9da87ece924d7c7db70fa5be8dc82d31843e..8190f1d37629d4a8e825a8407ffe4c5e6b1f9dca 100644 (file)
@@ -55,7 +55,7 @@
 #include "mach-o/dyld_images.h"
 
 // in dyldStartup.s
-extern "C" void fast_stub_binding_helper_interface();
+extern "C" void stub_binding_helper_i386_old();
 
 
 #if __x86_64__
@@ -352,11 +352,11 @@ void ImageLoaderMachOClassic::prefetchLINKEDIT(const LinkContext& context)
                end += fSymbolTable[fDynamicInfo->iextdefsym+fDynamicInfo->nextdefsym-1].n_un.n_strx;
                
        // round to whole pages
-       start = start & (-4096);
-       end = (end + 4095) & (-4096);
+       start = dyld_page_trunc(start);
+       end = dyld_page_round(end);
        
        // skip if there is only one page
-       if ( (end-start) > 4096 ) {
+       if ( (end-start) > dyld_page_size ) {
                madvise((void*)start, end-start, MADV_WILLNEED);
                fgTotalBytesPreFetched += (end-start);
                if ( context.verboseMapping ) {
@@ -619,7 +619,7 @@ bool ImageLoaderMachOClassic::hasSubLibrary(const LinkContext& context, const Im
                        const char* lastSlash = strrchr(childInstallPath, '/');
                        if ( lastSlash != NULL ) {
                                const char* firstDot = strchr(lastSlash, '.');
-                               int len;
+                               size_t len;
                                if ( firstDot == NULL )
                                        len = strlen(lastSlash);
                                else
@@ -1071,7 +1071,7 @@ uintptr_t ImageLoaderMachOClassic::resolveUndefined(const LinkContext& context,
                        // if reference is weak_import, then it is ok, just return 0
                        return 0;
                }
-               throwSymbolNotFound(context, symbolName, this->getPath(), "flat namespace");
+               throwSymbolNotFound(context, symbolName, this->getPath(), "", "flat namespace");
        }
        else {
                // symbol requires searching images with coalesced symbols (not done during prebinding)
@@ -1116,7 +1116,7 @@ uintptr_t ImageLoaderMachOClassic::resolveUndefined(const LinkContext& context,
                        if ( context.flatExportFinder(symbolName, &sym, foundIn) )
                                return (*foundIn)->getExportedSymbolAddress(sym, context, this);
                        
-                       throwSymbolNotFound(context, symbolName, this->getPath(), "dynamic lookup");
+                       throwSymbolNotFound(context, symbolName, this->getPath(), "", "dynamic lookup");
                }
                else if ( ord <= libraryCount() ) {
                        target = libImage(ord-1);
@@ -1150,7 +1150,7 @@ uintptr_t ImageLoaderMachOClassic::resolveUndefined(const LinkContext& context,
                }
                
                // nowhere to be found
-               throwSymbolNotFound(context, symbolName, this->getPath(), target->getPath());
+               throwSymbolNotFound(context, symbolName, this->getPath(), "", target->getPath());
        }
 }
 
@@ -1402,11 +1402,11 @@ uintptr_t ImageLoaderMachOClassic::doBindLazySymbol(uintptr_t* lazyPointer, cons
                                                const uint8_t type = sect->flags & SECTION_TYPE;
                                                uint32_t symbolIndex = INDIRECT_SYMBOL_LOCAL;
                                                if ( type == S_LAZY_SYMBOL_POINTERS ) {
-                                                       const uint32_t pointerCount = sect->size / sizeof(uintptr_t);
+                                                       const size_t pointerCount = sect->size / sizeof(uintptr_t);
                                                        uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + fSlide);
                                                        if ( (lazyPointer >= symbolPointers) && (lazyPointer < &symbolPointers[pointerCount]) ) {
                                                                const uint32_t indirectTableOffset = sect->reserved1;
-                                                               const uint32_t lazyIndex = lazyPointer - symbolPointers;
+                                                               const size_t lazyIndex = lazyPointer - symbolPointers;
                                                                symbolIndex = indirectTable[indirectTableOffset + lazyIndex];
                                                        }
                                                }
@@ -1519,7 +1519,7 @@ uintptr_t ImageLoaderMachOClassic::getAddressCoalIterator(CoalIterator& it, cons
                symbol_index = toc[it.curIndex-1].symbol_index;
        }
        else {
-               symbol_index = fDynamicInfo->iextdefsym+it.curIndex-1;
+               symbol_index = fDynamicInfo->iextdefsym + (uint32_t)it.curIndex - 1;
        }       
        const struct macho_nlist* sym = &fSymbolTable[symbol_index];
        //dyld::log("getAddressCoalIterator() => 0x%llX, %s symbol_index=%d, in %s\n", (uint64_t)(sym->n_value + fSlide), &fStrings[sym->n_un.n_strx], symbol_index, this->getPath());
@@ -1554,7 +1554,7 @@ void ImageLoaderMachOClassic::updateUsesCoalIterator(CoalIterator& it, uintptr_t
                symbol_index = toc[it.curIndex-1].symbol_index;
        }
        else {
-               symbol_index = fDynamicInfo->iextdefsym+it.curIndex-1;
+               symbol_index = fDynamicInfo->iextdefsym + (uint32_t)it.curIndex - 1;
        }       
 
        // if this image's copy of the symbol is not a weak definition nor a weak reference then nothing to coalesce here
@@ -1664,11 +1664,11 @@ void ImageLoaderMachOClassic::updateUsesCoalIterator(CoalIterator& it, uintptr_t
                                        case S_NON_LAZY_SYMBOL_POINTERS:
                                        case S_LAZY_SYMBOL_POINTERS:
                                        {
-                                               uint32_t elementCount = sect->size / elementSize;
+                                               size_t elementCount = sect->size / elementSize;
                                                const uint32_t indirectTableOffset = sect->reserved1;
                                                uint8_t* ptrToBind = (uint8_t*)(sect->addr + fSlide);
                                                //dyld::log(" scanning section %s of %s starting at %p\n", sect->sectname, this->getShortName(), ptrToBind);
-                                               for (uint32_t j=0; j < elementCount; ++j, ptrToBind += elementSize) {
+                                               for (size_t j=0; j < elementCount; ++j, ptrToBind += elementSize) {
                                                        if ( indirectTable[indirectTableOffset + j] == symbol_index ) {
                                                                //dyld::log("  found symbol index match at %d/%d, ptrToBind=%p\n", j, elementCount, ptrToBind);
                                                                // update pointer
@@ -1711,7 +1711,7 @@ void ImageLoaderMachOClassic::bindIndirectSymbolPointers(const LinkContext& cont
                                                bool isLazySymbol = false;
                                                const uint8_t type = sect->flags & SECTION_TYPE;
                                                uint32_t elementSize = sizeof(uintptr_t);
-                                               uint32_t elementCount = sect->size / elementSize;
+                                               size_t elementCount = sect->size / elementSize;
                                                if ( type == S_NON_LAZY_SYMBOL_POINTERS ) {
                                                        if ( ! bindNonLazys )
                                                                continue;
@@ -1739,7 +1739,7 @@ void ImageLoaderMachOClassic::bindIndirectSymbolPointers(const LinkContext& cont
                                                }
                                                const uint32_t indirectTableOffset = sect->reserved1;
                                                uint8_t* ptrToBind = (uint8_t*)(sect->addr + fSlide);
-                                               for (uint32_t j=0; j < elementCount; ++j, ptrToBind += elementSize) {
+                                               for (size_t j=0; j < elementCount; ++j, ptrToBind += elementSize) {
                                #if LINKEDIT_USAGE_DEBUG
                                                        noteAccessedLinkEditAddress(&indirectTable[indirectTableOffset + j]);
                                #endif
@@ -1832,7 +1832,7 @@ void ImageLoaderMachOClassic::initializeLazyStubs(const LinkContext& context)
                                                        const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff];
                                                        uint8_t* start = (uint8_t*)(sect->addr + this->fSlide);
                                                        uint8_t* end = start + sect->size;
-                                                       uintptr_t dyldHandler = (uintptr_t)&fast_stub_binding_helper_interface;
+                                                       uintptr_t dyldHandler = (uintptr_t)&stub_binding_helper_i386_old;
                                                        uint32_t entryIndex = 0;
                                                        for (uint8_t* entry = start; entry < end; entry += 5, ++entryIndex) {
                                                                bool installLazyHandler = true;
@@ -1950,19 +1950,12 @@ void ImageLoaderMachOClassic::doInterpose(const LinkContext& context)
                                        for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
                                                const uint8_t type = sect->flags & SECTION_TYPE;
                                                if ( (type == S_NON_LAZY_SYMBOL_POINTERS) || (type == S_LAZY_SYMBOL_POINTERS) ) {
-                                                       const uint32_t pointerCount = sect->size / sizeof(uintptr_t);
+                                                       const size_t pointerCount = sect->size / sizeof(uintptr_t);
                                                        uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + fSlide);
-                                                       for (uint32_t pointerIndex=0; pointerIndex < pointerCount; ++pointerIndex) {
-                                                               for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
-                                                                       // replace all references to 'replacee' with 'replacement'
-                                                                       if ( (symbolPointers[pointerIndex] == it->replacee) && (this != it->replacementImage) ) {
-                                                                               if ( context.verboseInterposing ) {
-                                                                                       dyld::log("dyld: interposing: at %p replace 0x%lX with 0x%lX in %s\n", 
-                                                                                               &symbolPointers[pointerIndex], it->replacee, it->replacement, this->getPath());
-                                                                               }
-                                                                               symbolPointers[pointerIndex] = it->replacement;
-                                                                       }
-                                                               }
+                                                       for (size_t pointerIndex=0; pointerIndex < pointerCount; ++pointerIndex) {
+                                                               uintptr_t newValue = interposedAddress(context, symbolPointers[pointerIndex], this);
+                                                               if ( newValue != symbolPointers[pointerIndex] )
+                                                                       symbolPointers[pointerIndex] = newValue;
                                                        }
                                                }
                                #if __i386__
@@ -1975,16 +1968,10 @@ void ImageLoaderMachOClassic::doInterpose(const LinkContext& context)
                                                                if ( entry[0] == 0xE9 ) { // 0xE9 == JMP 
                                                                        uint32_t rel32 = *((uint32_t*)&entry[1]); // assume unaligned load of uint32_t is ok
                                                                        uint32_t target = (uint32_t)&entry[5] + rel32;
-                                                                       for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
-                                                                               // replace all references to 'replacee' with 'replacement'
-                                                                               if ( (it->replacee == target) && (this != it->replacementImage) ) {
-                                                                                       if ( context.verboseInterposing ) {
-                                                                                               dyld::log("dyld: interposing: at %p replace JMP 0x%lX with JMP 0x%lX in %s\n", 
-                                                                                                       &entry[1], it->replacee, it->replacement, this->getPath());
-                                                                                       }
-                                                                                       uint32_t newRel32 = it->replacement - (uint32_t)&entry[5];
-                                                                                       *((uint32_t*)&entry[1]) = newRel32; // assume unaligned store of uint32_t is ok
-                                                                               }
+                                                                       uint32_t newTarget = interposedAddress(context, target, this);
+                                                                       if ( newTarget != target ) {
+                                                                               uint32_t newRel32 = newTarget - (uint32_t)&entry[5];
+                                                                               *((uint32_t*)&entry[1]) = newRel32; // assume unaligned store of uint32_t is ok
                                                                        }
                                                                }
                                                        }
@@ -2007,14 +1994,76 @@ void ImageLoaderMachOClassic::doInterpose(const LinkContext& context)
                                case POINTER_RELOC:
                                        {
                                                uintptr_t* location = ((uintptr_t*)(reloc->r_address + relocBase));
-                                               for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
+                                               uintptr_t value = *location;
+                                               uintptr_t newValue = interposedAddress(context, value, this);
+                                               if ( newValue != value )
+                                                       *location = newValue;
+                                       }
+                                       break;
+                       }
+               }
+       }
+}
+
+void ImageLoaderMachOClassic::dynamicInterpose(const LinkContext& context) 
+{
+       if ( context.verboseInterposing )
+               dyld::log("dyld: dynamic interposing %lu tuples onto image: %s\n", context.dynamicInterposeCount, this->getPath());
+
+       // scan indirect symbols
+       const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
+       const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
+       const struct load_command* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               switch (cmd->cmd) {
+                       case LC_SEGMENT_COMMAND:
+                               {
+                                       const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
+                                       const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
+                                       const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
+                                       for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+                                               const uint8_t type = sect->flags & SECTION_TYPE;
+                                               if ( (type == S_NON_LAZY_SYMBOL_POINTERS) || (type == S_LAZY_SYMBOL_POINTERS) ) {
+                                                       const size_t pointerCount = sect->size / sizeof(uintptr_t);
+                                                       uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + fSlide);
+                                                       for (size_t pointerIndex=0; pointerIndex < pointerCount; ++pointerIndex) {
+                                                               for(size_t i=0; i < context.dynamicInterposeCount; ++i) {
+                                                                       // replace all references to 'replacee' with 'replacement'
+                                                                       if ( symbolPointers[pointerIndex] == (uintptr_t)context.dynamicInterposeArray[i].replacee ) {
+                                                                               if ( context.verboseInterposing ) {
+                                                                                       dyld::log("dyld: dynamic interposing: at %p replace %p with %p in %s\n", 
+                                                                                               &symbolPointers[pointerIndex], context.dynamicInterposeArray[i].replacee, context.dynamicInterposeArray[i].replacement, this->getPath());
+                                                                               }
+                                                                               symbolPointers[pointerIndex] = (uintptr_t)context.dynamicInterposeArray[i].replacement;
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                               break;
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+       }
+       
+       // scan external relocations 
+       const uintptr_t relocBase = this->getRelocBase();
+       const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->extreloff]);
+       const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nextrel];
+       for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
+               if (reloc->r_length == RELOC_SIZE) {
+                       switch(reloc->r_type) {
+                               case POINTER_RELOC:
+                                       {
+                                               uintptr_t* location = ((uintptr_t*)(reloc->r_address + relocBase));
+                                               for(size_t i=0; i < context.dynamicInterposeCount; ++i) {
                                                        // replace all references to 'replacee' with 'replacement'
-                                                       if ( (*location == it->replacee) && (this != it->replacementImage) ) {
+                                                       if ( *location == (uintptr_t)context.dynamicInterposeArray[i].replacee ) {
                                                                if ( context.verboseInterposing ) {
-                                                                       dyld::log("dyld: interposing: at %p replace 0x%lX with 0x%lX in %s\n", 
-                                                                               location, it->replacee, it->replacement, this->getPath());
+                                                                       dyld::log("dyld: dynamic interposing: at %p replace %p with %p in %s\n", 
+                                                                               location, context.dynamicInterposeArray[i].replacee, context.dynamicInterposeArray[i].replacement, this->getPath());
                                                                }
-                                                               *location = it->replacement;
+                                                               *location = (uintptr_t)context.dynamicInterposeArray[i].replacement;
                                                        }
                                                }
                                        }
index 55685a5995021612dda013fa829b64d8a0327f48..88db64cbe07526921a3dfbb823a78d931c135686 100644 (file)
@@ -66,6 +66,7 @@ public:
 
 protected:
        virtual void                                            doInterpose(const LinkContext& context);
+       virtual void                                            dynamicInterpose(const LinkContext& context);
        virtual void                                            setDyldInfo(const dyld_info_command*) {}
        virtual void                                            setSymbolTableInfo(const macho_nlist*, const char*, const dysymtab_command*);
        virtual bool                                            isSubframeworkOf(const LinkContext& context, const ImageLoader* image) const;
index 5ba89ec01f14d6714ee99a624975422c238c574c..6a3a535d28b0395ed889e3fba135782db7d8c317 100644 (file)
@@ -374,11 +374,11 @@ void ImageLoaderMachOCompressed::markLINKEDIT(const LinkContext& context, int ad
                
                        
        // round to whole pages
-       start = start & (-4096);
-       end = (end + 4095) & (-4096);
+       start = dyld_page_trunc(start);
+       end = dyld_page_round(end);
 
        // do nothing if only one page of rebase/bind info
-       if ( (end-start) <= 4096 )
+       if ( (end-start) <= dyld_page_size )
                return;
        
        // tell kernel about our access to these pages
@@ -433,8 +433,8 @@ void ImageLoaderMachOCompressed::rebase(const LinkContext& context)
                int segmentIndex = 0;
                uintptr_t address = segActualLoadAddress(0);
                uintptr_t segmentEndAddress = segActualEndAddress(0);
-               uint32_t count;
-               uint32_t skip;
+               uintptr_t count;
+               uintptr_t skip;
                bool done = false;
                while ( !done && (p < end) ) {
                        uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
@@ -449,9 +449,9 @@ void ImageLoaderMachOCompressed::rebase(const LinkContext& context)
                                        break;
                                case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
                                        segmentIndex = immediate;
-                                       if ( segmentIndex > fSegmentsCount )
-                                               dyld::throwf("REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (%d)\n", 
-                                                               segmentIndex, fSegmentsCount);
+                                       if ( segmentIndex >= fSegmentsCount )
+                                               dyld::throwf("REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (0..%d)",
+                                                               segmentIndex, fSegmentsCount-1);
                                        address = segActualLoadAddress(segmentIndex) + read_uleb128(p, end);
                                        segmentEndAddress = segActualEndAddress(segmentIndex);
                                        break;
@@ -519,7 +519,7 @@ const uint8_t* ImageLoaderMachOCompressed::trieWalk(const uint8_t* start, const
 {
        const uint8_t* p = start;
        while ( p != NULL ) {
-               uint32_t terminalSize = *p++;
+               uintptr_t terminalSize = *p++;
                if ( terminalSize > 127 ) {
                        // except for re-export-with-rename, all terminal sizes fit in one byte
                        --p;
@@ -533,7 +533,7 @@ const uint8_t* ImageLoaderMachOCompressed::trieWalk(const uint8_t* start, const
                //dyld::log("trieWalk(%p) sym=%s, terminalSize=%d, children=%p\n", start, s, terminalSize, children);
                uint8_t childrenRemaining = *children++;
                p = children;
-               uint32_t nodeOffset = 0;
+               uintptr_t nodeOffset = 0;
                for (; childrenRemaining > 0; --childrenRemaining) {
                        const char* ss = s;
                        //dyld::log("trieWalk(%p) child str=%s\n", start, (char*)p);
@@ -592,16 +592,16 @@ const ImageLoader::Symbol* ImageLoaderMachOCompressed::findExportedSymbol(const
        const uint8_t* foundNodeStart = this->trieWalk(start, end, symbol); 
        if ( foundNodeStart != NULL ) {
                const uint8_t* p = foundNodeStart;
-               const uint32_t flags = read_uleb128(p, end);
+               const uintptr_t flags = read_uleb128(p, end);
                // found match, return pointer to terminal part of node
                if ( flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
                        // re-export from another dylib, lookup there
-                       const uint32_t ordinal = read_uleb128(p, end);
+                       const uintptr_t ordinal = read_uleb128(p, end);
                        const char* importedName = (char*)p;
                        if ( importedName[0] == '\0' )
                                importedName = symbol;
                        if ( (ordinal > 0) && (ordinal <= libraryCount()) ) {
-                               const ImageLoader* reexportedFrom = libImage(ordinal-1);
+                               const ImageLoader* reexportedFrom = libImage((unsigned int)ordinal-1);
                                //dyld::log("Compressed::findExportedSymbol(), %s -> %s/%s\n", symbol, reexportedFrom->getShortName(), importedName);
                                return reexportedFrom->findExportedSymbol(importedName, true, foundIn);
                        }
@@ -638,23 +638,17 @@ uintptr_t ImageLoaderMachOCompressed::exportedSymbolAddress(const LinkContext& c
        if ( (exportNode < exportTrieStart) || (exportNode > exportTrieEnd) )
                throw "symbol is not in trie";
        //dyld::log("exportedSymbolAddress(): node=%p, nodeOffset=0x%04X in %s\n", symbol, (int)((uint8_t*)symbol - exportTrieStart), this->getShortName());
-       uint32_t flags = read_uleb128(exportNode, exportTrieEnd);
+       uintptr_t flags = read_uleb128(exportNode, exportTrieEnd);
        switch ( flags & EXPORT_SYMBOL_FLAGS_KIND_MASK ) {
                case EXPORT_SYMBOL_FLAGS_KIND_REGULAR:
                        if ( runResolver && (flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) ) {
                                // this node has a stub and resolver, run the resolver to get target address
                                uintptr_t stub = read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)fMachOData; // skip over stub
                                // <rdar://problem/10657737> interposing dylibs have the stub address as their replacee
-                               for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
-                                       // replace all references to 'replacee' with 'replacement'
-                                       if ( (stub == it->replacee) && (requestor != it->replacementImage) ) {
-                                               if ( context.verboseInterposing ) {
-                                                       dyld::log("dyld interposing: lazy replace 0x%lX with 0x%lX from %s\n",
-                                                                         it->replacee, it->replacement, this->getPath());
-                                               }
-                                               return it->replacement;
-                                       }
-                               }
+                               uintptr_t interposedStub = interposedAddress(context, stub, requestor);
+                               if ( interposedStub != stub )
+                                       return interposedStub;
+                               // stub was not interposed, so run resolver
                                typedef uintptr_t (*ResolverProc)(void);
                                ResolverProc resolver = (ResolverProc)(read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)fMachOData);
                                uintptr_t result = (*resolver)();
@@ -665,14 +659,14 @@ uintptr_t ImageLoaderMachOCompressed::exportedSymbolAddress(const LinkContext& c
                        return read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)fMachOData;
                case EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL:
                        if ( flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER )
-                               dyld::throwf("unsupported exported symbol kind. flags=%d at node=%p", flags, symbol);
+                               dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags, symbol);
                        return read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)fMachOData;
                case EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE:
                        if ( flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER )
-                               dyld::throwf("unsupported exported symbol kind. flags=%d at node=%p", flags, symbol);
+                               dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags, symbol);
                        return read_uleb128(exportNode, exportTrieEnd);
                default:
-                       dyld::throwf("unsupported exported symbol kind. flags=%d at node=%p", flags, symbol);
+                       dyld::throwf("unsupported exported symbol kind. flags=%lu at node=%p", flags, symbol);
        }
 }
 
@@ -683,7 +677,7 @@ bool ImageLoaderMachOCompressed::exportedSymbolIsWeakDefintion(const Symbol* sym
        const uint8_t* exportTrieEnd = exportTrieStart + fDyldInfo->export_size;
        if ( (exportNode < exportTrieStart) || (exportNode > exportTrieEnd) )
                throw "symbol is not in trie";
-       uint32_t flags = read_uleb128(exportNode, exportTrieEnd);
+       uintptr_t flags = read_uleb128(exportNode, exportTrieEnd);
        return ( flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION );
 }
 
@@ -740,7 +734,7 @@ uintptr_t ImageLoaderMachOCompressed::resolveFlat(const LinkContext& context, co
                // definition can't be found anywhere, ok because it is weak, just return 0
                return 0;
        }
-       throwSymbolNotFound(context, symbolName, this->getPath(), "flat namespace");
+       throwSymbolNotFound(context, symbolName, this->getPath(), "", "flat namespace");
 }
 
 
@@ -758,13 +752,29 @@ uintptr_t ImageLoaderMachOCompressed::resolveTwolevel(const LinkContext& context
                return 0;
        }
 
-       // nowhere to be found
-       throwSymbolNotFound(context, symbolName, this->getPath(), targetImage->getPath());
+       // nowhere to be found, check if maybe this image is too new for this OS
+       char versMismatch[256];
+       versMismatch[0] = '\0';
+       uint32_t imageMinOS = this->minOSVersion();
+       // dyld is always built for the current OS, so we can get the current OS version
+       // from the load command in dyld itself.
+       extern const mach_header __dso_handle;
+       uint32_t dyldMinOS = ImageLoaderMachO::minOSVersion(&__dso_handle);
+       if ( imageMinOS > dyldMinOS ) {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+               const char* msg = dyld::mkstringf(" (which was built for Mac OS X %d.%d)", imageMinOS >> 16, (imageMinOS >> 8) & 0xFF);
+#else
+               const char* msg = dyld::mkstringf(" (which was built for iOS %d.%d)", imageMinOS >> 16, (imageMinOS >> 8) & 0xFF);
+#endif
+               strcpy(versMismatch, msg);
+               ::free((void*)msg);
+       }
+       throwSymbolNotFound(context, symbolName, this->getPath(), versMismatch, targetImage->getPath());
 }
 
 
 uintptr_t ImageLoaderMachOCompressed::resolve(const LinkContext& context, const char* symbolName, 
-                                                                                                       uint8_t symboFlags, int libraryOrdinal, const ImageLoader** targetImage,
+                                                                                                       uint8_t symboFlags, long libraryOrdinal, const ImageLoader** targetImage,
                                                                                                        LastLookup* last, bool runResolver)
 {
        *targetImage = NULL;
@@ -792,14 +802,14 @@ uintptr_t ImageLoaderMachOCompressed::resolve(const LinkContext& context, const
                        *targetImage = this;
                }
                else if ( libraryOrdinal <= 0 ) {
-                       dyld::throwf("bad mach-o binary, unknown special library ordinal (%u) too big for symbol %s in %s",
+                       dyld::throwf("bad mach-o binary, unknown special library ordinal (%ld) too big for symbol %s in %s",
                                libraryOrdinal, symbolName, this->getPath());
                }
                else if ( (unsigned)libraryOrdinal <= libraryCount() ) {
-                       *targetImage = libImage(libraryOrdinal-1);
+                       *targetImage = libImage((unsigned int)libraryOrdinal-1);
                }
                else {
-                       dyld::throwf("bad mach-o binary, library ordinal (%u) too big (max %u) for symbol %s in %s",
+                       dyld::throwf("bad mach-o binary, library ordinal (%ld) too big (max %u) for symbol %s in %s",
                                libraryOrdinal, libraryCount(), symbolName, this->getPath());
                }
                if ( *targetImage == NULL ) {
@@ -808,7 +818,7 @@ uintptr_t ImageLoaderMachOCompressed::resolve(const LinkContext& context, const
                                symbolAddress = 0;
                        }
                        else {
-                               dyld::throwf("can't resolve symbol %s in %s because dependent dylib #%d could not be loaded",
+                               dyld::throwf("can't resolve symbol %s in %s because dependent dylib #%ld could not be loaded",
                                        symbolName, this->getPath(), libraryOrdinal);
                        }
                }
@@ -830,7 +840,7 @@ uintptr_t ImageLoaderMachOCompressed::resolve(const LinkContext& context, const
 }
 
 uintptr_t ImageLoaderMachOCompressed::bindAt(const LinkContext& context, uintptr_t addr, uint8_t type, const char* symbolName, 
-                                                               uint8_t symboFlags, intptr_t addend, int libraryOrdinal, const char* msg, 
+                                                               uint8_t symboFlags, intptr_t addend, long libraryOrdinal, const char* msg, 
                                                                LastLookup* last, bool runResolver)
 {
        const ImageLoader*      targetImage;
@@ -915,10 +925,10 @@ void ImageLoaderMachOCompressed::eachBind(const LinkContext& context, bind_handl
                uintptr_t segmentEndAddress = segActualEndAddress(0);
                const char* symbolName = NULL;
                uint8_t symboFlags = 0;
-               int libraryOrdinal = 0;
+               long libraryOrdinal = 0;
                intptr_t addend = 0;
-               uint32_t count;
-               uint32_t skip;
+               uintptr_t count;
+               uintptr_t skip;
                LastLookup last = { 0, 0, NULL, 0, NULL };
                const uint8_t* const start = fLinkEditBase + fDyldInfo->bind_off;
                const uint8_t* const end = &start[fDyldInfo->bind_size];
@@ -962,9 +972,9 @@ void ImageLoaderMachOCompressed::eachBind(const LinkContext& context, bind_handl
                                        break;
                                case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
                                        segmentIndex = immediate;
-                                       if ( segmentIndex > fSegmentsCount )
-                                               dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (%d)\n", 
-                                                               segmentIndex, fSegmentsCount);
+                                       if ( segmentIndex >= fSegmentsCount )
+                                               dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (0..%d)",
+                                                               segmentIndex, fSegmentsCount-1);
                                        address = segActualLoadAddress(segmentIndex) + read_uleb128(p, end);
                                        segmentEndAddress = segActualEndAddress(segmentIndex);
                                        break;
@@ -1020,7 +1030,7 @@ void ImageLoaderMachOCompressed::eachLazyBind(const LinkContext& context, bind_h
                uintptr_t segmentEndAddress = segActualEndAddress(0);
                const char* symbolName = NULL;
                uint8_t symboFlags = 0;
-               int libraryOrdinal = 0;
+               long libraryOrdinal = 0;
                intptr_t addend = 0;
                const uint8_t* const start = fLinkEditBase + fDyldInfo->lazy_bind_off;
                const uint8_t* const end = &start[fDyldInfo->lazy_bind_size];
@@ -1064,9 +1074,9 @@ void ImageLoaderMachOCompressed::eachLazyBind(const LinkContext& context, bind_h
                                        break;
                                case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
                                        segmentIndex = immediate;
-                                       if ( segmentIndex > fSegmentsCount )
-                                               dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (%d)\n", 
-                                                               segmentIndex, fSegmentsCount);
+                                       if ( segmentIndex >= fSegmentsCount )
+                                               dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (0..%d)",
+                                                               segmentIndex, fSegmentsCount-1);
                                        address = segActualLoadAddress(segmentIndex) + read_uleb128(p, end);
                                        segmentEndAddress = segActualEndAddress(segmentIndex);
                                        break;
@@ -1140,11 +1150,11 @@ uintptr_t ImageLoaderMachOCompressed::doBindLazySymbol(uintptr_t* lazyPointer, c
                                                const uint8_t type = sect->flags & SECTION_TYPE;
                                                uint32_t symbolIndex = INDIRECT_SYMBOL_LOCAL;
                                                if ( type == S_LAZY_SYMBOL_POINTERS ) {
-                                                       const uint32_t pointerCount = sect->size / sizeof(uintptr_t);
+                                                       const size_t pointerCount = sect->size / sizeof(uintptr_t);
                                                        uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + fSlide);
                                                        if ( (lazyPointer >= symbolPointers) && (lazyPointer < &symbolPointers[pointerCount]) ) {
                                                                const uint32_t indirectTableOffset = sect->reserved1;
-                                                               const uint32_t lazyIndex = lazyPointer - symbolPointers;
+                                                               const size_t lazyIndex = lazyPointer - symbolPointers;
                                                                symbolIndex = indirectTable[indirectTableOffset + lazyIndex];
                                                        }
                                                }
@@ -1193,7 +1203,7 @@ uintptr_t ImageLoaderMachOCompressed::doBindFastLazySymbol(uint32_t lazyBindingI
        uintptr_t address = 0;
        const char* symbolName = NULL;
        uint8_t symboFlags = 0;
-       int libraryOrdinal = 0;
+       long libraryOrdinal = 0;
        bool done = false;
        uintptr_t result = 0;
        const uint8_t* p = &start[lazyBindingInfoOffset];
@@ -1231,9 +1241,9 @@ uintptr_t ImageLoaderMachOCompressed::doBindFastLazySymbol(uint32_t lazyBindingI
                                type = immediate;
                                break;
                        case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
-                               if ( immediate > fSegmentsCount )
-                                       dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (%d)\n", 
-                                                       immediate, fSegmentsCount);
+                               if ( immediate >= fSegmentsCount )
+                                       dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (0..%d)", 
+                                                       immediate, fSegmentsCount-1);
                                address = segActualLoadAddress(immediate) + read_uleb128(p, end);
                                break;
                        case BIND_OPCODE_DO_BIND:
@@ -1289,8 +1299,8 @@ bool ImageLoaderMachOCompressed::incrementCoalIterator(CoalIterator& it)
        const uint8_t* start = fLinkEditBase + fDyldInfo->weak_bind_off;
        const uint8_t* p = start + it.curIndex;
        const uint8_t* end = fLinkEditBase + fDyldInfo->weak_bind_off + this->fDyldInfo->weak_bind_size;
-       uint32_t count;
-       uint32_t skip;
+       uintptr_t count;
+       uintptr_t skip;
        while ( p < end ) {
                uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
                uint8_t opcode = *p & BIND_OPCODE_MASK;
@@ -1317,9 +1327,9 @@ bool ImageLoaderMachOCompressed::incrementCoalIterator(CoalIterator& it)
                                it.addend = read_sleb128(p, end);
                                break;
                        case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
-                               if ( immediate > fSegmentsCount )
-                                       dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (%d)\n", 
-                                                       immediate, fSegmentsCount);
+                               if ( immediate >= fSegmentsCount )
+                                       dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (0..%d)",
+                                                       immediate, fSegmentsCount-1);
                                it.address = segActualLoadAddress(immediate) + read_uleb128(p, end);
                                break;
                        case BIND_OPCODE_ADD_ADDR_ULEB:
@@ -1379,8 +1389,8 @@ void ImageLoaderMachOCompressed::updateUsesCoalIterator(CoalIterator& it, uintpt
        uintptr_t address = it.address;
        const char* symbolName = it.symbolName;
        intptr_t addend = it.addend;
-       uint32_t count;
-       uint32_t skip;
+       uintptr_t count;
+       uintptr_t skip;
        bool done = false;
        bool boundSomething = false;
        while ( !done && (p < end) ) {
@@ -1401,9 +1411,9 @@ void ImageLoaderMachOCompressed::updateUsesCoalIterator(CoalIterator& it, uintpt
                                addend = read_sleb128(p, end);
                                break;
                        case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
-                               if ( immediate > fSegmentsCount )
-                                       dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (%d)\n", 
-                                                       immediate, fSegmentsCount);
+                               if ( immediate >= fSegmentsCount )
+                                       dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (0..%d)",
+                                                       immediate, fSegmentsCount-1);
                                address = segActualLoadAddress(immediate) + read_uleb128(p, end);
                                break;
                        case BIND_OPCODE_ADD_ADDR_ULEB:
@@ -1443,21 +1453,14 @@ void ImageLoaderMachOCompressed::updateUsesCoalIterator(CoalIterator& it, uintpt
 }
 
 uintptr_t ImageLoaderMachOCompressed::interposeAt(const LinkContext& context, uintptr_t addr, uint8_t type, const char*, 
-                                                                                               uint8_t, intptr_t, int, const char*, LastLookup*, bool runResolver)
+                                                                                               uint8_t, intptr_t, long, const char*, LastLookup*, bool runResolver)
 {
        if ( type == BIND_TYPE_POINTER ) {
                uintptr_t* fixupLocation = (uintptr_t*)addr;
-               uintptr_t value = *fixupLocation;
-               for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
-                       // replace all references to 'replacee' with 'replacement'
-                       if ( (value == it->replacee) && (this != it->replacementImage) ) {
-                               if ( context.verboseInterposing ) {
-                                       dyld::log("dyld: interposing: at %p replace 0x%lX with 0x%lX in %s\n", 
-                                               fixupLocation, it->replacee, it->replacement, this->getPath());
-                               }
-                               *fixupLocation = it->replacement;
-                       }
-               }
+               uintptr_t curValue = *fixupLocation;
+               uintptr_t newValue = interposedAddress(context, curValue, this);
+               if ( newValue != curValue)
+                       *fixupLocation = newValue;
        }
        return 0;
 }
@@ -1473,6 +1476,37 @@ void ImageLoaderMachOCompressed::doInterpose(const LinkContext& context)
 }
 
 
+uintptr_t ImageLoaderMachOCompressed::dynamicInterposeAt(const LinkContext& context, uintptr_t addr, uint8_t type, const char* symbolName, 
+                                                                                               uint8_t, intptr_t, long, const char*, LastLookup*, bool runResolver)
+{
+       if ( type == BIND_TYPE_POINTER ) {
+               uintptr_t* fixupLocation = (uintptr_t*)addr;
+               uintptr_t value = *fixupLocation;
+               // don't apply interposing to table entries.
+               if ( (context.dynamicInterposeArray <= (void*)addr) && ((void*)addr < &context.dynamicInterposeArray[context.dynamicInterposeCount]) )
+                       return 0;
+               for(size_t i=0; i < context.dynamicInterposeCount; ++i) {
+                       if ( value == (uintptr_t)context.dynamicInterposeArray[i].replacee ) {
+                               if ( context.verboseInterposing ) {
+                                       dyld::log("dyld: dynamic interposing: at %p replace %p with %p in %s\n", 
+                                               fixupLocation, context.dynamicInterposeArray[i].replacee, context.dynamicInterposeArray[i].replacement, this->getPath());
+                               }
+                               *fixupLocation = (uintptr_t)context.dynamicInterposeArray[i].replacement;
+                       }
+               }
+       }
+       return 0;
+}
+
+void ImageLoaderMachOCompressed::dynamicInterpose(const LinkContext& context)
+{
+       if ( context.verboseInterposing )
+               dyld::log("dyld: dynamic interposing %lu tuples onto image: %s\n", context.dynamicInterposeCount, this->getPath());
+
+       // update already bound references to symbols
+       eachBind(context, &ImageLoaderMachOCompressed::dynamicInterposeAt);
+       eachLazyBind(context, &ImageLoaderMachOCompressed::dynamicInterposeAt);
+}
 
 
 const char* ImageLoaderMachOCompressed::findClosestSymbol(const void* addr, const void** closestAddr) const
index 6d8c5b773908723b939b17ce3b4323e8d29f95c7..1a43900d574a7050a28c922ef654f7b913c9d7ed 100644 (file)
@@ -68,6 +68,7 @@ public:
        
 protected:
        virtual void                                            doInterpose(const LinkContext& context);
+       virtual void                                            dynamicInterpose(const LinkContext& context);
        virtual void                                            setDyldInfo(const dyld_info_command* dyldInfo) { fDyldInfo = dyldInfo; }
        virtual void                                            setSymbolTableInfo(const macho_nlist*, const char*, const dysymtab_command*) {}
        virtual bool                                            isSubframeworkOf(const LinkContext& context, const ImageLoader* image) const { return false; }
@@ -90,11 +91,11 @@ protected:
 
                
 private:
-       struct LastLookup { int ordinal; uint8_t flags; const char* name; uintptr_t result; const ImageLoader* foundIn; };
+       struct LastLookup { long ordinal; uint8_t flags; const char* name; uintptr_t result; const ImageLoader* foundIn; };
 
 
        typedef uintptr_t (ImageLoaderMachOCompressed::*bind_handler)(const LinkContext& context, uintptr_t addr, uint8_t type, 
-                                                                                       const char* symbolName, uint8_t symboFlags, intptr_t addend, int libraryOrdinal, 
+                                                                                       const char* symbolName, uint8_t symboFlags, intptr_t addend, long libraryOrdinal, 
                                                                                        const char* msg, LastLookup* last, bool runResolver);
 
        void                                                            eachLazyBind(const LinkContext& context, bind_handler);
@@ -113,13 +114,13 @@ private:
        void                                                            throwBadRebaseAddress(uintptr_t address, uintptr_t segmentEndAddress, int segmentIndex, 
                                                                                                const uint8_t* startOpcodes, const uint8_t* endOpcodes, const uint8_t* pos);
        uintptr_t                                                       bindAt(const LinkContext& context, uintptr_t addr, uint8_t type, const char* symbolName, 
-                                                                                               uint8_t symboFlags, intptr_t addend, int libraryOrdinal, const char* msg,
+                                                                                               uint8_t symboFlags, intptr_t addend, long libraryOrdinal, const char* msg,
                                                                                                LastLookup* last, bool runResolver=false);
        void                                                            bindCompressed(const LinkContext& context);
        void                                                            throwBadBindingAddress(uintptr_t address, uintptr_t segmentEndAddress, int segmentIndex, 
                                                                                                const uint8_t* startOpcodes, const uint8_t* endOpcodes, const uint8_t* pos);
        uintptr_t                                                       resolve(const LinkContext& context, const char* symbolName, 
-                                                                                               uint8_t symboFlags, int libraryOrdinal, const ImageLoader** targetImage, 
+                                                                                               uint8_t symboFlags, long libraryOrdinal, const ImageLoader** targetImage, 
                                                                                                LastLookup* last = NULL, bool runResolver=false);
        uintptr_t                                                       resolveFlat(const LinkContext& context, const char* symbolName, bool weak_import, bool runResolver,
                                                                                                        const ImageLoader** foundIn);
@@ -127,7 +128,9 @@ private:
        uintptr_t                                                       resolveTwolevel(const LinkContext& context, const ImageLoader* targetImage, bool weak_import, 
                                                                                                                const char* symbolName, bool runResolver, const ImageLoader** foundIn);
        uintptr_t                                                       interposeAt(const LinkContext& context, uintptr_t addr, uint8_t type, const char*, 
-                                                                                               uint8_t, intptr_t, int, const char*, LastLookup*, bool runResolver);
+                                                                                               uint8_t, intptr_t, long, const char*, LastLookup*, bool runResolver);
+       uintptr_t                                                       dynamicInterposeAt(const LinkContext& context, uintptr_t addr, uint8_t type, const char*, 
+                                                                                               uint8_t, intptr_t, long, const char*, LastLookup*, bool runResolver);
        static const uint8_t*                           trieWalk(const uint8_t* start, const uint8_t* end, const  char* s);
     void                                updateOptimizedLazyPointers(const LinkContext& context);
     void                                updateAlternateLazyPointer(uint8_t* stub, void** originalLazyPointerAddr, const LinkContext& context);
index d143bc9238e869fee7f48a55089d3c4e84e045f6..23e482fea7132ed0d0f130cb06679409268f6c82 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2013 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -51,6 +51,7 @@
 #include <Availability.h>
 #include <System/sys/codesign.h>
 #include <_simple.h>
+#include <os/lock_private.h>
 
 
 #ifndef CPU_SUBTYPE_ARM_V5TEJ
        #define LC_DYLD_ENVIRONMENT                     0x27
 #endif
 
+#ifndef CPU_SUBTYPE_X86_64_H
+       #define CPU_SUBTYPE_X86_64_H            ((cpu_subtype_t) 8) 
+#endif 
+
 #ifndef VM_PROT_SLIDE   
     #define VM_PROT_SLIDE 0x20
 #endif
 #if DYLD_SHARED_CACHE_SUPPORT
 #include "dyld_cache_format.h"
 #endif
-#if CORESYMBOLICATION_SUPPORT
-#include "coreSymbolicationDyldSupport.hpp"
+#if TARGET_IPHONE_SIMULATOR
+  void coresymbolication_load_image(void*, const ImageLoader*, uint64_t);
+  void coresymbolication_unload_image(void*, const ImageLoader*);
+#else
+  #include "coreSymbolicationDyldSupport.hpp"
 #endif
 
 // not libc header for send() syscall interface
 extern "C" ssize_t __sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
 
 
-// ARM is the only architecture that use cpu-sub-types
-#define CPU_SUBTYPES_SUPPORTED  __arm__
+// ARM and x86_64 are the only architecture that use cpu-sub-types
+#define CPU_SUBTYPES_SUPPORTED  ((__arm__ || __x86_64__) && !TARGET_IPHONE_SIMULATOR)
 
 
 
@@ -123,7 +131,7 @@ extern "C" {
 extern "C" void dyld_fatal_error(const char* errString) __attribute__((noreturn));
 
 // magic linker symbol for start of dyld binary
-extern "C" void* __dso_handle;
+extern "C" const macho_header __dso_handle;
 
 
 //
@@ -212,13 +220,14 @@ static cpu_subtype_t                              sHostCPUsubtype;
 static ImageLoader*                                    sMainExecutable = NULL;
 static bool                                                    sProcessIsRestricted = false;
 static RestrictedReason                                sRestrictedReason = restrictedNot;
-static unsigned int                                    sInsertedDylibCount = 0;
+static size_t                                          sInsertedDylibCount = 0;
 static std::vector<ImageLoader*>       sAllImages;
 static std::vector<ImageLoader*>       sImageRoots;
 static std::vector<ImageLoader*>       sImageFilesNeedingTermination;
 static std::vector<RegisteredDOF>      sImageFilesNeedingDOFUnregistration;
 static std::vector<ImageCallback>   sAddImageCallbacks;
 static std::vector<ImageCallback>   sRemoveImageCallbacks;
+static bool                                                    sRemoveImageCallbacksInUse = false;
 static void*                                           sSingleHandlers[7][3];
 static void*                                           sBatchHandlers[7][3];
 static ImageLoader*                                    sLastImageByAddressCache;
@@ -231,10 +240,11 @@ static ImageLoader*                                       sBundleBeingLoaded = NULL;      // hack until OFI is reworked
 static const dyld_cache_header*                sSharedCache = NULL;
 static long                                                    sSharedCacheSlide = 0;
 static bool                                                    sSharedCacheIgnoreInodeAndTimeStamp = false;
-#if __IPHONE_OS_VERSION_MIN_REQUIRED && DYLD_SHARED_CACHE_SUPPORT
-       bool                                                    gSharedCacheOverridden = false;
+          bool                                                 gSharedCacheOverridden = false;
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
        static const char*                              sSharedCacheDir = IPHONE_DYLD_SHARED_CACHE_DIR;
        static bool                                             sDylibsOverrideCache = false;
+       #define ENABLE_DYLIBS_TO_OVERRIDE_CACHE_SIZE 1024
 #else
        static const char*                              sSharedCacheDir = MACOSX_DYLD_SHARED_CACHE_DIR;
 #endif
@@ -250,9 +260,12 @@ static std::vector<DylibOverride>  sDylibOverrides;
 static int                                                     sLogSocket = -1;
 #endif
 static bool                                                    sFrameworksFoundAsDylibs = false;
+#if __x86_64__
+static bool                                                    sHaswell = false;
+#endif
 static std::vector<ImageLoader::DynamicReference> sDynamicReferences;
-       
+static bool                                                    sLogToFile = false;
+static char                                                    sLoadingCrashMessage[1024] = "dyld: launch, loading dependent libraries";
 
 //
 // The MappedRanges structure is used for fast address->image lookups.
@@ -368,7 +381,6 @@ void throwf(const char* format, ...)
 }
 
 
-//#define ALTERNATIVE_LOGFILE "/dev/console"
 #if !TARGET_IPHONE_SIMULATOR
 static int sLogfile = STDERR_FILENO;
 #endif
@@ -456,10 +468,11 @@ static void socket_syslogv(int priority, const char* format, va_list list)
 
 void vlog(const char* format, va_list list)
 {
-       if ( useSyslog() ) 
+       if ( !sLogToFile && useSyslog() ) 
                socket_syslogv(LOG_ERR, format, list);
-       else
+       else {
                _simple_vdprintf(sLogfile, format, list);
+       }
 }
 
 void log(const char* format, ...)
@@ -491,22 +504,32 @@ void warn(const char* format, ...)
 
 // <rdar://problem/8867781> control access to sAllImages through a lock 
 // because global dyld lock is not held during initialization phase of dlopen()
-static long sAllImagesLock = 0;
+// <rdar://problem/16145518> Use OSSpinLockLock to allow yielding
+static OSSpinLock sAllImagesLock = 0;
 
 static void allImagesLock()
 {
     //dyld::log("allImagesLock()\n");
+#if TARGET_IPHONE_SIMULATOR    
+       // <rdar://problem/16154256> can't use OSSpinLockLock in simulator until thread_switch is provided by host dyld
        while ( ! OSAtomicCompareAndSwapPtrBarrier((void*)0, (void*)1, (void**)&sAllImagesLock) ) {
         // spin
     }
+#else
+       OSSpinLockLock(&sAllImagesLock);
+#endif
 }
 
 static void allImagesUnlock()
 {
     //dyld::log("allImagesUnlock()\n");
+#if TARGET_IPHONE_SIMULATOR    
        while ( ! OSAtomicCompareAndSwapPtrBarrier((void*)1, (void*)0, (void**)&sAllImagesLock) ) {
-        // spin
-   }
+               // spin
+       }
+#else
+       OSSpinLockUnlock(&sAllImagesLock);
+#endif
 }
 
 
@@ -537,7 +560,7 @@ FileOpener::~FileOpener()
 
 static void    registerDOFs(const std::vector<ImageLoader::DOFInfo>& dofs)
 {
-       const unsigned int dofSectionCount = dofs.size();
+       const size_t dofSectionCount = dofs.size();
        if ( !sEnv.DYLD_DISABLE_DOFS && (dofSectionCount != 0) ) {
                int fd = open("/dev/" DTRACEMNR_HELPER, O_RDWR);
                if ( fd < 0 ) {
@@ -573,7 +596,7 @@ static void registerDOFs(const std::vector<ImageLoader::DOFInfo>& dofs)
                                }
                        }
                        else {
-                               dyld::log( "dyld: ioctl to register dtrace DOF section failed\n");
+                               //dyld::log( "dyld: ioctl to register dtrace DOF section failed\n");
                        }
                        close(fd);
                }
@@ -676,20 +699,23 @@ static void notifySingle(dyld_image_states state, const ImageLoader* image)
                        }
                }
        }
-#if CORESYMBOLICATION_SUPPORT
     // mach message csdlc about dynamically loaded images 
        if ( image->addFuncNotified() && (state == dyld_image_state_terminated) ) {
                if ( sEnv.DYLD_PRINT_CS_NOTIFICATIONS ) {
                        dyld::log("dyld core symbolication unload notification: %p %s\n", image->machHeader(), image->getPath());
                }
                if ( dyld::gProcessInfo->coreSymbolicationShmPage != NULL) {
+#if TARGET_IPHONE_SIMULATOR
+                       void* connection = dyld::gProcessInfo->coreSymbolicationShmPage;
+                       if ( *((uint32_t*)connection) == 2 ) {
+#else
                        CSCppDyldSharedMemoryPage* connection = (CSCppDyldSharedMemoryPage*)dyld::gProcessInfo->coreSymbolicationShmPage;
                        if ( connection->is_valid_version() ) {
+#endif
                                coresymbolication_unload_image(connection, image);
                        }
                }
        }
-#endif
 }
 
 
@@ -759,7 +785,7 @@ static void notifyBatchPartial(dyld_image_states state, bool orLater, dyld_image
                                *end++ = sBundleBeingLoaded;
                }
         const char* dontLoadReason = NULL;
-               unsigned int count = end-images;
+               uint32_t count = (uint32_t)(end-images);
                if ( end != images ) {
                        // sort bottom up
                        qsort(images, count, sizeof(ImageLoader*), &imageSorter);
@@ -802,7 +828,6 @@ static void notifyBatchPartial(dyld_image_states state, bool orLater, dyld_image
         if ( dontLoadReason != NULL )
             throw dontLoadReason;
        }
-#if CORESYMBOLICATION_SUPPORT
        if ( state == dyld_image_state_rebased ) {
                if ( sEnv.DYLD_PRINT_CS_NOTIFICATIONS ) {
                        for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
@@ -812,8 +837,13 @@ static void notifyBatchPartial(dyld_image_states state, bool orLater, dyld_image
                        }
                }
                if ( dyld::gProcessInfo->coreSymbolicationShmPage != NULL) {
+#if TARGET_IPHONE_SIMULATOR
+                       void* connection = dyld::gProcessInfo->coreSymbolicationShmPage;
+                       if ( *((uint32_t*)connection) == 2 ) {
+#else
                        CSCppDyldSharedMemoryPage* connection = (CSCppDyldSharedMemoryPage*)dyld::gProcessInfo->coreSymbolicationShmPage;
                        if ( connection->is_valid_version() ) {
+#endif
                                // This needs to be captured now
                                uint64_t load_timestamp = mach_absolute_time();
                                for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
@@ -824,7 +854,6 @@ static void notifyBatchPartial(dyld_image_states state, bool orLater, dyld_image
                        }
                }
        }
-#endif
 }
 
 
@@ -861,7 +890,7 @@ static void printAllDepths()
 
 static unsigned int imageCount()
 {
-       return sAllImages.size();
+       return (unsigned int)sAllImages.size();
 }
 
 
@@ -906,7 +935,7 @@ static void addDynamicReference(ImageLoader* from, ImageLoader* to) {
        t.to = to;
        sDynamicReferences.push_back(t);
 }
-       
+
 static void addImage(ImageLoader* image)
 {
        // add to master list
@@ -976,9 +1005,11 @@ void removeImage(ImageLoader* image)
        // tell all registered remove image handlers about this
        // do this before removing image from internal data structures so that the callback can query dyld about the image
        if ( image->getState() >= dyld_image_state_bound ) {
+               sRemoveImageCallbacksInUse = true; // This only runs inside dyld's global lock, so ok to use a global for the in-use flag.
                for (std::vector<ImageCallback>::iterator it=sRemoveImageCallbacks.begin(); it != sRemoveImageCallbacks.end(); it++) {
                        (*it)(image->machHeader(), image->getSlide());
                }
+               sRemoveImageCallbacksInUse = false;
        }
        
        // notify 
@@ -1022,7 +1053,7 @@ void removeImage(ImageLoader* image)
 }
 
 
-void runImageTerminators(ImageLoader* image)
+void runImageStaticTerminators(ImageLoader* image)
 {
        // if in termination list, pull it out and run terminator
        bool mightBeMore;
@@ -1031,17 +1062,13 @@ void runImageTerminators(ImageLoader* image)
                for (std::vector<ImageLoader*>::iterator it=sImageFilesNeedingTermination.begin(); it != sImageFilesNeedingTermination.end(); it++) {
                        if ( *it == image ) {
                                sImageFilesNeedingTermination.erase(it);
+                               if (gLogAPIs) dyld::log("dlclose(), running static terminators for %p %s\n", image, image->getShortName());
                                image->doTermination(gLinkContext);
                                mightBeMore = true;
                                break;
                        }
                }
        } while ( mightBeMore );
-
-       // <rdar://problem/7740779> dyld should directly call __cxa_finalize()
-       if ( (gLibSystemHelpers != NULL) && (gLibSystemHelpers->version >= 8) )
-               (*gLibSystemHelpers->cxa_finalize)(image->machHeader());
-       
 }
 
 static void terminationRecorder(ImageLoader* image)
@@ -1054,6 +1081,21 @@ const char* getExecutablePath()
        return sExecPath;
 }
 
+static void runAllStaticTerminators(void* extra)
+{
+       try {
+               const size_t imageCount = sImageFilesNeedingTermination.size();
+               for(size_t i=imageCount; i > 0; --i){
+                       ImageLoader* image = sImageFilesNeedingTermination[i-1];
+                       image->doTermination(gLinkContext);
+               }
+               sImageFilesNeedingTermination.clear();
+               notifyBatch(dyld_image_state_terminated);
+       }
+       catch (const char* msg) {
+               halt(msg);
+       }
+}
 
 void initializeMainExecutable()
 {
@@ -1062,25 +1104,24 @@ void initializeMainExecutable()
 
        // run initialzers for any inserted dylibs
        ImageLoader::InitializerTimingList initializerTimes[sAllImages.size()];
-       const int rootCount = sImageRoots.size();
+       initializerTimes[0].count = 0;
+       const size_t rootCount = sImageRoots.size();
        if ( rootCount > 1 ) {
-               for(int i=1; i < rootCount; ++i) {
-                       initializerTimes[0].count = 0;
+               for(size_t i=1; i < rootCount; ++i) {
                        sImageRoots[i]->runInitializers(gLinkContext, initializerTimes[0]);
                }
        }
        
        // run initializers for main executable and everything it brings up 
-       initializerTimes[0].count = 0;
        sMainExecutable->runInitializers(gLinkContext, initializerTimes[0]);
        
-       // register atexit() handler to run terminators in all loaded images when this process exits
+       // register cxa_atexit() handler to run static terminators in all loaded images when this process exits
        if ( gLibSystemHelpers != NULL ) 
-               (*gLibSystemHelpers->cxa_atexit)(&runTerminators, NULL, NULL);
+               (*gLibSystemHelpers->cxa_atexit)(&runAllStaticTerminators, NULL, NULL);
 
        // dump info if requested
        if ( sEnv.DYLD_PRINT_STATISTICS )
-               ImageLoaderMachO::printStatistics(sAllImages.size(), initializerTimes[0]);
+               ImageLoaderMachO::printStatistics((unsigned int)sAllImages.size(), initializerTimes[0]);
 }
 
 bool mainExecutablePrebound()
@@ -1094,21 +1135,6 @@ ImageLoader* mainExecutable()
 }
 
 
-void runTerminators(void* extra)
-{
-       try {
-               const unsigned int imageCount = sImageFilesNeedingTermination.size();
-               for(unsigned int i=imageCount; i > 0; --i){
-                       ImageLoader* image = sImageFilesNeedingTermination[i-1];
-                       image->doTermination(gLinkContext);
-               }
-               sImageFilesNeedingTermination.clear();
-               notifyBatch(dyld_image_state_terminated);
-       }
-       catch (const char* msg) {
-               halt(msg);
-       }
-}
 
 
 #if SUPPORT_VERSIONED_PATHS
@@ -1256,9 +1282,9 @@ static const char** parseColonList(const char* list, const char* mainExecutableD
        char** result = new char*[colonCount+2];
        for(const char* s=list; *s != '\0'; ++s) {
                if (*s == ':') {
-                       int len = s-start;
+                       size_t len = s-start;
                        if ( (mainExecutableDir != NULL) && (strncmp(start, "@loader_path/", 13) == 0) ) {
-                               int mainExecDirLen = strlen(mainExecutableDir);
+                               size_t mainExecDirLen = strlen(mainExecutableDir);
                                char* str = new char[mainExecDirLen+len+1];
                                strcpy(str, mainExecutableDir);
                                strlcat(str, &start[13], mainExecDirLen+len+1);
@@ -1267,7 +1293,7 @@ static const char** parseColonList(const char* list, const char* mainExecutableD
                                result[index++] = str;
                        }
                        else if ( (mainExecutableDir != NULL) && (strncmp(start, "@executable_path/", 17) == 0) ) {
-                               int mainExecDirLen = strlen(mainExecutableDir);
+                               size_t mainExecDirLen = strlen(mainExecutableDir);
                                char* str = new char[mainExecDirLen+len+1];
                                strcpy(str, mainExecutableDir);
                                strlcat(str, &start[17], mainExecDirLen+len+1);
@@ -1284,9 +1310,9 @@ static const char** parseColonList(const char* list, const char* mainExecutableD
                        }
                }
        }
-       int len = strlen(start);
+       size_t len = strlen(start);
        if ( (mainExecutableDir != NULL) && (strncmp(start, "@loader_path/", 13) == 0) ) {
-               int mainExecDirLen = strlen(mainExecutableDir);
+               size_t mainExecDirLen = strlen(mainExecutableDir);
                char* str = new char[mainExecDirLen+len+1];
                strcpy(str, mainExecutableDir);
                strlcat(str, &start[13], mainExecDirLen+len+1);
@@ -1294,7 +1320,7 @@ static const char** parseColonList(const char* list, const char* mainExecutableD
                result[index++] = str;
        }
        else if ( (mainExecutableDir != NULL) && (strncmp(start, "@executable_path/", 17) == 0) ) {
-               int mainExecDirLen = strlen(mainExecutableDir);
+               size_t mainExecDirLen = strlen(mainExecutableDir);
                char* str = new char[mainExecDirLen+len+1];
                strcpy(str, mainExecutableDir);
                strlcat(str, &start[17], mainExecDirLen+len+1);
@@ -1559,6 +1585,9 @@ void processDyldEnvironmentVariable(const char* key, const char* value, const ch
                appendParsedColonList(value, mainExecutableDir, &sEnv.DYLD_VERSIONED_FRAMEWORK_PATH);
        }
 #endif
+       else if ( strcmp(key, "DYLD_PRINT_TO_FILE") == 0 ) {
+               // handled in _main()
+       }
        else {
                dyld::warn("unknown environment variable: %s\n", key);
        }
@@ -1578,7 +1607,7 @@ static void checkLoadCommandEnvironmentVariables()
                        {
                                const struct dylinker_command* envcmd = (struct dylinker_command*)cmd;
                                const char* keyEqualsValue = (char*)envcmd + envcmd->name.offset;
-                               char mainExecutableDir[strlen(sExecPath)];
+                               char mainExecutableDir[strlen(sExecPath)+2];
                                strcpy(mainExecutableDir, sExecPath);
                                char* lastSlash = strrchr(mainExecutableDir, '/');
                                if ( lastSlash != NULL)
@@ -1589,7 +1618,7 @@ static void checkLoadCommandEnvironmentVariables()
                                        if ( equals != NULL ) {
                                                if ( strncmp(&equals[-5], "_PATH", 5) == 0 ) {
                                                        const char* value = &equals[1];
-                                                       const int keyLen = equals-keyEqualsValue;
+                                                       const size_t keyLen = equals-keyEqualsValue;
                                                        char key[keyLen+1];
                                                        strncpy(key, keyEqualsValue, keyLen);
                                                        key[keyLen] = '\0';
@@ -1693,6 +1722,9 @@ static void pruneEnvironmentVariables(const char* envp[], const char*** applep)
        // disable framework and library fallback paths for setuid binaries rdar://problem/4589305
        sEnv.DYLD_FALLBACK_FRAMEWORK_PATH = NULL;
        sEnv.DYLD_FALLBACK_LIBRARY_PATH = NULL;
+
+       if ( removedCount > 0 )
+               strlcat(sLoadingCrashMessage, ", ignoring DYLD_* env vars", sizeof(sLoadingCrashMessage));
 }
 
 
@@ -1705,8 +1737,10 @@ static void checkEnvironmentVariables(const char* envp[], bool ignoreEnviron)
            if ( strncmp(keyEqualsValue, "DYLD_", 5) == 0 ) {
                        const char* equals = strchr(keyEqualsValue, '=');
                        if ( (equals != NULL) && !ignoreEnviron ) {
+                               strlcat(sLoadingCrashMessage, "\n", sizeof(sLoadingCrashMessage));
+                               strlcat(sLoadingCrashMessage, keyEqualsValue, sizeof(sLoadingCrashMessage));
                                const char* value = &equals[1];
-                               const int keyLen = equals-keyEqualsValue;
+                               const size_t keyLen = equals-keyEqualsValue;
                                char key[keyLen+1];
                                strncpy(key, keyEqualsValue, keyLen);
                                key[keyLen] = '\0';
@@ -1761,7 +1795,10 @@ static void checkEnvironmentVariables(const char* envp[], bool ignoreEnviron)
 static void getHostInfo()
 {
 #if CPU_SUBTYPES_SUPPORTED
-#if __ARM_ARCH_7A__
+#if __ARM_ARCH_7K__
+       sHostCPU                = CPU_TYPE_ARM;
+       sHostCPUsubtype = CPU_SUBTYPE_ARM_V7K;
+#elif __ARM_ARCH_7A__
        sHostCPU                = CPU_TYPE_ARM;
        sHostCPUsubtype = CPU_SUBTYPE_ARM_V7;
 #elif __ARM_ARCH_6K__
@@ -1773,9 +1810,6 @@ static void getHostInfo()
 #elif __ARM_ARCH_7S__
        sHostCPU                = CPU_TYPE_ARM;
        sHostCPUsubtype = CPU_SUBTYPE_ARM_V7S;
-#elif __ARM_ARCH_7K__
-       sHostCPU                = CPU_TYPE_ARM;
-       sHostCPUsubtype = CPU_SUBTYPE_ARM_V7K;
 #else
        struct host_basic_info info;
        mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
@@ -1785,6 +1819,7 @@ static void getHostInfo()
                throw "host_info() failed";
        sHostCPU                = info.cpu_type;
        sHostCPUsubtype = info.cpu_subtype;
+       mach_port_deallocate(mach_task_self(), hostPort);
 #endif
 #endif
 }
@@ -1799,14 +1834,20 @@ static void checkSharedRegionDisable()
                if ( gLinkContext.verboseMapping )
                        dyld::warn("disabling shared region because main executable overlaps\n");
        }
+#if __i386__
+       if ( sProcessIsRestricted ) {
+               // <rdar://problem/15280847> use private or no shared region for suid processes
+               gLinkContext.sharedRegionMode = ImageLoader::kUsePrivateSharedRegion;
+       }
+#endif
 #endif
        // iPhoneOS cannot run without shared region
 }
 
 bool validImage(const ImageLoader* possibleImage)
 {
-    const unsigned int imageCount = sAllImages.size();
-    for(unsigned int i=0; i < imageCount; ++i) {
+    const size_t imageCount = sAllImages.size();
+    for(size_t i=0; i < imageCount; ++i) {
         if ( possibleImage == sAllImages[i] ) {
             return true;
         }
@@ -1816,7 +1857,7 @@ bool validImage(const ImageLoader* possibleImage)
 
 uint32_t getImageCount()
 {
-       return sAllImages.size();
+       return (uint32_t)sAllImages.size();
 }
 
 ImageLoader* getIndexedImage(unsigned int index)
@@ -1852,8 +1893,8 @@ ImageLoader* findImageContainingSymbol(const void* symbol)
 
 void forEachImageDo( void (*callback)(ImageLoader*, void* userData), void* userData)
 {
-       const unsigned int imageCount = sAllImages.size();
-       for(unsigned int i=0; i < imageCount; ++i) {
+       const size_t imageCount = sAllImages.size();
+       for(size_t i=0; i < imageCount; ++i) {
                ImageLoader* anImage = sAllImages[i];
                (*callback)(anImage, userData);
        }
@@ -1861,8 +1902,8 @@ void forEachImageDo( void (*callback)(ImageLoader*, void* userData), void* userD
 
 ImageLoader* findLoadedImage(const struct stat& stat_buf)
 {
-       const unsigned int imageCount = sAllImages.size();
-       for(unsigned int i=0; i < imageCount; ++i){
+       const size_t imageCount = sAllImages.size();
+       for(size_t i=0; i < imageCount; ++i){
                ImageLoader* anImage = sAllImages[i];
                if ( anImage->statMatch(stat_buf) )
                        return anImage;
@@ -1873,7 +1914,7 @@ ImageLoader* findLoadedImage(const struct stat& stat_buf)
 // based on ANSI-C strstr()
 static const char* strrstr(const char* str, const char* sub) 
 {
-       const int sublen = strlen(sub);
+       const size_t sublen = strlen(sub);
        for(const char* p = &str[strlen(str)]; p != str; --p) {
                if ( strncmp(p, sub, sublen) == 0 )
                        return p;
@@ -1903,7 +1944,7 @@ static const char* getFrameworkPartialPath(const char* path)
                                const char* frameworkStart = &dirStart[1];
                                if ( dirStart == path )
                                        --frameworkStart;
-                               int len = dirDot - frameworkStart;
+                               size_t len = dirDot - frameworkStart;
                                char framework[len+1];
                                strncpy(framework, frameworkStart, len);
                                framework[len] = '\0';
@@ -1966,11 +2007,11 @@ static const cpu_subtype_t kARM[kARM_RowCount][9] = {
        // armv7f can run: v7f, v7, v6, v5, and v4
        {  CPU_SUBTYPE_ARM_V7F, CPU_SUBTYPE_ARM_V7, CPU_SUBTYPE_ARM_V6, CPU_SUBTYPE_ARM_V5TEJ, CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, CPU_SUBTYPE_END_OF_LIST },
 
-       // armv7k can run: v7k, v6, v5, and v4
-       {  CPU_SUBTYPE_ARM_V7K, CPU_SUBTYPE_ARM_V6, CPU_SUBTYPE_ARM_V5TEJ, CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, CPU_SUBTYPE_END_OF_LIST },
+       // armv7k can run: v7k
+       {  CPU_SUBTYPE_ARM_V7K, CPU_SUBTYPE_END_OF_LIST },
 
        // armv7s can run: v7s, v7, v7f, v7k, v6, v5, and v4
-       {  CPU_SUBTYPE_ARM_V7S, CPU_SUBTYPE_ARM_V7, CPU_SUBTYPE_ARM_V7F, CPU_SUBTYPE_ARM_V7K, CPU_SUBTYPE_ARM_V6, CPU_SUBTYPE_ARM_V5TEJ, CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, CPU_SUBTYPE_END_OF_LIST },
+       {  CPU_SUBTYPE_ARM_V7S, CPU_SUBTYPE_ARM_V7, CPU_SUBTYPE_ARM_V7F, CPU_SUBTYPE_ARM_V6, CPU_SUBTYPE_ARM_V5TEJ, CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, CPU_SUBTYPE_END_OF_LIST },
 
        // armv7 can run: v7, v6, v5, and v4
        {  CPU_SUBTYPE_ARM_V7, CPU_SUBTYPE_ARM_V6, CPU_SUBTYPE_ARM_V5TEJ, CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, CPU_SUBTYPE_END_OF_LIST },
@@ -1989,6 +2030,22 @@ static const cpu_subtype_t kARM[kARM_RowCount][9] = {
 };
 #endif
 
+#if __x86_64__
+//      
+//     x86_64 sub-type lists
+//
+const int kX86_64_RowCount = 2;
+static const cpu_subtype_t kX86_64[kX86_64_RowCount][5] = {
+
+       // x86_64h can run: x86_64h, x86_64h(lib), x86_64(lib), and x86_64
+       { CPU_SUBTYPE_X86_64_H, CPU_SUBTYPE_LIB64|CPU_SUBTYPE_X86_64_H, CPU_SUBTYPE_LIB64|CPU_SUBTYPE_X86_64_ALL, CPU_SUBTYPE_X86_64_ALL,  CPU_SUBTYPE_END_OF_LIST },
+
+       // x86_64 can run: x86_64(lib) and x86_64
+       { CPU_SUBTYPE_X86_64_ALL, CPU_SUBTYPE_LIB64|CPU_SUBTYPE_X86_64_ALL, CPU_SUBTYPE_END_OF_LIST },
+
+};
+#endif
+
 
 // scan the tables above to find the cpu-sub-type-list for this machine
 static const cpu_subtype_t* findCPUSubtypeList(cpu_type_t cpu, cpu_subtype_t subtype)
@@ -2001,6 +2058,14 @@ static const cpu_subtype_t* findCPUSubtypeList(cpu_type_t cpu, cpu_subtype_t sub
                                        return kARM[i];
                        }
                        break;
+#endif
+#if __x86_64__
+               case CPU_TYPE_X86_64:
+                       for (int i=0; i < kX86_64_RowCount ; ++i) {
+                               if ( kX86_64[i][0] == subtype )
+                                       return kX86_64[i];
+                       }
+                       break;
 #endif
        }
        return NULL;
@@ -2056,6 +2121,15 @@ static bool fatFindRunsOnAllCPUs(cpu_type_t cpu, const fat_header* fh, uint64_t*
                                                return true;
                                        }
                                        break;
+#endif
+#if __x86_64__
+                               case CPU_TYPE_X86_64:
+                                       if ( (cpu_subtype_t)OSSwapBigToHostInt32(archs[i].cpusubtype) == CPU_SUBTYPE_X86_64_ALL ) {
+                                               *offset = OSSwapBigToHostInt32(archs[i].offset);
+                                               *len = OSSwapBigToHostInt32(archs[i].size);
+                                               return true;
+                                       }
+                                       break;
 #endif
                        }
                }
@@ -2179,7 +2253,7 @@ static ImageLoader* instantiateFromLoadedImage(const macho_header* mh, uintptr_t
 
 
 #if DYLD_SHARED_CACHE_SUPPORT
-static bool findInSharedCacheImage(const char* path, const struct stat* stat_buf, const macho_header** mh, const char** pathInCache, long* slide)
+static bool findInSharedCacheImage(const char* path, bool searchByPath, const struct stat* stat_buf, const macho_header** mh, const char** pathInCache, long* slide)
 {
        if ( sSharedCache != NULL ) {
 #if __MAC_OS_X_VERSION_MIN_REQUIRED    
@@ -2192,13 +2266,24 @@ static bool findInSharedCacheImage(const char* path, const struct stat* stat_buf
                        stat_buf = &statb;
                }
 #endif
+#if __IPHONE_OS_VERSION_MIN_REQUIRED   
+               uint64_t hash = 0;
+               for (const char* s=path; *s != '\0'; ++s)
+                       hash += hash*4 + *s;
+#endif
+
                // walk shared cache to see if there is a cached image that matches the inode/mtime/path desired
                const dyld_cache_image_info* const start = (dyld_cache_image_info*)((uint8_t*)sSharedCache + sSharedCache->imagesOffset);
                const dyld_cache_image_info* const end = &start[sSharedCache->imagesCount];
+#if __IPHONE_OS_VERSION_MIN_REQUIRED   
+               const bool cacheHasHashInfo = (start->modTime == 0);
+#endif
                for( const dyld_cache_image_info* p = start; p != end; ++p) {
 #if __IPHONE_OS_VERSION_MIN_REQUIRED   
                        // just check path
                        const char* aPath = (char*)sSharedCache + p->pathFileOffset;
+                       if ( cacheHasHashInfo && (p->inode != hash) )
+                               continue;
                        if ( strcmp(path, aPath) == 0 ) {
                                // found image in cache
                                *mh = (macho_header*)(p->address+sSharedCacheSlide);
@@ -2208,12 +2293,12 @@ static bool findInSharedCacheImage(const char* path, const struct stat* stat_buf
                        }
 #elif __MAC_OS_X_VERSION_MIN_REQUIRED
                        // check mtime and inode first because it is fast
-                       if ( sSharedCacheIgnoreInodeAndTimeStamp 
-                               || ( ((time_t)p->modTime == stat_buf->st_mtime) && ((ino_t)p->inode == stat_buf->st_ino) ) ) {
+                       bool inodeMatch = ( ((time_t)p->modTime == stat_buf->st_mtime) && ((ino_t)p->inode == stat_buf->st_ino) );
+                       if ( searchByPath || sSharedCacheIgnoreInodeAndTimeStamp || inodeMatch ) {
                                // mod-time and inode match an image in the shared cache, now check path
                                const char* aPath = (char*)sSharedCache + p->pathFileOffset;
                                bool cacheHit = (strcmp(path, aPath) == 0);
-                               if ( cacheHit ) {
+                               if ( inodeMatch && !cacheHit ) {
                                        // path does not match install name of dylib in cache, but inode and mtime does match
                                        // perhaps path is a symlink to the cached dylib
                                        struct stat pathInCacheStatBuf;
@@ -2241,7 +2326,7 @@ bool inSharedCache(const char* path)
        const macho_header* mhInCache;
        const char*                     pathInCache;
        long                            slide;
-       return findInSharedCacheImage(path, NULL, &mhInCache, &pathInCache, &slide);
+       return findInSharedCacheImage(path, true, NULL, &mhInCache, &pathInCache, &slide);
 }
 
 #endif
@@ -2284,6 +2369,32 @@ static ImageLoader* checkandAddImage(ImageLoader* image, const LoadContext& cont
        return image;
 }
 
+#if TARGET_IPHONE_SIMULATOR    
+static bool isSimulatorBinary(const uint8_t* firstPage, const char* path)
+{
+       const macho_header* mh = (macho_header*)firstPage;
+       const uint32_t cmd_count = mh->ncmds;
+       const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header));
+       const struct load_command* const cmdsReadEnd = (struct load_command*)(((char*)mh)+4096);
+       const struct load_command* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               switch (cmd->cmd) {
+                       case LC_VERSION_MIN_IPHONEOS:
+                               return true;
+                       case LC_VERSION_MIN_MACOSX:
+                               // grandfather in a few libSystem dylibs
+                               if ( strncmp(path, "/usr/lib/system/libsystem_", 26) == 0 )
+                                       return true;
+                               return false;
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+               if ( cmd > cmdsReadEnd )
+                       return true;
+       }
+       return false;
+}
+#endif
+
 // map in file and instantiate an ImageLoader
 static ImageLoader* loadPhase6(int fd, const struct stat& stat_buf, const char* path, const LoadContext& context)
 {
@@ -2338,6 +2449,13 @@ static ImageLoader* loadPhase6(int fd, const struct stat& stat_buf, const char*
                                throw "mach-o, but wrong filetype";
                }
                
+#if TARGET_IPHONE_SIMULATOR    
+               // <rdar://problem/14168872> dyld_sim should restrict loading osx binaries
+               if ( !isSimulatorBinary(firstPage, path) ) {
+                       throw "mach-o, but not built for iOS simulator";
+               }
+#endif
+
                // instantiate an image
                ImageLoader* image = ImageLoaderMachO::instantiateFromFile(path, fd, firstPage, fileOffset, fileLength, stat_buf, gLinkContext);
                
@@ -2421,7 +2539,7 @@ static ImageLoader* loadPhase5load(const char* path, const char* orgPath, const
        const macho_header* mhInCache;
        const char*                     pathInCache;
        long                            slideInCache;
-       if ( findInSharedCacheImage(path, &stat_buf, &mhInCache, &pathInCache, &slideInCache) ) {
+       if ( findInSharedCacheImage(path, false, &stat_buf, &mhInCache, &pathInCache, &slideInCache) ) {
                image = ImageLoaderMachO::instantiateFromCache(mhInCache, pathInCache, slideInCache, stat_buf, gLinkContext);
                return checkandAddImage(image, context);
        }
@@ -2483,7 +2601,7 @@ static ImageLoader* loadPhase5load(const char* path, const char* orgPath, const
        const macho_header* mhInCache;
        const char*                     pathInCache;
        long                            slideInCache;
-       if ( findInSharedCacheImage(path, NULL, &mhInCache, &pathInCache, &slideInCache) ) {
+       if ( findInSharedCacheImage(path, true, NULL, &mhInCache, &pathInCache, &slideInCache) ) {
                // see if this image in the cache was already loaded via a different path
                for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); ++it) {
                        ImageLoader* anImage = *it;
@@ -2725,7 +2843,7 @@ static ImageLoader* loadPhase2(const char* path, const char* orgPath, const Load
        const char* frameworkPartialPath = getFrameworkPartialPath(path);
        if ( frameworkPaths != NULL ) {
                if ( frameworkPartialPath != NULL ) {
-                       const int frameworkPartialPathLen = strlen(frameworkPartialPath);
+                       const size_t frameworkPartialPathLen = strlen(frameworkPartialPath);
                        for(const char* const* fp = frameworkPaths; *fp != NULL; ++fp) {
                                char npath[strlen(*fp)+frameworkPartialPathLen+8];
                                strcpy(npath, *fp);
@@ -2742,7 +2860,7 @@ static ImageLoader* loadPhase2(const char* path, const char* orgPath, const Load
        // <rdar://problem/14160846> Some apps depend on frameworks being found via library paths
        if ( (libraryPaths != NULL) && ((frameworkPartialPath == NULL) || sFrameworksFoundAsDylibs) ) {
                const char* libraryLeafName = getLibraryLeafName(path);
-               const int libraryLeafNameLen = strlen(libraryLeafName);
+               const size_t libraryLeafNameLen = strlen(libraryLeafName);
                for(const char* const* lp = libraryPaths; *lp != NULL; ++lp) {
                        char libpath[strlen(*lp)+libraryLeafNameLen+8];
                        strcpy(libpath, *lp);
@@ -2816,6 +2934,16 @@ static ImageLoader* loadPhase0(const char* path, const char* orgPath, const Load
        return loadPhase1(path, orgPath, context, exceptions);
 }
 
+#if DYLD_SHARED_CACHE_SUPPORT
+       static bool cacheablePath(const char* path) {
+               if (strncmp(path, "/usr/lib/", 9) == 0)
+                       return true;
+               if (strncmp(path, "/System/Library/", 16) == 0)
+                       return true;
+               return false;
+       }
+#endif
+
 //
 // Given all the DYLD_ environment variables, the general case for loading libraries
 // is that any given path expands into a list of possible locations to load.  We
@@ -2853,19 +2981,44 @@ ImageLoader* load(const char* path, const LoadContext& context)
        // try all path permutations and try open() until first success
        std::vector<const char*> exceptions;
        image = loadPhase0(path, orgPath, context, &exceptions);
+#if __IPHONE_OS_VERSION_MIN_REQUIRED && DYLD_SHARED_CACHE_SUPPORT && !TARGET_IPHONE_SIMULATOR
+       // <rdar://problem/16704628> support symlinks on disk to a path in dyld shared cache
+       if ( (image == NULL) && cacheablePath(path) && !context.dontLoad ) {
+               char resolvedPath[PATH_MAX];
+               realpath(path, resolvedPath);
+               int myerr = errno;
+               // If realpath() resolves to a path which does not exist on disk, errno is set to ENOENT
+               if ( (myerr == ENOENT) || (myerr == 0) )
+               {
+                       // see if this image is in shared cache
+                       const macho_header* mhInCache;
+                       const char*                     pathInCache;
+                       long                            slideInCache;
+                       if ( findInSharedCacheImage(resolvedPath, false, NULL, &mhInCache, &pathInCache, &slideInCache) ) {
+                               struct stat stat_buf;
+                               bzero(&stat_buf, sizeof(stat_buf));
+                               try {
+                                       image = ImageLoaderMachO::instantiateFromCache(mhInCache, pathInCache, slideInCache, stat_buf, gLinkContext);
+                                       image = checkandAddImage(image, context);
+                               }
+                               catch (...) {
+                                       image = NULL;
+                               }
+                       }
+               }
+       }
+#endif
     CRSetCrashLogMessage2(NULL);
        if ( image != NULL ) {
                // <rdar://problem/6916014> leak in dyld during dlopen when using DYLD_ variables
                for (std::vector<const char*>::iterator it = exceptions.begin(); it != exceptions.end(); ++it) {
                        free((void*)(*it));
                }
-#if __IPHONE_OS_VERSION_MIN_REQUIRED && DYLD_SHARED_CACHE_SUPPORT
+#if DYLD_SHARED_CACHE_SUPPORT
                // if loaded image is not from cache, but original path is in cache
                // set gSharedCacheOverridden flag to disable some ObjC optimizations
-               if ( !gSharedCacheOverridden ) {
-                       if ( !image->inSharedCache() && inSharedCache(path) ) {
-                               gSharedCacheOverridden = true;
-                       }
+               if ( !gSharedCacheOverridden && !image->inSharedCache() && image->isDylib() && cacheablePath(path) && inSharedCache(path) ) {
+                       gSharedCacheOverridden = true;
                }
 #endif
                return image;
@@ -2881,11 +3034,11 @@ ImageLoader* load(const char* path, const LoadContext& context)
                const char* msgStart = "no suitable image found.  Did find:";
                const char* delim = "\n\t";
                size_t allsizes = strlen(msgStart)+8;
-               for (unsigned int i=0; i < exceptions.size(); ++i) 
+               for (size_t i=0; i < exceptions.size(); ++i) 
                        allsizes += (strlen(exceptions[i]) + strlen(delim));
                char* fullMsg = new char[allsizes];
                strcpy(fullMsg, msgStart);
-               for (unsigned int i=0; i < exceptions.size(); ++i) {
+               for (size_t i=0; i < exceptions.size(); ++i) {
                        strcat(fullMsg, delim);
                        strcat(fullMsg, exceptions[i]);
                        free((void*)exceptions[i]);
@@ -2906,6 +3059,8 @@ ImageLoader* load(const char* path, const LoadContext& context)
 #elif __x86_64__
        #define ARCH_NAME                       "x86_64"
        #define ARCH_CACHE_MAGIC        "dyld_v1  x86_64"
+       #define ARCH_NAME_H                     "x86_64h"
+       #define ARCH_CACHE_MAGIC_H      "dyld_v1 x86_64h"
 #elif __ARM_ARCH_5TEJ__
        #define ARCH_NAME                       "armv5"
        #define ARCH_CACHE_MAGIC        "dyld_v1   armv5"
@@ -2915,15 +3070,18 @@ ImageLoader* load(const char* path, const LoadContext& context)
 #elif __ARM_ARCH_7F__
        #define ARCH_NAME                       "armv7f"
        #define ARCH_CACHE_MAGIC        "dyld_v1  armv7f"
+#elif __ARM_ARCH_7K__
+       #define ARCH_NAME                       "armv7k"
+       #define ARCH_CACHE_MAGIC        "dyld_v1  armv7k"
 #elif __ARM_ARCH_7A__
        #define ARCH_NAME                       "armv7"
        #define ARCH_CACHE_MAGIC        "dyld_v1   armv7"
 #elif __ARM_ARCH_7S__
        #define ARCH_NAME                       "armv7s"
        #define ARCH_CACHE_MAGIC        "dyld_v1  armv7s"
-#elif __ARM_ARCH_7K__
-       #define ARCH_NAME                       "armv7k"
-       #define ARCH_CACHE_MAGIC        "dyld_v1  armv7k"
+#elif __arm64__
+       #define ARCH_NAME                       "arm64"
+       #define ARCH_CACHE_MAGIC        "dyld_v1   arm64"
 #endif
 
 
@@ -2936,7 +3094,7 @@ static int __attribute__((noinline)) _shared_region_check_np(uint64_t* start_add
 
 
 static int __attribute__((noinline)) _shared_region_map_and_slide_np(int fd, uint32_t count, const shared_file_mapping_np mappings[],
-                                                                                               int codeSignatureMappingIndex, int slide, void* slideInfo, uint32_t slideInfoSize)
+                                                                                               int codeSignatureMappingIndex, long slide, void* slideInfo, unsigned long slideInfoSize)
 {
        // register code signature blob for whole dyld cache
        if ( codeSignatureMappingIndex != -1 ) {
@@ -3034,10 +3192,43 @@ int openSharedCacheFile()
        char path[MAXPATHLEN];
        strlcpy(path, sSharedCacheDir, MAXPATHLEN);
        strlcat(path, "/", MAXPATHLEN);
+#if __x86_64__
+       if ( sHaswell ) {
+               strlcat(path, DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME_H, MAXPATHLEN);
+               int fd = my_open(path, O_RDONLY, 0);
+               if ( fd != -1 ) {
+                       if ( gLinkContext.verboseMapping ) 
+                               dyld::log("dyld: Mapping%s shared cache from %s\n", (gLinkContext.sharedRegionMode == ImageLoader::kUsePrivateSharedRegion) ? " private": "", path);
+                       return fd;
+               }
+               strlcpy(path, sSharedCacheDir, MAXPATHLEN);
+       }
+#endif
        strlcat(path, DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME, MAXPATHLEN);
+       if ( gLinkContext.verboseMapping ) 
+               dyld::log("dyld: Mapping%s shared cache from %s\n", (gLinkContext.sharedRegionMode == ImageLoader::kUsePrivateSharedRegion) ? " private": "", path);
        return my_open(path, O_RDONLY, 0);
 }
 
+
+static void getCacheBounds(uint32_t mappingsCount, const shared_file_mapping_np mappings[], uint64_t& lowAddress, uint64_t& highAddress)
+{
+       lowAddress = 0;
+       highAddress = 0;
+       for(uint32_t i=0; i < mappingsCount; ++i) {
+               if ( lowAddress == 0 ) {
+                       lowAddress = mappings[i].sfm_address;
+                       highAddress = mappings[i].sfm_address + mappings[i].sfm_size;
+               }
+               else {
+                       if ( mappings[i].sfm_address < lowAddress )
+                               lowAddress = mappings[i].sfm_address;
+                       if ( (mappings[i].sfm_address + mappings[i].sfm_size) > highAddress )
+                               highAddress = mappings[i].sfm_address + mappings[i].sfm_size;
+               }
+       }
+}
+
 static long pickCacheSlide(uint32_t mappingsCount, shared_file_mapping_np mappings[])
 {
 #if __x86_64__
@@ -3068,26 +3259,15 @@ static long pickCacheSlide(uint32_t mappingsCount, shared_file_mapping_np mappin
        // else fall through to handle old style cache
 #endif
        // get bounds of cache
-       uint64_t lowAddress = 0;
-       uint64_t highAddress = 0;
-       for(uint32_t i=0; i < mappingsCount; ++i) {
-               if ( lowAddress == 0 ) {
-                       lowAddress = mappings[i].sfm_address;
-                       highAddress = mappings[i].sfm_address + mappings[i].sfm_size;
-               }
-               else {
-                       if ( mappings[i].sfm_address < lowAddress )
-                               lowAddress = mappings[i].sfm_address;
-                       if ( (mappings[i].sfm_address + mappings[i].sfm_size) > highAddress )
-                               highAddress = mappings[i].sfm_address + mappings[i].sfm_size;
-               }
-       }
+       uint64_t lowAddress;
+       uint64_t highAddress;
+       getCacheBounds(mappingsCount, mappings, lowAddress, highAddress);
        
        // find slop space
        const uint64_t space = (SHARED_REGION_BASE + SHARED_REGION_SIZE) - highAddress;
        
        // choose new random slide
-       long slide = (arc4random() % space) & (-4096);
+       long slide = dyld_page_trunc(arc4random() % space);
        //dyld::log("slideSpace=0x%0llX\n", space);
        //dyld::log("slide=0x%0lX\n", slide);
        
@@ -3102,11 +3282,16 @@ static long pickCacheSlide(uint32_t mappingsCount, shared_file_mapping_np mappin
 static void mapSharedCache()
 {
        uint64_t cacheBaseAddress = 0;
-       // quick check if a cache is alreay mapped into shared region
+       // quick check if a cache is already mapped into shared region
        if ( _shared_region_check_np(&cacheBaseAddress) == 0 ) {
                sSharedCache = (dyld_cache_header*)cacheBaseAddress;
                // if we don't understand the currently mapped shared cache, then ignore
-               if ( strcmp(sSharedCache->magic, ARCH_CACHE_MAGIC) != 0 ) {
+#if __x86_64__
+               const char* magic = (sHaswell ? ARCH_CACHE_MAGIC_H : ARCH_CACHE_MAGIC);
+#else
+               const char* magic = ARCH_CACHE_MAGIC;
+#endif
+               if ( strcmp(sSharedCache->magic, magic) != 0 ) {
                        sSharedCache = NULL;
                        if ( gLinkContext.verboseMapping ) {
                                dyld::log("dyld: existing shared cached in memory is not compatible\n");
@@ -3128,6 +3313,10 @@ static void mapSharedCache()
                if ( header->mappingOffset >= 0x68 ) {
                        memcpy(dyld::gProcessInfo->sharedCacheUUID, header->uuid, 16);
                }
+               // verbose logging
+               if ( gLinkContext.verboseMapping ) {
+                       dyld::log("dyld: re-using existing shared cache mapping\n");
+               }
        }
        else {
 #if __i386__ || __x86_64__
@@ -3160,7 +3349,12 @@ static void mapSharedCache()
                        uint8_t firstPages[8192];
                        if ( ::read(fd, firstPages, 8192) == 8192 ) {
                                dyld_cache_header* header = (dyld_cache_header*)firstPages;
-                               if ( strcmp(header->magic, ARCH_CACHE_MAGIC) == 0 ) {
+               #if __x86_64__
+                               const char* magic = (sHaswell ? ARCH_CACHE_MAGIC_H : ARCH_CACHE_MAGIC);
+               #else
+                               const char* magic = ARCH_CACHE_MAGIC;
+               #endif
+                               if ( strcmp(header->magic, magic) == 0 ) {
                                        const dyld_cache_mapping_info* const fileMappingsStart = (dyld_cache_mapping_info*)&firstPages[header->mappingOffset];
                                        const dyld_cache_mapping_info* const fileMappingsEnd = &fileMappingsStart[header->mappingCount];
                                        shared_file_mapping_np  mappings[header->mappingCount+1]; // add room for code-sig 
@@ -3194,7 +3388,7 @@ static void mapSharedCache()
                                                        }
                                                }
                                                // if shared cache is code signed, add a mapping for the code signature
-                                               uint32_t signatureSize = header->codeSignatureSize;
+                                               uint64_t signatureSize = header->codeSignatureSize;
                                                // zero size in header means signature runs to end-of-file
                                                if ( signatureSize == 0 )
                                                        signatureSize = stat_buf.st_size - header->codeSignatureOffset;
@@ -3202,7 +3396,11 @@ static void mapSharedCache()
                             int linkeditMapping = mappingCount-1;
                                                        codeSignatureMappingIndex = mappingCount++;
                                                        mappings[codeSignatureMappingIndex].sfm_address         = mappings[linkeditMapping].sfm_address + mappings[linkeditMapping].sfm_size;
+#if __arm__ || __arm64__
+                                                       mappings[codeSignatureMappingIndex].sfm_size            = (signatureSize+16383) & (-16384);
+#else
                                                        mappings[codeSignatureMappingIndex].sfm_size            = (signatureSize+4095) & (-4096);
+#endif
                                                        mappings[codeSignatureMappingIndex].sfm_file_offset     = header->codeSignatureOffset;
                                                        mappings[codeSignatureMappingIndex].sfm_max_prot        = VM_PROT_READ;
                                                        mappings[codeSignatureMappingIndex].sfm_init_prot       = VM_PROT_READ;
@@ -3228,7 +3426,17 @@ static void mapSharedCache()
                                                        goodCache = false;
                                                }
                                        }
-#endif                         
+#endif
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
+                                       {
+                                               uint64_t lowAddress;
+                                               uint64_t highAddress;
+                                               getCacheBounds(mappingCount, mappings, lowAddress, highAddress);
+                                               if ( (highAddress-lowAddress) > SHARED_REGION_SIZE ) 
+                                                       throw "dyld shared cache is too big to fit in shared region";
+                                       }
+#endif
+
                                        if ( goodCache && (readWriteMappingIndex == -1) ) {
                                                dyld::log("dyld: shared cached file is missing read/write mapping: %s" DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME "\n", sSharedCacheDir);
                                                goodCache = false;
@@ -3240,7 +3448,7 @@ static void mapSharedCache()
                                        if ( goodCache ) {
                                                long cacheSlide = 0;
                                                void* slideInfo = NULL;
-                                               uint32_t slideInfoSize = 0;
+                                               uint64_t slideInfoSize = 0;
                                                // check if shared cache contains slid info
                                                if ( header->slideInfoSize != 0 ) {
                                                        // <rdar://problem/8611968> don't slide shared cache if ASLR disabled (main executable didn't slide)
@@ -3256,6 +3464,12 @@ static void mapSharedCache()
                                                                mappings[readWriteMappingIndex].sfm_init_prot |= VM_PROT_SLIDE;
                                                        }
                                                }
+                                               if ( gLinkContext.verboseMapping ) {
+                                                       dyld::log("dyld: calling _shared_region_map_and_slide_np() with regions:\n");
+                                                       for (int i=0; i < mappingCount; ++i) {
+                                                               dyld::log("   address=0x%08llX, size=0x%08llX, fileOffset=0x%08llX\n", mappings[i].sfm_address, mappings[i].sfm_size, mappings[i].sfm_file_offset);
+                                                       }
+                                               }
                                                if (_shared_region_map_and_slide_np(fd, mappingCount, mappings, codeSignatureMappingIndex, cacheSlide, slideInfo, slideInfoSize) == 0) {
                                                        // successfully mapped cache into shared region
                                                        sSharedCache = (dyld_cache_header*)mappings[0].sfm_address;
@@ -3268,6 +3482,9 @@ static void mapSharedCache()
                                                        }
                                                }
                                                else {
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
+                                                       throw "dyld shared cache could not be mapped";
+#endif
                                                        if ( gLinkContext.verboseMapping ) 
                                                                dyld::log("dyld: shared cached file could not be mapped\n");
                                                }
@@ -3302,12 +3519,6 @@ static void mapSharedCache()
                // only room to tell gdb about first four regions
                if ( dyld_shared_cache_ranges.sharedRegionsCount > 4 )
                        dyld_shared_cache_ranges.sharedRegionsCount = 4;
-               if ( gLinkContext.verboseMapping ) {
-                       if ( gLinkContext.sharedRegionMode == ImageLoader::kUseSharedRegion )
-                               dyld::log("dyld: Mapping shared cache from %s/" DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME "\n", sSharedCacheDir);
-                       else if ( gLinkContext.sharedRegionMode == ImageLoader::kUsePrivateSharedRegion )
-                               dyld::log("dyld: Mapping private shared cache from %s/" DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME "\n", sSharedCacheDir);
-               }
                const dyld_cache_mapping_info* const end = &start[dyld_shared_cache_ranges.sharedRegionsCount];
                int index = 0;
                for (const dyld_cache_mapping_info* p = start; p < end; ++p, ++index ) {
@@ -3339,7 +3550,7 @@ static void mapSharedCache()
                if ( gLinkContext.verboseMapping ) {
                        // list the code blob
                        dyld_cache_header* header = (dyld_cache_header*)sSharedCache;
-                       uint32_t signatureSize = header->codeSignatureSize;
+                       uint64_t signatureSize = header->codeSignatureSize;
                        // zero size in header means signature runs to end-of-file
                        if ( signatureSize == 0 ) {
                                struct stat stat_buf;
@@ -3355,7 +3566,10 @@ static void mapSharedCache()
 #if __IPHONE_OS_VERSION_MIN_REQUIRED
                // check for file that enables dyld shared cache dylibs to be overridden
                struct stat enableStatBuf;
-               sDylibsOverrideCache = ( my_stat(IPHONE_DYLD_SHARED_CACHE_DIR "enable-dylibs-to-override-cache", &enableStatBuf) == 0 );
+               // check file size to determine if correct file is in place. 
+               // See <rdar://problem/13591370> Need a way to disable roots without removing /S/L/C/com.apple.dyld/enable...
+               sDylibsOverrideCache = ( (my_stat(IPHONE_DYLD_SHARED_CACHE_DIR "enable-dylibs-to-override-cache", &enableStatBuf) == 0)
+                                                                       && (enableStatBuf.st_size < ENABLE_DYLIBS_TO_OVERRIDE_CACHE_SIZE) );
 #endif 
        }
 }
@@ -3445,6 +3659,9 @@ void registerAddCallback(ImageCallback func)
 
 void registerRemoveCallback(ImageCallback func)
 {
+       // <rdar://problem/15025198> ignore calls to register a notification during a notification
+       if ( sRemoveImageCallbacksInUse )
+               return;
        sRemoveImageCallbacks.push_back(func);
 }
 
@@ -3541,7 +3758,7 @@ uintptr_t fastBindLazySymbol(ImageLoader** imageLoaderCache, uintptr_t lazyBindi
        
        // bind lazy pointer and return it
        try {
-               result = (*imageLoaderCache)->doBindFastLazySymbol(lazyBindingInfoOffset, gLinkContext, 
+               result = (*imageLoaderCache)->doBindFastLazySymbol((uint32_t)lazyBindingInfoOffset, gLinkContext, 
                                                                (dyld::gLibSystemHelpers != NULL) ? dyld::gLibSystemHelpers->acquireGlobalDyldLock : NULL,
                                                                (dyld::gLibSystemHelpers != NULL) ? dyld::gLibSystemHelpers->releaseGlobalDyldLock : NULL);
        }
@@ -3573,8 +3790,8 @@ static bool findExportedSymbol(const char* name, bool onlyInCoalesced, const Ima
        // search all images in order
        const ImageLoader* firstWeakImage = NULL;
        const ImageLoader::Symbol* firstWeakSym = NULL;
-       const unsigned int imageCount = sAllImages.size();
-       for(unsigned int i=0; i < imageCount; ++i) {
+       const size_t imageCount = sAllImages.size();
+       for(size_t i=0; i < imageCount; ++i) {
                ImageLoader* anImage = sAllImages[i];
                // the use of inserted libraries alters search order
                // so that inserted libraries are found before the main executable
@@ -3625,8 +3842,8 @@ bool findCoalescedExportedSymbol(const char* name, const ImageLoader::Symbol** s
 bool flatFindExportedSymbolWithHint(const char* name, const char* librarySubstring, const ImageLoader::Symbol** sym, const ImageLoader** image)
 {
        // search all images in order
-       const unsigned int imageCount = sAllImages.size();
-       for(unsigned int i=0; i < imageCount; ++i){
+       const size_t imageCount = sAllImages.size();
+       for(size_t i=0; i < imageCount; ++i){
                ImageLoader* anImage = sAllImages[i];
                // only look at images whose paths contain the hint string (NULL hint string is wildcard)
                if ( ! anImage->isBundle() && ((librarySubstring==NULL) || (strstr(anImage->getPath(), librarySubstring) != NULL)) ) {
@@ -3784,8 +4001,14 @@ static void setContext(const macho_header* mainExecutableMH, int argc, const cha
        gLinkContext.programVars.__prognamePtr=&gLinkContext.progname;
        gLinkContext.mainExecutable                     = NULL;
        gLinkContext.imageSuffix                        = NULL;
+       gLinkContext.dynamicInterposeArray      = NULL;
+       gLinkContext.dynamicInterposeCount      = 0;
        gLinkContext.prebindUsage                       = ImageLoader::kUseAllPrebinding;
+#if TARGET_IPHONE_SIMULATOR
+       gLinkContext.sharedRegionMode           = ImageLoader::kDontUseSharedRegion;
+#else
        gLinkContext.sharedRegionMode           = ImageLoader::kUseSharedRegion;
+#endif
 }
 
 
@@ -3898,6 +4121,7 @@ static bool getDylibVersionAndInstallname(const char* dylibPath, uint32_t* versi
 }
 #endif // SUPPORT_VERSIONED_PATHS
                                                
+
 #if 0
 static void printAllImages()
 {
@@ -3997,17 +4221,31 @@ void garbageCollectImages()
                }
 
                // collect phase: run termination routines for images not marked in-use
-               // TO DO:  When libc has cxa_finalize() that takes array of images, pass deadImages[] instead of the for loop here
+               const int maxRangeCount = deadCount*2;
+               __cxa_range_t ranges[maxRangeCount];
+               int rangeCount = 0;
                for (unsigned i=0; i < deadCount; ++i) {
                        ImageLoader* image = deadImages[i];
+                       for (unsigned int j=0; j < image->segmentCount(); ++j) {
+                               if ( !image->segExecutable(j) )
+                                       continue;
+                               if ( rangeCount < maxRangeCount ) {
+                                       ranges[rangeCount].addr = (const void*)image->segActualLoadAddress(j);
+                                       ranges[rangeCount].length = image->segSize(j);
+                                       ++rangeCount;
+                               }
+                       }
                        try {
-                               if (gLogAPIs) dyld::log("dlclose(), running terminators for %p %s\n", image, image->getShortName());
-                               runImageTerminators(image);
+                               runImageStaticTerminators(image);
                        }
                        catch (const char* msg) {
                                dyld::warn("problem running terminators for image: %s\n", msg);
                        }
                }
+               
+               // <rdar://problem/14718598> dyld should call __cxa_finalize_ranges()
+               if ( (rangeCount > 0) && (gLibSystemHelpers != NULL) && (gLibSystemHelpers->version >= 13) )
+                       (*gLibSystemHelpers->cxa_finalize_ranges)(ranges, rangeCount);
 
                // collect phase: delete all images which are not marked in-use
                bool mightBeMore;
@@ -4062,6 +4300,25 @@ void preflight(ImageLoader* image, const ImageLoader::RPathChain& loaderRPaths)
        preflight_finally(image);
 }
 
+#if __x86_64__
+static bool isHaswell()
+{
+#if TARGET_IPHONE_SIMULATOR
+       return false;
+#else
+       // check system is capable of running x86_64h code
+       struct host_basic_info info;
+       mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
+       mach_port_t hostPort = mach_host_self();
+       kern_return_t result = host_info(hostPort, HOST_BASIC_INFO, (host_info_t)&info, &count);
+       mach_port_deallocate(mach_task_self(), hostPort);
+       if ( result != KERN_SUCCESS )
+               return false;
+       return ( info.cpu_subtype == CPU_SUBTYPE_X86_64_H );
+#endif
+}
+#endif
+
 static void loadInsertedDylib(const char* path)
 {
        ImageLoader* image = NULL;
@@ -4081,7 +4338,11 @@ static void loadInsertedDylib(const char* path)
                image = load(path, context);
        }
        catch (const char* msg) {
+#if TARGET_IPHONE_SIMULATOR
+               dyld::log("dyld: warning: could not load inserted library '%s' because %s\n", path, msg);
+#else
                halt(dyld::mkstringf("could not load inserted library '%s' because %s\n", path, msg));
+#endif
        }
        catch (...) {
                halt(dyld::mkstringf("could not load inserted library '%s'\n", path));
@@ -4156,7 +4417,8 @@ typedef int (*fcntl_proc_t)(int, int, void*);
 typedef int (*ioctl_proc_t)(int, unsigned long, void*);
 static void* getProcessInfo() { return dyld::gProcessInfo; }
 static SyscallHelpers sSysCalls = {
-               1, 
+               3,
+               // added in version 1
                (open_proc_t)&open, 
                &close, 
                &pread, 
@@ -4185,7 +4447,13 @@ static SyscallHelpers sSysCalls = {
                &OSMemoryBarrier,
                &getProcessInfo,
                &__error,
-               &mach_absolute_time
+               &mach_absolute_time,
+               // added in version 2
+               &thread_switch,
+               // added in version 3
+               &opendir,
+               &readdir_r,
+               &closedir
 };
 
 __attribute__((noinline))
@@ -4325,6 +4593,19 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide,
 {
        uintptr_t result = 0;
        sMainExecutableMachHeader = mainExecutableMH;
+#if !TARGET_IPHONE_SIMULATOR
+       const char* loggingPath = _simple_getenv(envp, "DYLD_PRINT_TO_FILE");
+       if ( loggingPath != NULL ) {
+               int fd = open(loggingPath, O_WRONLY | O_CREAT | O_APPEND, 0644);
+               if ( fd != -1 ) {
+                       sLogfile = fd;
+                       sLogToFile = true;
+               }
+               else {
+                       dyld::log("dyld: could not open DYLD_PRINT_TO_FILE='%s', errno=%d\n", loggingPath, errno);
+               }
+       }
+#endif
 #if __MAC_OS_X_VERSION_MIN_REQUIRED
        // if this is host dyld, check to see if iOS simulator is being run
        const char* rootPath = _simple_getenv(envp, "DYLD_ROOT_PATH");
@@ -4344,13 +4625,6 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide,
 #endif
 
        CRSetCrashLogMessage("dyld: launch started");
-#ifdef ALTERNATIVE_LOGFILE
-       sLogfile = open(ALTERNATIVE_LOGFILE, O_WRONLY | O_CREAT | O_APPEND);
-       if ( sLogfile == -1 ) {
-               sLogfile = STDERR_FILENO;
-               dyld::log("error opening alternate log file %s, errno = %d\n", ALTERNATIVE_LOGFILE, errno);
-       }
-#endif
 
 #if LOG_BINDINGS
        char bindingsLogPath[256];
@@ -4438,16 +4712,35 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide,
        try {
                // add dyld itself to UUID list
                addDyldImageToUUIDList();
-               if ( sProcessIsRestricted )
-                       CRSetCrashLogMessage("dyld: launch, loading dependent libraries, ignoring DYLD_* env vars");
-               else
-                       CRSetCrashLogMessage("dyld: launch, loading dependent libraries");
+               CRSetCrashLogMessage(sLoadingCrashMessage);
                // instantiate ImageLoader for main executable
                sMainExecutable = instantiateFromLoadedImage(mainExecutableMH, mainExecutableSlide, sExecPath);
                gLinkContext.mainExecutable = sMainExecutable;
                gLinkContext.processIsRestricted = sProcessIsRestricted;
                gLinkContext.mainExecutableCodeSigned = hasCodeSignatureLoadCommand(mainExecutableMH);
+
+#if TARGET_IPHONE_SIMULATOR
+               // check main executable is not too new for this OS
+               {
+                       if ( ! isSimulatorBinary((uint8_t*)mainExecutableMH, sExecPath) ) {
+                               throwf("program was built for Mac OS X and cannot be run in simulator"); 
+                       }
+                       uint32_t mainMinOS = sMainExecutable->minOSVersion();
+                       // dyld is always built for the current OS, so we can get the current OS version
+                       // from the load command in dyld itself.
+                       uint32_t dyldMinOS = ImageLoaderMachO::minOSVersion((const mach_header*)&__dso_handle);
+                       if ( mainMinOS > dyldMinOS ) {
+                               throwf("app was built for iOS %d.%d which is newer than this simulator %d.%d", 
+                                               mainMinOS >> 16, ((mainMinOS >> 8) & 0xFF),
+                                               dyldMinOS >> 16, ((dyldMinOS >> 8) & 0xFF));
+                       }
+               }
+#endif
+
                // load shared cache
+       #if __x86_64__
+               sHaswell = isHaswell();
+       #endif
                checkSharedRegionDisable();
        #if DYLD_SHARED_CACHE_SUPPORT
                if ( gLinkContext.sharedRegionMode != ImageLoader::kDontUseSharedRegion )
@@ -4479,7 +4772,11 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide,
                                ImageLoader* image = sAllImages[i+1];
                                link(image, sEnv.DYLD_BIND_AT_LAUNCH, true, ImageLoader::RPathChain(NULL, NULL));
                                image->setNeverUnloadRecursive();
-                               // only INSERTED libraries can interpose
+                       }
+                       // only INSERTED libraries can interpose
+                       // register interposing info after all inserted libraries are bound so chaining works
+                       for(unsigned int i=0; i < sInsertedDylibCount; ++i) {
+                               ImageLoader* image = sAllImages[i+1];
                                image->registerInterposing();
                        }
                }
@@ -4524,13 +4821,6 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide,
                dyld::log("dyld: launch failed\n");
        }
 
-#ifdef ALTERNATIVE_LOGFILE
-       // only use alternate log during launch, otherwise file is open forever
-       if ( sLogfile != STDERR_FILENO ) {
-               close(sLogfile);
-               sLogfile = STDERR_FILENO;
-       }
-#endif
        CRSetCrashLogMessage(NULL);
        
        return result;
index 9c55ecdd2a465670416ff0af5bcd78bf54c58c2e..3cdc3c7fc998df2ea299e08a154e6860e67ea486 100644 (file)
@@ -75,8 +75,7 @@ namespace dyld {
        extern void                                     preflight(ImageLoader* image, const ImageLoader::RPathChain& loaderRPaths);
        extern void                                     link(ImageLoader* image, bool forceLazysBound, bool neverUnload, const ImageLoader::RPathChain& loaderRPaths);
        extern void                                     runInitializers(ImageLoader* image);
-       extern void                                     runTerminators(void*);
-       extern void                                     runImageTerminators(ImageLoader* image);
+       extern void                                     runImageStaticTerminators(ImageLoader* image);  
        extern const char*                      getExecutablePath();
        extern bool                                     validImage(const ImageLoader*);
        extern ImageLoader*                     getIndexedImage(uint32_t index);
@@ -93,8 +92,8 @@ namespace dyld {
        extern void                                     removeImage(ImageLoader* image);
        extern ImageLoader*                     cloneImage(ImageLoader* image);
        extern void                                     forEachImageDo( void (*)(ImageLoader*, void*), void*);
-       extern uintptr_t                        _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int argc, const char* argv[], const char* envp[], 
-                                                                         const char* apple[], uintptr_t* startGlue) __attribute__((noinline));  // <rdar://problem/11340356>
+       extern uintptr_t                        _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int argc, const char* argv[], const char* envp[],
+                                                                         const char* apple[], uintptr_t* startGlue) __attribute__((noinline));  // <rdar://problem/113
        extern void                                     halt(const char* message)  __attribute__((noreturn));
        extern void                                     setErrorMessage(const char* msg);
        extern const char*                      getErrorMessage();
index b99ea46728ac3cb636b3d3e7546dacbcb4647fdc..2c888ced856fa8655fae3e5aeefcd51731a4e28a 100644 (file)
@@ -70,6 +70,7 @@ extern void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[
        #define DEPRECATED_APIS_SUPPORTED 1
 #endif
 
+static bool sDynamicInterposing = false;
 
 #if DEPRECATED_APIS_SUPPORTED
 static char sLastErrorFilePath[1024];
@@ -100,7 +101,7 @@ static void _dyld_call_module_initializers_for_dylib(const struct mach_header* m
 static void            client_dyld_lookup_and_bind(const char* symbolName, void** address, NSModule* module);
 static bool            client_NSIsSymbolNameDefined(const char* symbolName);
 #endif // DEPRECATED_APIS_SUPPORTED
-#if !__arm__
+#if SUPPORT_ZERO_COST_EXCEPTIONS
 static bool client_dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info);
 #endif
 
@@ -134,20 +135,18 @@ static struct dyld_func dyld_funcs[] = {
        {"__dyld_dyld_register_image_state_change_handler",     (void*)dyld_register_image_state_change_handler },
        {"__dyld_register_thread_helpers",                                      (void*)registerThreadHelpers },
        {"__dyld_fork_child",                                                           (void*)_dyld_fork_child },
-    {"__dyld_moninit",                                                                 (void*)_dyld_moninit },
     {"__dyld_make_delayed_module_initializer_calls",   (void*)_dyld_make_delayed_module_initializer_calls },
        {"__dyld_get_all_image_infos",                                          (void*)_dyld_get_all_image_infos },
-#if !__arm__
+#if SUPPORT_ZERO_COST_EXCEPTIONS
        {"__dyld_find_unwind_sections",                                         (void*)client_dyld_find_unwind_sections },
 #endif
-#if __i386__ || __x86_64__ || __arm__
+#if __i386__ || __x86_64__ || __arm__ || __arm64__
        {"__dyld_fast_stub_entry",                                                      (void*)dyld::fastBindLazySymbol },
 #endif
        {"__dyld_image_path_containing_address",                        (void*)dyld_image_path_containing_address },
-#if __IPHONE_OS_VERSION_MIN_REQUIRED   
        {"__dyld_shared_cache_some_image_overridden",           (void*)dyld_shared_cache_some_image_overridden },
-#endif
        {"__dyld_process_is_restricted",                                        (void*)dyld::processIsRestricted },
+       {"__dyld_dynamic_interpose",                                            (void*)dyld_dynamic_interpose },
 
        // deprecated
 #if DEPRECATED_APIS_SUPPORTED
@@ -283,7 +282,7 @@ int _NSGetExecutablePath(char* buf, uint32_t *bufsize)
                dyld::log("%s(...)\n", __func__);
        const char* exePath = dyld::getExecutablePath();
        if(*bufsize < strlen(exePath) + 1){
-           *bufsize = strlen(exePath) + 1;
+           *bufsize = (uint32_t)(strlen(exePath) + 1);
            return -1;
        }
        strcpy(buf, exePath);
@@ -1114,7 +1113,19 @@ bool NSUnLinkModule(NSModule module, uint32_t options)
        ImageLoader* image = NSModuleToImageLoader(module);
        if ( image == NULL ) 
                return false;
-       dyld::runImageTerminators(image);
+       dyld::runImageStaticTerminators(image);
+       if ( (dyld::gLibSystemHelpers != NULL) && (dyld::gLibSystemHelpers->version >= 13) ) {
+               __cxa_range_t ranges[3];
+               int rangeCount = 0;
+               for (unsigned int j=0; j < image->segmentCount(); ++j) {
+                       if ( !image->segExecutable(j) )
+                               continue;
+                       ranges[rangeCount].addr = (const void*)image->segActualLoadAddress(j);
+                       ranges[rangeCount].length = image->segSize(j);
+                       ++rangeCount;
+               }
+               (*dyld::gLibSystemHelpers->cxa_finalize_ranges)(ranges, rangeCount);
+       }
        dyld::removeImage(image);
        
        if ( (options & NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED) != 0 )
@@ -1195,27 +1206,6 @@ void _dyld_fork_child()
        dyld::gProcessInfo->systemOrderFlag = 0;
 }
 
-typedef void (*MonitorProc)(char *lowpc, char *highpc);
-
-static void monInitCallback(ImageLoader* image, void* userData)
-{
-       MonitorProc proc = (MonitorProc)userData;
-       void* start;
-       size_t length;
-       if ( image->getSectionContent("__TEXT", "__text", &start, &length) ) {
-               proc((char*)start, (char*)start+length);
-       }
-}
-
-//
-// _dyld_moninit is called from profiling runtime routine moninit().
-// dyld calls back with the range of each __TEXT/__text section in every
-// linked image.
-//
-void _dyld_moninit(MonitorProc proc)
-{
-       dyld::forEachImageDo(&monInitCallback, (void*)proc);
-}
 
 #if DEPRECATED_APIS_SUPPORTED
 // returns true if prebinding was used in main executable
@@ -1250,13 +1240,13 @@ static bool NSMakePrivateModulePublic(NSModule module)
 
 #endif // DEPRECATED_APIS_SUPPORTED
 
-bool lookupDyldFunction(const char* name, uintptr_t* address)
+int _dyld_func_lookup(const char* name, void** address)
 {
        for (const dyld_func* p = dyld_funcs; p->name != NULL; ++p) {
            if ( strcmp(p->name, name) == 0 ) {
                        if( p->implementation == unimplemented )
                                dyld::log("unimplemented dyld function: %s\n", p->name);
-                       *address = (uintptr_t)p->implementation;
+                       *address = p->implementation;
                        return true;
            }
        }
@@ -1272,7 +1262,7 @@ static void registerThreadHelpers(const dyld::LibSystemHelpers* helpers)
        // let gdb know it is safe to run code in inferior that might call malloc()
        dyld::gProcessInfo->libSystemInitialized = true;        
        
-#if __arm__
+#if !SUPPORT_ZERO_COST_EXCEPTIONS
        if ( helpers->version >= 5 )  {
                // create key use by dyld exception handling
                pthread_key_t key;
@@ -1744,7 +1734,13 @@ void* dlsym(void* handle, const char* symbolName)
                
                if ( sym != NULL ) {
                        CRSetCrashLogMessage(NULL);
-                       return (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
+                       ImageLoader* callerImage = NULL;
+                       if ( sDynamicInterposing ) {
+                               // only take time to look up caller, if dynamic interposing in use
+                               void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
+                               callerImage = dyld::findImageContainingAddress(callerAddress);
+                       }
+                       return (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext, callerImage);
                }
                const char* str = dyld::mkstringf("dlsym(%p, %s): symbol not found", handle, symbolName);
                dlerrorSet(str);
@@ -1771,7 +1767,7 @@ const struct dyld_all_image_infos* _dyld_get_all_image_infos()
        return dyld::gProcessInfo;
 }
 
-#if !__arm__
+#if SUPPORT_ZERO_COST_EXCEPTIONS
 static bool client_dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info)
 {
        //if ( dyld::gLogAPIs )
@@ -1811,7 +1807,6 @@ const char* dyld_image_path_containing_address(const void* address)
 
 
 
-#if __IPHONE_OS_VERSION_MIN_REQUIRED   
 bool dyld_shared_cache_some_image_overridden()
 {
  #if DYLD_SHARED_CACHE_SUPPORT
@@ -1820,7 +1815,32 @@ bool dyld_shared_cache_some_image_overridden()
     return true;
  #endif
 }
-#endif
+
+
+void dyld_dynamic_interpose(const struct mach_header* mh, const struct dyld_interpose_tuple array[], size_t count)
+{
+       if ( mh == NULL )
+               return;
+       if ( array == NULL )
+               return;
+       if ( count == 0 )
+               return;
+       ImageLoader* image = dyld::findImageByMachHeader(mh);
+       if ( image == NULL )
+               return;
+       
+       // make pass at bound references in this image and update them
+       dyld::gLinkContext.dynamicInterposeArray = array;
+       dyld::gLinkContext.dynamicInterposeCount = count;
+               image->dynamicInterpose(dyld::gLinkContext);
+       dyld::gLinkContext.dynamicInterposeArray = NULL;
+       dyld::gLinkContext.dynamicInterposeCount = 0;
+       
+       // leave interposing info so any future (lazy) binding will get it too
+       image->addDynamicInterposingTuples(array, count);
+       
+       sDynamicInterposing = true;
+}
 
 
 
index f7b59be6f2bcab18c6ee01407255a06a74f9994d..6ded1a7e7f430ccc6297bdeb535159544c1c0f1a 100644 (file)
 #include "mach-o/dyld.h"
 #include "mach-o/dyld_priv.h"
 
+#include "ImageLoader.h"
 #include "dyldLock.h"
 #include "start_glue.h"
 
 extern "C" int  __cxa_atexit(void (*func)(void *), void *arg, void *dso);
 extern "C" void __cxa_finalize(const void *dso);
+extern "C" void __cxa_finalize_ranges(const struct __cxa_range_t ranges[], int count);
 
 
 #ifndef LC_VERSION_MIN_MACOSX
@@ -61,7 +63,6 @@ extern "C" void __cxa_finalize(const void *dso);
        #define LC_LOAD_UPWARD_DYLIB (0x23|LC_REQ_DYLD) /* load of dylib whose initializers run later */
 #endif
 
-#define DYLD_SHARED_CACHE_SUPPORT (__i386__ || __x86_64__ || __arm__)
 
 // deprecated APIs are still availble on Mac OS X, but not on iPhone OS
 #if __IPHONE_OS_VERSION_MIN_REQUIRED   
@@ -79,10 +80,10 @@ extern "C" void __cxa_finalize(const void *dso);
 static
 bool
 names_match(
-char *install_name,
+const char *install_name,
 const char* libraryName)
 {
-    char *basename;
+    const char *basename;
     unsigned long n;
 
        /*
@@ -103,7 +104,7 @@ const char* libraryName)
         * of the -framework cases.
         */
        if(strcmp(basename, libraryName) == 0)
-           return(TRUE);
+           return true;
 
        /*
         * Now check the base name for "lib" if so proceed to check for the
@@ -113,14 +114,14 @@ const char* libraryName)
            n = strlen(libraryName);
            if(strncmp(basename+3, libraryName, n) == 0){
                if(strncmp(basename+3+n, ".dylib", 6) == 0)
-                   return(TRUE);
+                   return true;
                if(basename[3+n] == '.' &&
                   basename[3+n+1] != '\0' &&
                   strncmp(basename+3+n+2, ".dylib", 6) == 0)
-                   return(TRUE);
+                   return true;
            }
        }
-       return(FALSE);
+       return false;
 }
 
 #if DEPRECATED_APIS_SUPPORTED
@@ -346,42 +347,35 @@ uint32_t options)
  * and not a list of current versions that dependent libraries and bundles the
  * program is using were built with.
  */
-int32_t
-NSVersionOfLinkTimeLibrary(
-const char* libraryName)
+int32_t NSVersionOfLinkTimeLibrary(const char* libraryName)
 {
-    unsigned long i;
-    struct load_command *load_commands, *lc;
-    struct dylib_command *dl;
-    char *install_name;
+       // Lazily call _NSGetMachExecuteHeader() and cache result
 #if __LP64__
-    static struct mach_header_64 *mh = NULL;
+    static mach_header_64* mh = NULL;
 #else
-    static struct mach_header *mh = NULL;
+    static mach_header* mh = NULL;
 #endif
-       if(mh == NULL)
+       if ( mh == NULL )
            mh = _NSGetMachExecuteHeader();
-       load_commands = (struct load_command *)
 #if __LP64__
-                           ((char *)mh + sizeof(struct mach_header_64));
+       const load_command* lc = (load_command*)((char*)mh + sizeof(mach_header_64));
 #else
-                           ((char *)mh + sizeof(struct mach_header));
+       const load_command* lc = (load_command*)((char*)mh + sizeof(mach_header));
 #endif
-       lc = load_commands;
-       for(i = 0; i < mh->ncmds; i++){
+       for(uint32_t i = 0; i < mh->ncmds; i++){
                switch ( lc->cmd ) { 
                        case LC_LOAD_DYLIB:
                        case LC_LOAD_WEAK_DYLIB:
                        case LC_LOAD_UPWARD_DYLIB:
-                               dl = (struct dylib_command *)lc;
-                               install_name = (char *)dl + dl->dylib.name.offset;
-                               if(names_match(install_name, libraryName) == TRUE)
-                                       return(dl->dylib.current_version);
+                               const dylib_command* dl = (dylib_command *)lc;
+                               const char* install_name = (char*)dl + dl->dylib.name.offset;
+                               if ( names_match(install_name, libraryName) )
+                                       return dl->dylib.current_version;
                                break;
                }
-           lc = (struct load_command *)((char *)lc + lc->cmdsize);
+           lc = (load_command*)((char*)lc + lc->cmdsize);
        }
-       return(-1);
+       return (-1);
 }
 
 /*
@@ -391,39 +385,31 @@ const char* libraryName)
  * it would be "x" and with -framework Foo it would be "Foo").  If the program
  * is not using the specified library it returns -1.
  */
-int32_t
-NSVersionOfRunTimeLibrary(
-const char* libraryName)
-{
-    unsigned long i, j, n;
-    char *install_name;
-    struct load_command *load_commands, *lc;
-    struct dylib_command *dl;
-    const struct mach_header *mh;
-
-       n = _dyld_image_count();
-       for(i = 0; i < n; i++){
-           mh = _dyld_get_image_header(i);
-           if(mh->filetype != MH_DYLIB)
-               continue;
-           load_commands = (struct load_command *)
+int32_t NSVersionOfRunTimeLibrary(const char* libraryName)
+{
+       uint32_t n = _dyld_image_count();
+       for(uint32_t i = 0; i < n; i++){
+           const mach_header* mh = _dyld_get_image_header(i);
+               if ( mh == NULL )
+                       continue;
+           if ( mh->filetype != MH_DYLIB )
+                       continue;
 #if __LP64__
-                           ((char *)mh + sizeof(struct mach_header_64));
+           const load_command* lc = (load_command*)((char*)mh + sizeof(mach_header_64));
 #else
-                           ((char *)mh + sizeof(struct mach_header));
+           const load_command* lc = (load_command*)((char*)mh + sizeof(mach_header));
 #endif
-           lc = load_commands;
-           for(j = 0; j < mh->ncmds; j++){
-               if(lc->cmd == LC_ID_DYLIB){
-                   dl = (struct dylib_command *)lc;
-                   install_name = (char *)dl + dl->dylib.name.offset;
-                   if(names_match(install_name, libraryName) == TRUE)
-                       return(dl->dylib.current_version);
-               }
-               lc = (struct load_command *)((char *)lc + lc->cmdsize);
+           for(uint32_t j = 0; j < mh->ncmds; j++){
+                       if ( lc->cmd == LC_ID_DYLIB ) {
+                               const dylib_command* dl = (dylib_command*)lc;
+                               const char* install_name = (char *)dl + dl->dylib.name.offset;
+                               if ( names_match(install_name, libraryName) )
+                                       return dl->dylib.current_version;
+                       }
+                       lc = (load_command*)((char*)lc + lc->cmdsize);
            }
        }
-       return(-1);
+       return (-1);
 }
 
 #define PACKED_VERSION(major, minor, tiny) ((((major) & 0xffff) << 16) | (((minor) & 0xff) << 8) | ((tiny) & 0xff))
@@ -459,7 +445,12 @@ uint32_t dyld_get_sdk_version(const mach_header* mh)
        uint32_t libSystemVers = 0;
 #endif
        for(uint32_t i = 0; i < mh->ncmds; ++i) {
-               switch ( cmd->cmd ) { 
+           const load_command* nextCmd = (load_command*)((char *)cmd + cmd->cmdsize);
+               // <rdar://problem/14381579&16050962> sanity check size of command
+               if ( (cmd->cmdsize < 8) || (nextCmd > cmdsEnd) || (nextCmd < startCmds)) {
+                       return 0;
+               }
+               switch ( cmd->cmd ) {
 #if __IPHONE_OS_VERSION_MIN_REQUIRED 
                        case LC_VERSION_MIN_IPHONEOS:
 #else
@@ -478,6 +469,9 @@ uint32_t dyld_get_sdk_version(const mach_header* mh)
                        case LC_LOAD_WEAK_DYLIB:
                        case LC_LOAD_UPWARD_DYLIB:
                                dylibCmd = (dylib_command*)cmd;
+                               // sanity check dylib command layout
+                               if ( dylibCmd->dylib.name.offset > cmd->cmdsize )
+                                       return 0;
                                dylibName = (char*)dylibCmd + dylibCmd->dylib.name.offset;
 #if __IPHONE_OS_VERSION_MIN_REQUIRED          
                                if ( strcmp(dylibName, "/System/Library/Frameworks/Foundation.framework/Foundation") == 0 )
@@ -488,13 +482,7 @@ uint32_t dyld_get_sdk_version(const mach_header* mh)
 #endif
                                break;
                }
-               // <rdar://problem/14381579> sanity check size of command
-               if ( (cmd->cmdsize < 8) || (cmd->cmdsize > mh->sizeofcmds) )
-                       return 0;
-           cmd = (load_command*)((char *)cmd + cmd->cmdsize);
-               // <rdar://problem/14381579> bounds check
-               if ( (cmd > cmdsEnd) || (cmd < startCmds) )
-                       return 0;
+               cmd = nextCmd;
        }
 
        struct DylibToOSMapping {
@@ -582,7 +570,12 @@ uint32_t dyld_get_min_os_version(const struct mach_header* mh)
        const version_min_command* versCmd;
        const load_command* cmd = startCmds;
        for(uint32_t i = 0; i < mh->ncmds; ++i) {
-               switch ( cmd->cmd ) { 
+           const load_command* nextCmd = (load_command*)((char *)cmd + cmd->cmdsize);
+               // <rdar://problem/14381579&16050962> sanity check size of command
+               if ( (cmd->cmdsize < 8) || (nextCmd > cmdsEnd) || (nextCmd < startCmds)) {
+                       return 0;
+               }
+               switch ( cmd->cmd ) {
 #if __IPHONE_OS_VERSION_MIN_REQUIRED          
                        case LC_VERSION_MIN_IPHONEOS:
 #else
@@ -592,13 +585,7 @@ uint32_t dyld_get_min_os_version(const struct mach_header* mh)
                                return versCmd->version;        // found explicit min OS version
                                break;
                }
-               // <rdar://problem/14381579> sanity check size of command
-               if ( (cmd->cmdsize < 8) || (cmd->cmdsize > mh->sizeofcmds) )
-                       return 0;
-           cmd = (load_command*)((char *)cmd + cmd->cmdsize);
-               // <rdar://problem/14381579> bounds check
-               if ( (cmd > cmdsEnd) || (cmd < startCmds) )
-                       return 0;
+               cmd = nextCmd;
        }
        return 0;
 }
@@ -1106,7 +1093,7 @@ uint32_t
 _dyld_image_count(void)
 {
        DYLD_NO_LOCK_THIS_BLOCK;
-    static unsigned long (*p)(void) = NULL;
+    static uint32_t (*p)(void) = NULL;
 
        if(p == NULL)
            _dyld_func_lookup("__dyld_image_count", (void**)&p);
@@ -1181,17 +1168,6 @@ const void* address)
        return p(address);
 }
 
-void _dyld_moninit(
-void (*monaddition)(char *lowpc, char *highpc))
-{
-       DYLD_LOCK_THIS_BLOCK;
-       typedef void (*monproc)(char *lowpc, char *highpc);
-    static void (*p)(monproc monaddition) = NULL;
-
-       if(p == NULL)
-           _dyld_func_lookup("__dyld_moninit", (void**)&p);
-       p(monaddition);
-}
 
 #if DEPRECATED_APIS_SUPPORTED
 bool _dyld_launched_prebound(void)
@@ -1232,12 +1208,12 @@ static bool dlerrorPerThreadKeyInitialized = false;
 // data kept per-thread
 struct dlerrorPerThreadData
 {
-       uint32_t        sizeAllocated;
+       size_t          sizeAllocated;
        char            message[1];
 };
 
 // function called by dyld to get buffer to store dlerror message
-static char* getPerThreadBufferFor_dlerror(uint32_t sizeRequired)
+static char* getPerThreadBufferFor_dlerror(size_t sizeRequired)
 {
        // ok to create key lazily because this function is called within dyld lock, so there is no race condition
        if (!dlerrorPerThreadKeyInitialized ) {
@@ -1246,11 +1222,11 @@ static char* getPerThreadBufferFor_dlerror(uint32_t sizeRequired)
                dlerrorPerThreadKeyInitialized = true;
        }
 
-       const int size = (sizeRequired < 256) ? 256 : sizeRequired;
+       const size_t size = (sizeRequired < 256) ? 256 : sizeRequired;
        dlerrorPerThreadData* data = (dlerrorPerThreadData*)pthread_getspecific(dlerrorPerThreadKey);
        if ( data == NULL ) {
                //int mallocSize = offsetof(dlerrorPerThreadData, message[size]);
-               const int mallocSize = sizeof(dlerrorPerThreadData)+size;
+               const size_t mallocSize = sizeof(dlerrorPerThreadData)+size;
                data = (dlerrorPerThreadData*)malloc(mallocSize);
                data->sizeAllocated = size;
                pthread_setspecific(dlerrorPerThreadKey, data);
@@ -1258,7 +1234,7 @@ static char* getPerThreadBufferFor_dlerror(uint32_t sizeRequired)
        else if ( data->sizeAllocated < sizeRequired ) {
                free(data);
                //int mallocSize = offsetof(dlerrorPerThreadData, message[size]);
-               const int mallocSize = sizeof(dlerrorPerThreadData)+size;
+               const size_t mallocSize = sizeof(dlerrorPerThreadData)+size;
                data = (dlerrorPerThreadData*)malloc(mallocSize);
                data->sizeAllocated = size;
                pthread_setspecific(dlerrorPerThreadKey, data);
@@ -1307,7 +1283,7 @@ static void shared_cache_out_of_date()
 
 
 // the table passed to dyld containing thread helpers
-static dyld::LibSystemHelpers sHelpers = { 12, &dyldGlobalLockAcquire, &dyldGlobalLockRelease,
+static dyld::LibSystemHelpers sHelpers = { 13, &dyldGlobalLockAcquire, &dyldGlobalLockRelease,
                                                                        &getPerThreadBufferFor_dlerror, &malloc, &free, &__cxa_atexit,
                                                #if DYLD_SHARED_CACHE_SUPPORT
                                                                        &shared_cache_missing, &shared_cache_out_of_date,
@@ -1323,7 +1299,8 @@ static dyld::LibSystemHelpers sHelpers = { 12, &dyldGlobalLockAcquire, &dyldGlob
                                                                        &hasPerThreadBufferFor_dlerror,
                                                                        &isLaunchdOwned,
                                                                        &vm_allocate,
-                                                                       &mmap};
+                                                                       &mmap,
+                                                                       &__cxa_finalize_ranges};
 
 
 //
@@ -1434,7 +1411,7 @@ const struct dyld_all_image_infos* _dyld_get_all_image_infos()
        return p();
 }
 
-#if !__arm__
+#if SUPPORT_ZERO_COST_EXCEPTIONS
 bool _dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info)
 {
        DYLD_NO_LOCK_THIS_BLOCK;
@@ -1447,7 +1424,7 @@ bool _dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info)
 #endif
 
 
-#if __i386__ || __x86_64__ || __arm__
+#if __i386__ || __x86_64__ || __arm__ || __arm64__
 __attribute__((visibility("hidden"))) 
 void* _dyld_fast_stub_entry(void* loadercache, long lazyinfo)
 {
@@ -1471,7 +1448,6 @@ const char* dyld_image_path_containing_address(const void* addr)
        return p(addr);
 }
 
-#if __IPHONE_OS_VERSION_MIN_REQUIRED   
 bool dyld_shared_cache_some_image_overridden()
 {
        DYLD_NO_LOCK_THIS_BLOCK;
@@ -1481,7 +1457,6 @@ bool dyld_shared_cache_some_image_overridden()
            _dyld_func_lookup("__dyld_shared_cache_some_image_overridden", (void**)&p);
        return p();
 }
-#endif
 
 
 bool dyld_process_is_restricted()
@@ -1495,6 +1470,15 @@ bool dyld_process_is_restricted()
 }
 
 
+void dyld_dynamic_interpose(const struct mach_header* mh, const struct dyld_interpose_tuple array[], size_t count)
+{
+       DYLD_LOCK_THIS_BLOCK;
+    static void (*p)(const struct mach_header* mh, const struct dyld_interpose_tuple array[], size_t count) = NULL;
+
+       if (p == NULL)
+           _dyld_func_lookup("__dyld_dynamic_interpose", (void**)&p);
+       p(mh, array, count);
+}
 
 
 // SPI called __fork
index b015be520caf36423728f7655a4746433f2e2cf7..487835e4db9e55baa68b6606fb164fed83c70f5e 100644 (file)
@@ -35,6 +35,7 @@
 #include "mach-o/dyld_priv.h"
 #include "dyldLibSystemInterface.h"
 
+
 extern void _ZN4dyld3logEPKcz(const char*, ...);
 extern struct LibSystemHelpers* _ZN4dyld17gLibSystemHelpersE;
 
@@ -95,11 +96,10 @@ char* __cxa_get_globals_fast()
 
 
 
-
-#if !__arm__
+#if !__USING_SJLJ_EXCEPTIONS__
 //
-//  The intel versions of dyld uses zero-cost exceptions which are handled by
-//  linking with a special copy of libunwind.a
+//  When dyld uses zero-cost exceptions it just needs to implement 
+//  _dyld_find_unwind_sections to return sections inside dyld proper.
 //
 
 extern void*  ehStart  __asm("section$start$__TEXT$__eh_frame");
@@ -128,10 +128,11 @@ bool _dyld_find_unwind_sections(void* addr, struct dyld_unwind_sections* info)
        }
 }
 
-#endif // !__arm__
-
-
-#if __arm__
+#else
+//
+//  When dyld uses setjump-longjump exceptions it needs to implement 
+//  routines to push and pop a stack of _Unwind_FunctionContext.
+//
 
 struct _Unwind_FunctionContext
 {
index 7957c0c26b8ebecd054c702fcc283af44427e190..50d758da233013f0bd0c139e1a47bf8e13620342 100644 (file)
@@ -154,7 +154,7 @@ static void rebaseDyld(const struct macho_header* mh, intptr_t slide)
                                                const uint8_t type = sect->flags & SECTION_TYPE;
                                                if ( type == S_NON_LAZY_SYMBOL_POINTERS ) {
                                                        // rebase non-lazy pointers (which all point internal to dyld, since dyld uses no shared libraries)
-                                                       const uint32_t pointerCount = sect->size / sizeof(uintptr_t);
+                                                       const uint32_t pointerCount = (uint32_t)(sect->size / sizeof(uintptr_t));
                                                        uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + slide);
                                                        for (uint32_t j=0; j < pointerCount; ++j) {
                                                                symbolPointers[j] += slide;
index 20c6cdfec7e5c49a05153c6b0a6b265a4f168eb6..4b6a63820090c8db7f675a343d2cd94312dd1604 100644 (file)
 #include <stddef.h>
 #include <TargetConditionals.h>
 
-
-// simulator does not have full libdyld.dylib - just a small libdyld_sim.dylib
-#if ! TARGET_IPHONE_SIMULATOR
-
  
 //
 // This is the temporary private interface between libSystem.B.dylib and dyld
@@ -78,5 +74,3 @@ int _dyld_func_lookup(const char* dyld_func_name, void **address)
        return (*myDyldSection.lookup)(dyld_func_name, address);
 }
 
-#endif //! TARGET_IPHONE_SIMULATOR
-
index f191f78855ea104026870405e19aeb98b57b03be..f39a275d3b453d14659662f43e834d718cee8c64 100644 (file)
@@ -28,6 +28,8 @@
 
 #include <stdint.h>
 
+struct __cxa_range_t { const void* addr; size_t length; };
+
 #if __cplusplus
 namespace dyld {
 #endif
@@ -41,7 +43,7 @@ namespace dyld {
                uintptr_t       version;
                void            (*acquireGlobalDyldLock)();
                void            (*releaseGlobalDyldLock)();
-               char*           (*getThreadBufferFor_dlerror)(uint32_t sizeRequired);
+               char*           (*getThreadBufferFor_dlerror)(size_t sizeRequired);
                // addded in version 2
                void*           (*malloc)(size_t);
                void            (*free)(void*);
@@ -70,6 +72,8 @@ namespace dyld {
                // added in version 12
                kern_return_t (*vm_alloc)(vm_map_t task, vm_address_t* addr, vm_size_t size, int flags);
                void*           (*mmap)(void* addr, size_t len, int prot, int flags, int fd, off_t offset);
+               // added in version 13
+               void            (*cxa_finalize_ranges)(const struct __cxa_range_t ranges[], int count);
        };
 #if __cplusplus
 }
index bd99cde389be5b172abf0f92b9824e5df4b91c13..d68fc4e01479dc6b7667892f84ecaacc304ea200 100644 (file)
@@ -41,7 +41,7 @@ extern "C" void* __dso_handle;
 
 #if __LP64__
        // room for about ~1000 initial dylibs
-       #define DYLD_POOL_CHUNK_SIZE 224*1024
+       #define DYLD_POOL_CHUNK_SIZE 200*1024
 #else
        // room for about ~900 initial dylibs
        #define DYLD_POOL_CHUNK_SIZE 150*1024
@@ -102,8 +102,8 @@ void free(void* ptr)
        // ignore any pointer within dyld (i.e. stuff from pool or static strings)
        if ( (dyld::gLibSystemHelpers != NULL) && ((ptr < &__dso_handle) || (ptr >= &initialPoolContent[DYLD_POOL_CHUNK_SIZE])) ) {
                // ignore stuff in any dynamically alloated dyld pools
-               for (dyld_static_pool* p = initialPool.previousPool; p != NULL; p = p->previousPool) {
-                       if ( (p->pool < ptr) && (ptr < p->end) ) {
+               for (dyld_static_pool* p = currentPool; p != NULL; p = p->previousPool) {
+                       if ( (p->pool <= ptr) && (ptr < p->end) ) {
                                // do nothing, pool entries can't be reclaimed
                                //dyld::log("free(%p) from dynamic pool\n", ptr);
                                return;
index d340ee8392f6b23d54bb6cfe812ba688b08e52ae..58055cbb1b83f386f1f027037d98aee995ce8d19 100644 (file)
        .globl __dyld_start
 
 #ifdef __i386__
-#if !TARGET_IPHONE_SIMULATOR
-       .data
-__dyld_start_static_picbase: 
-       .long   L__dyld_start_picbase
-Lmh:   .long   ___dso_handle
-#endif
 
-       .text
-       .align 2
-# stable entry points into dyld
-       .globl  _stub_binding_helper
-_stub_binding_helper:
-       jmp     _stub_binding_helper_interface
-       nop
-       nop
-       nop
-       .globl  _dyld_func_lookup
-_dyld_func_lookup:
-       jmp     __Z18lookupDyldFunctionPKcPm
-       nop
-       nop
-       nop
-
-       # space for future stable entry points
-       .space  32
-
-       
 #if !TARGET_IPHONE_SIMULATOR
        .text
        .align  4, 0x90
@@ -151,11 +125,15 @@ Lapple:   movl    (%ebx),%ecx     # look for NULL ending env[] array
        pushl   %edx            # simulate return address into _start in libdyld
        jmp     *%eax           # jump to main(argc,argv,env,apple) with return address set to _start
 #endif 
-       
-       .globl dyld_stub_binding_helper
-dyld_stub_binding_helper:
-       hlt
-L_end:
+
+#if !TARGET_IPHONE_SIMULATOR
+       .data
+__dyld_start_static_picbase: 
+       .long   L__dyld_start_picbase
+Lmh:   .long   ___dso_handle
+#endif
+
+
 #endif /* __i386__ */
 
 
@@ -168,24 +146,6 @@ __dyld_start_static:
        .quad   __dyld_start
 #endif
 
-# stable entry points into dyld
-       .text
-       .align 2
-       .globl  _stub_binding_helper
-_stub_binding_helper:
-       jmp     _stub_binding_helper_interface
-       nop
-       nop
-       nop
-       .globl  _dyld_func_lookup
-_dyld_func_lookup:
-       jmp     __Z18lookupDyldFunctionPKcPm
-       nop
-       nop
-       nop
-
-       # space for future stable entry points
-       .space  24
 
 #if !TARGET_IPHONE_SIMULATOR
        .text
@@ -242,21 +202,6 @@ Lapple: movq       (%rcx),%r8
 __dyld_start_static_picbase: 
        .long   L__dyld_start_picbase
 
-       .text
-       .align 2
-       .globl  _stub_binding_helper
-_stub_binding_helper:
-       b       _stub_binding_helper_interface
-       nop 
-       
-       .globl  _dyld_func_lookup
-_dyld_func_lookup:
-       b       _branch_to_lookupDyldFunction
-       nop
-       
-       # space for future stable entry points
-       .space  24
-    
     
        // Hack to make ___dso_handle work
        // Without this local symbol, assembler will error out about in subtraction expression
@@ -319,28 +264,65 @@ Lapple:   ldr     r4, [r3]
 L__dyld_start_picbase_ptr:
        .long   __dyld_start_static_picbase-L__dyld_start_picbase
 Lmh:   .long   ___dso_handle-L3-8
-       
+
+#endif /* __arm__ */
+
+
+
+
+#if __arm64__
+       .data
+       .align 3
+__dso_static: 
+       .quad   ___dso_handle
+
        .text
        .align 2
-_branch_to_lookupDyldFunction:
-       // arm has no "bx label" instruction, so need this island in case lookupDyldFunction() is in thumb
-       ldr ip, L2
-L1:    ldr pc, [pc, ip]
-L2:    .long   _lookupDyldFunction_ptr-8-L1
-       
-       .data
-       .align 2
-_lookupDyldFunction_ptr:
-       .long   __Z18lookupDyldFunctionPKcPm
+       .globl __dyld_start
+__dyld_start:
+       mov     x28, sp
+       and     sp, x28, #~15           // force 16-byte alignment of stack
+       mov     x0, #0
+       mov     x1, #0
+       stp     x1, x0, [sp, #-16]!     // make aligned terminating frame
+       mov     fp, sp                  // set up fp to point to terminating frame
+       sub     sp, sp, #16             // make room for local variables
+       ldr     x0, [x28]               // get app's mh into x0
+       ldr     x1, [x28, #8]           // get argc into x1 (kernel passes 32-bit int argc as 64-bits on stack to keep alignment)
+       add     x2, x28, #16            // get argv into x2
+       adrp    x4,___dso_handle@page
+       add     x4,x4,___dso_handle@pageoff // get dyld's mh in to x4
+       adrp    x3,__dso_static@page
+       ldr     x3,[x3,__dso_static@pageoff] // get unslid start of dyld
+       sub     x3,x4,x3                // x3 now has slide of dyld
+       mov     x5,sp                   // x5 has &startGlue
        
-      
-       .text
-       .globl dyld_stub_binding_helper
-dyld_stub_binding_helper:
-       trap
+       // call dyldbootstrap::start(app_mh, argc, argv, slide, dyld_mh, &startGlue)
+       bl      __ZN13dyldbootstrap5startEPK12macho_headeriPPKclS2_Pm
+       mov     x16,x0                  // save entry point address in x16
+       ldr     x1, [sp]
+       cmp     x1, #0
+       b.ne    Lnew
+
+       // LC_UNIXTHREAD way, clean up stack and jump to result
+       add     sp, x28, #8             // restore unaligned stack pointer without app mh
+       br      x16                     // jump to the program's entry point
+
+       // LC_MAIN case, set up stack for call to main()
+Lnew:  mov     lr, x1              // simulate return address into _start in libdyld.dylib
+       ldr     x0, [x28, #8]       // main param1 = argc
+       add     x1, x28, #16        // main param2 = argv
+       add     x2, x1, x0, lsl #3  
+       add     x2, x2, #8          // main param3 = &env[0]
+       mov     x3, x2
+Lapple:        ldr     x4, [x3]
+       add     x3, x3, #8
+       cmp     x4, #0
+       b.ne    Lapple              // main param4 = apple
+       br      x16
+
+#endif // __arm64__
 
-L_end:
-#endif /* __arm__ */
 
 /*
  * dyld calls this function to terminate a process.
@@ -357,6 +339,8 @@ _dyld_fatal_error:
 #elif __x86_64__ || __i386__
     int3
     nop
+#elif __arm64__
+    brk        #3
 #else
     #error unknown architecture
 #endif
index a9bb0bf6c23938184ddd3c1b3aee6cb614d1a104..12be7db67af6d708ff685f47c13e57ace782ba55 100644 (file)
@@ -26,6 +26,7 @@
 #ifndef __DYLD_SYSCALL_HELPERS__
 #define __DYLD_SYSCALL_HELPERS__
 
+#include <dirent.h>
 
 #if __cplusplus
 namespace dyld {
@@ -67,6 +68,12 @@ namespace dyld {
                void*                   (*getProcessInfo)(void); // returns dyld_all_image_infos*;
                int*                    (*errnoAddress)();
                uint64_t                (*mach_absolute_time)();
+               // Added in version 2
+               kern_return_t   (*thread_switch)(mach_port_name_t, int, mach_msg_timeout_t);
+               // Added in version 3
+               DIR*                    (*opendir)(const char* path);
+               int                     (*readdir_r)(DIR* dirp, struct dirent* entry, struct dirent **result);
+               int                     (*closedir)(DIR* dirp);
        };
 
        extern const struct SyscallHelpers* gSyscallHelpers;
diff --git a/src/dyld_debug.c b/src/dyld_debug.c
deleted file mode 100644 (file)
index 8132b2c..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
- *
- * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-
-int dummy_dyld_symbol = 1;
-
index 3f1fa0e117cf34f18badc214f225aedf9c070e44..5f07dcfcf5c7c96435a532d7db2258611707aeb4 100644 (file)
@@ -61,7 +61,7 @@ void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[])
        // append all new images
        for (uint32_t i=0; i < infoCount; ++i)
                sImageInfos.push_back(info[i]);
-       dyld::gProcessInfo->infoArrayCount = sImageInfos.size();
+       dyld::gProcessInfo->infoArrayCount = (uint32_t)sImageInfos.size();
        
        // set infoArray back to base address of vector (other process can now read)
        dyld::gProcessInfo->infoArray = &sImageInfos[0];
@@ -79,7 +79,7 @@ void syncProcessInfo()
                                sImageInfos.push_back(dyld::gProcessInfo->infoArray[i]);
                        }
                        dyld::gProcessInfo->infoArray = &sImageInfos[0];
-                       dyld::gProcessInfo->infoArrayCount = sImageInfos.size();
+                       dyld::gProcessInfo->infoArrayCount = (uint32_t)sImageInfos.size();
                }
        }
        dyld::gProcessInfo->notification(dyld_image_info_change, 0, NULL);
@@ -127,7 +127,7 @@ void removeImageFromAllImages(const struct mach_header* loadAddress)
                        break;
                }
        }
-       dyld::gProcessInfo->infoArrayCount = sImageInfos.size();
+       dyld::gProcessInfo->infoArrayCount = (uint32_t)sImageInfos.size();
        
        // set infoArray back to base address of vector
        dyld::gProcessInfo->infoArray = &sImageInfos[0];
@@ -189,7 +189,8 @@ void setAlImageInfosHalt(const char* message, uintptr_t flags)
                                                                = { 
                                                                        14, 0, NULL, &gdb_image_notifier, false, false, (const mach_header*)&__dso_handle, NULL,
                                                                        XSTR(DYLD_VERSION), NULL, 0, NULL, 0, 0, NULL, &dyld_all_image_infos, 
-                                                                       0, dyld_error_kind_none, NULL, NULL, NULL, 0, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, 0
+                                                                       0, dyld_error_kind_none, NULL, NULL, NULL, 0, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, 
+                                                                       {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}
                                                                        };
 
        struct dyld_shared_cache_ranges dyld_shared_cache_ranges;
index 9949a879bc0b4355c71c525d965ae642c8bf0c5f..c4c45efef423c0d8dd7efccfedc8ab2eda871ba0 100644 (file)
@@ -25,9 +25,6 @@
  
 #include <System/machine/cpu_capabilities.h>
 
-// simulator does not have full libdyld.dylib - just a small libdyld_sim.dylib
-#if ! TARGET_IPHONE_SIMULATOR
-
 
 #ifdef __i386__
 
@@ -93,112 +90,164 @@ dyld_stub_binder_:
 
 #if __x86_64__
 
-#define MH_PARAM_BP                    8
-#define LP_PARAM_BP                    16
-
-#define RDI_SAVE                       0
-#define RSI_SAVE                       8
-#define RDX_SAVE                       16
-#define RCX_SAVE                       24
-#define R8_SAVE                                32
-#define R9_SAVE                                40
-#define RAX_SAVE                       48
-#define XMM0_SAVE                      64    /* 16-byte align */
-#define XMM1_SAVE                      80
-#define XMM2_SAVE                      96
-#define XMM3_SAVE                      112
-#define XMM4_SAVE                      128
-#define XMM5_SAVE                      144
-#define XMM6_SAVE                      160
-#define XMM7_SAVE                      176
-#define YMM0_SAVE                      64
-#define YMM1_SAVE                      96
-#define YMM2_SAVE                      128
-#define YMM3_SAVE                      160
-#define YMM4_SAVE                      192
-#define YMM5_SAVE                      224
-#define YMM6_SAVE                      256
-#define YMM7_SAVE                      288
-#define STACK_SIZE                     320 
+#define RET_ADDR_RBP                   24
+#define LP_PARAM_RBP                   16
+#define MH_PARAM_RBP                   8
+#define OLD_RBP_RBP                            0
+
+#define RDI_SAVE_RBP                   -8
+#define RSI_SAVE_RBP                   -16
+#define RDX_SAVE_RBP                   -24
+#define RCX_SAVE_RBP                   -32
+#define RBX_SAVE_RBP                   -40
+#define RAX_SAVE_RBP                   -48
+#define R8_SAVE_RBP                    -56
+#define R9_SAVE_RBP                    -64
+#define STATIC_STACK_SIZE              256     // extra padding to allow it to be 64-byte aligned
+
+#define XMM0_SAVE_RSP                  0x00
+#define XMM1_SAVE_RSP                  0x10
+#define XMM2_SAVE_RSP                  0x20
+#define XMM3_SAVE_RSP                  0x30
+#define XMM4_SAVE_RSP                  0x40
+#define XMM5_SAVE_RSP                  0x50
+#define XMM6_SAVE_RSP                  0x60
+#define XMM7_SAVE_RSP                  0x70
+
 
  /*    
- * sp+4        lazy binding info offset
- * sp+0        address of ImageLoader cache
+ * sp+16 return address
+ * sp+8  lazy binding info offset
+ * sp+0         address of ImageLoader cache
  */
     .align 2,0x90
     .globl dyld_stub_binder
 dyld_stub_binder:
        pushq           %rbp
+       test            $0xF,%rsp                               # at this point stack should be 16-byte aligned
+       jne                     _stack_not_16_byte_aligned_error
        movq            %rsp,%rbp
-       subq            $STACK_SIZE,%rsp        # at this point stack is 16-byte aligned because two meta-parameters where pushed
-       movq            %rdi,RDI_SAVE(%rsp)     # save registers that might be used as parameters
-       movq            %rsi,RSI_SAVE(%rsp)
-       movq            %rdx,RDX_SAVE(%rsp)
-       movq            %rcx,RCX_SAVE(%rsp)
-       movq            %r8,R8_SAVE(%rsp)
-       movq            %r9,R9_SAVE(%rsp)
-       movq            %rax,RAX_SAVE(%rsp)
-misaligned_stack_error_entering_dyld_stub_binder:
-       movq            $(_COMM_PAGE_CPU_CAPABILITIES), %rax
-       movl            (%rax), %eax
-       testl           $kHasAVX1_0, %eax
-       jne             L2
-       movdqa          %xmm0,XMM0_SAVE(%rsp)
-       movdqa          %xmm1,XMM1_SAVE(%rsp)
-       movdqa          %xmm2,XMM2_SAVE(%rsp)
-       movdqa          %xmm3,XMM3_SAVE(%rsp)
-       movdqa          %xmm4,XMM4_SAVE(%rsp)
-       movdqa          %xmm5,XMM5_SAVE(%rsp)
-       movdqa          %xmm6,XMM6_SAVE(%rsp)
-       movdqa          %xmm7,XMM7_SAVE(%rsp)
-       jmp             L3
-L2:    vmovdqu         %ymm0,YMM0_SAVE(%rsp)   # stack is only 16-byte aligned, so must use unaligned stores for avx registers
-       vmovdqu         %ymm1,YMM1_SAVE(%rsp)
-       vmovdqu         %ymm2,YMM2_SAVE(%rsp)
-       vmovdqu         %ymm3,YMM3_SAVE(%rsp)
-       vmovdqu         %ymm4,YMM4_SAVE(%rsp)
-       vmovdqu         %ymm5,YMM5_SAVE(%rsp)
-       vmovdqu         %ymm6,YMM6_SAVE(%rsp)
-       vmovdqu         %ymm7,YMM7_SAVE(%rsp)
-L3:
-dyld_stub_binder_:
-       movq            MH_PARAM_BP(%rbp),%rdi  # call fastBindLazySymbol(loadercache, lazyinfo)
-       movq            LP_PARAM_BP(%rbp),%rsi
+       subq            $STATIC_STACK_SIZE,%rsp
+       movq            %rdi,RDI_SAVE_RBP(%rbp) # save registers that might be used as parameters
+       movq            %rsi,RSI_SAVE_RBP(%rbp)
+       movq            %rdx,RDX_SAVE_RBP(%rbp)
+       movq            %rcx,RCX_SAVE_RBP(%rbp)
+       movq            %rbx,RBX_SAVE_RBP(%rbp)
+       movq            %rax,RAX_SAVE_RBP(%rbp)
+       movq            %r8, R8_SAVE_RBP(%rbp)
+       movq            %r9, R9_SAVE_RBP(%rbp)
+
+       cmpl            $0, _inited(%rip)
+       jne                     Linited
+       movl            $0x01,%eax
+       cpuid           # get cpu features to check on xsave instruction support
+       andl            $0x08000000,%ecx                # check OSXSAVE bit
+       movl            %ecx,_hasXSave(%rip)
+       cmpl            $0, %ecx
+       jne                     LxsaveInfo
+       movl            $1, _inited(%rip)
+       jmp                     Lsse
+
+LxsaveInfo:
+       movl            $0x0D,%eax
+       movl            $0x00,%ecx
+       cpuid           # get xsave parameter info
+       movl            %eax,_features_lo32(%rip)
+       movl            %edx,_features_hi32(%rip)
+       movl            %ecx,_bufferSize32(%rip)
+       movl            $1, _inited(%rip)
+
+Linited:
+       cmpl            $0, _hasXSave(%rip)
+       jne                     Lxsave
+
+Lsse:
+       subq            $128, %rsp
+       movdqa      %xmm0, XMM0_SAVE_RSP(%rsp)
+       movdqa      %xmm1, XMM1_SAVE_RSP(%rsp)
+       movdqa      %xmm2, XMM2_SAVE_RSP(%rsp)
+       movdqa      %xmm3, XMM3_SAVE_RSP(%rsp)
+       movdqa      %xmm4, XMM4_SAVE_RSP(%rsp)
+       movdqa      %xmm5, XMM5_SAVE_RSP(%rsp)
+       movdqa      %xmm6, XMM6_SAVE_RSP(%rsp)
+       movdqa      %xmm7, XMM7_SAVE_RSP(%rsp)
+       jmp                     Lbind
+
+Lxsave:
+       movl            _bufferSize32(%rip),%eax
+       movq            %rsp, %rdi
+       subq            %rax, %rdi                              # stack alloc buffer
+       andq            $-64, %rdi                              # 64-byte align stack
+       movq            %rdi, %rsp
+       # xsave requires buffer to be zero'ed out
+       movq            $0, %rcx
+       movq            %rdi, %r8
+       movq            %rdi, %r9
+       addq            %rax, %r9
+Lz:    movq            %rcx, (%r8)
+       addq            $8, %r8
+       cmpq            %r8,%r9
+       ja                      Lz
+
+       movl            _features_lo32(%rip),%eax
+       movl            _features_hi32(%rip),%edx
+       # call xsave with buffer on stack and eax:edx flag bits
+       # note: do not use xsaveopt, it assumes you are using the same
+       # buffer as previous xsaves, and this thread is on the same cpu.
+       xsave           (%rsp)
+
+Lbind:
+       movq            MH_PARAM_RBP(%rbp),%rdi # call fastBindLazySymbol(loadercache, lazyinfo)
+       movq            LP_PARAM_RBP(%rbp),%rsi
        call            __Z21_dyld_fast_stub_entryPvl
-       movq            %rax,%r11               # save target
-       movq            $(_COMM_PAGE_CPU_CAPABILITIES), %rax
-       movl            (%rax), %eax
-       testl           $kHasAVX1_0, %eax
-       jne             L4
-       movdqa          XMM0_SAVE(%rsp),%xmm0
-       movdqa          XMM1_SAVE(%rsp),%xmm1
-       movdqa          XMM2_SAVE(%rsp),%xmm2
-       movdqa          XMM3_SAVE(%rsp),%xmm3
-       movdqa          XMM4_SAVE(%rsp),%xmm4
-       movdqa          XMM5_SAVE(%rsp),%xmm5
-       movdqa          XMM6_SAVE(%rsp),%xmm6
-       movdqa          XMM7_SAVE(%rsp),%xmm7
-       jmp             L5
-L4:    vmovdqu         YMM0_SAVE(%rsp),%ymm0
-       vmovdqu         YMM1_SAVE(%rsp),%ymm1
-       vmovdqu         YMM2_SAVE(%rsp),%ymm2
-       vmovdqu         YMM3_SAVE(%rsp),%ymm3
-       vmovdqu         YMM4_SAVE(%rsp),%ymm4
-       vmovdqu         YMM5_SAVE(%rsp),%ymm5
-       vmovdqu         YMM6_SAVE(%rsp),%ymm6
-       vmovdqu         YMM7_SAVE(%rsp),%ymm7
-L5: movq               RDI_SAVE(%rsp),%rdi
-       movq            RSI_SAVE(%rsp),%rsi
-       movq            RDX_SAVE(%rsp),%rdx
-       movq            RCX_SAVE(%rsp),%rcx
-       movq            R8_SAVE(%rsp),%r8
-       movq            R9_SAVE(%rsp),%r9
-       movq            RAX_SAVE(%rsp),%rax
-       addq            $STACK_SIZE,%rsp
+       movq            %rax,%r11               # copy jump target
+
+       cmpl            $0, _hasXSave(%rip)
+       jne                     Lxrstror
+
+       movdqa      XMM0_SAVE_RSP(%rsp),%xmm0
+       movdqa      XMM1_SAVE_RSP(%rsp),%xmm1
+       movdqa      XMM2_SAVE_RSP(%rsp),%xmm2
+       movdqa      XMM3_SAVE_RSP(%rsp),%xmm3
+       movdqa      XMM4_SAVE_RSP(%rsp),%xmm4
+       movdqa      XMM5_SAVE_RSP(%rsp),%xmm5
+       movdqa      XMM6_SAVE_RSP(%rsp),%xmm6
+       movdqa      XMM7_SAVE_RSP(%rsp),%xmm7
+       jmp                     Ldone
+
+Lxrstror:
+       movl            _features_lo32(%rip),%eax
+       movl            _features_hi32(%rip),%edx
+       # call xsave with buffer on stack and eax:edx flag bits
+       xrstor          (%rsp)
+
+Ldone:
+       movq            RDI_SAVE_RBP(%rbp),%rdi
+       movq            RSI_SAVE_RBP(%rbp),%rsi
+       movq            RDX_SAVE_RBP(%rbp),%rdx
+       movq            RCX_SAVE_RBP(%rbp),%rcx
+       movq            RBX_SAVE_RBP(%rbp),%rbx
+       movq            RAX_SAVE_RBP(%rbp),%rax
+       movq            R8_SAVE_RBP(%rbp),%r8
+       movq            R9_SAVE_RBP(%rbp),%r9
+       movq            %rbp,%rsp
        popq            %rbp
        addq            $16,%rsp                # remove meta-parameters
-       jmp             *%r11                   # jmp to target
+       jmp                     *%r11                   # jmp to target
+
+_stack_not_16_byte_aligned_error:
+       movdqa      %xmm0, 0(%rsp)
+       int3
+
+       .data
+# Cached info from cpuid.  These must be lazily evaluated.
+# You cannot initalize these from _dyld_initializer() because
+# that function is called from another dylib...
+_inited:                       .long 0
+_features_lo32:                .long 0
+_features_hi32:                .long 0
+_bufferSize32:         .long 0
+_hasXSave:                     .long 0
 
 #endif
 
@@ -219,10 +268,17 @@ dyld_stub_binder:
        ldr     r0, [sp, #24]                   // move address ImageLoader cache to 1st parameter
        ldr     r1, [sp, #28]                   // move lazy info offset 2nd parameter
 
+#if __ARM_ARCH_7K__
+       vpush   {d0, d1, d2, d3, d4, d5, d6, d7}
+#endif
        // call dyld::fastBindLazySymbol(loadercache, lazyinfo)
        bl      __Z21_dyld_fast_stub_entryPvl
        mov     ip, r0                          // move the symbol`s address into ip
 
+#if __ARM_ARCH_7K__
+       vpop    {d0, d1, d2, d3, d4, d5, d6, d7}
+#endif
+
        ldmfd   sp!, {r0,r1,r2,r3,r7,lr}        // restore registers
        add     sp, sp, #8                      // remove meta-parameters
 
@@ -230,7 +286,50 @@ dyld_stub_binder:
 
 #endif /* __arm__ */
 
+
+#if __arm64__
+ /*    
+  * sp+0       lazy binding info offset
+  * sp+8       address of ImageLoader cache
+  */
+       .text
+       .align 2
+       .globl  dyld_stub_binder
+dyld_stub_binder:
+       stp             fp, lr, [sp, #-16]!
+       mov             fp, sp
+       sub             sp, sp, #240
+       stp             x0,x1, [fp, #-16]       ; x0-x7 are int parameter registers
+       stp             x2,x3, [fp, #-32]
+       stp             x4,x5, [fp, #-48]
+       stp             x6,x7, [fp, #-64]
+       stp             x8,x9, [fp, #-80]       ; x8 is used for struct returns
+       stp             q0,q1, [fp, #-128]      ; q0-q7 are vector/fp parameter registers
+       stp             q2,q3, [fp, #-160]
+       stp             q4,q5, [fp, #-192]
+       stp             q6,q7, [fp, #-224]
+
+       ldr             x0, [fp, #24]   ; move address ImageLoader cache to 1st parameter
+       ldr             x1, [fp, #16]   ; move lazy info offset 2nd parameter
+       ; call dyld::fastBindLazySymbol(loadercache, lazyinfo)
+       bl              __Z21_dyld_fast_stub_entryPvl
+       mov             x16,x0                  ; save target function address in lr
        
+       ; restore parameter registers
+       ldp             x0,x1, [fp, #-16]
+       ldp             x2,x3, [fp, #-32]
+       ldp             x4,x5, [fp, #-48]
+       ldp             x6,x7, [fp, #-64]
+       ldp             x8,x9, [fp, #-80]
+       ldp             q0,q1, [fp, #-128]
+       ldp             q2,q3, [fp, #-160]
+       ldp             q4,q5, [fp, #-192]
+       ldp             q6,q7, [fp, #-224]
        
-// simulator does not have full libdyld.dylib - just a small libdyld_sim.dylib
-#endif // ! TARGET_IPHONE_SIMULATOR
+       mov             sp, fp
+       ldp             fp, lr, [sp], #16
+       add             sp, sp, #16     ; remove meta-parameters
+       br              x16
+
+#endif
+
index 69b5f2283e596f9e9afab160b9730c61f007e02d..5616c87d709b3f418fb27468636877a11d0f0ad1 100644 (file)
 #include <pthread.h>
 #if TARGET_IPHONE_SIMULATOR
        #include "dyldSyscallInterface.h"
+       #include "dyld_images.h"
+       #include <mach-o/loader.h>
+       #include <mach-o/nlist.h>
+       #if __LP64__
+               #define LC_SEGMENT_COMMAND                      LC_SEGMENT_64
+               typedef struct segment_command_64       macho_segment_command;
+               typedef struct mach_header_64           macho_header;
+               typedef struct nlist_64                         macho_nlist;
+       #else
+               #define LC_SEGMENT_COMMAND                      LC_SEGMENT
+               typedef struct segment_command          macho_segment_command;
+               typedef struct mach_header                      macho_header;
+               typedef struct nlist                            macho_nlist;
+       #endif
 #endif
 
 // from _simple.h in libc
@@ -108,10 +122,12 @@ void __assert_rtn(const char* func, const char* file, int line, const char* fail
 }
 
 
+int    myfprintf(FILE* file, const char* format, ...) __asm("_fprintf");
+
 // called by libuwind code before aborting
 size_t fwrite(const void* ptr, size_t size, size_t nitme, FILE* stream)
 {
-       return fprintf(stream, "%s", (char*)ptr); 
+       return myfprintf(stream, "%s", (char*)ptr); 
 }
 
 // called by libuwind code before aborting
@@ -447,6 +463,109 @@ uint64_t mach_absolute_time(void) {
        return gSyscallHelpers->mach_absolute_time();
 } 
 
+DIR* opendir(const char* path) {
+       if ( gSyscallHelpers->version < 3 )
+               return NULL;
+       return gSyscallHelpers->opendir(path);
+}
+
+int    readdir_r(DIR* dirp, struct dirent* entry, struct dirent **result) {
+       if ( gSyscallHelpers->version < 3 )
+               return EPERM;
+       return gSyscallHelpers->readdir_r(dirp, entry, result);
+}
+
+int closedir(DIR* dirp) {
+       if ( gSyscallHelpers->version < 3 )
+               return EPERM;
+       return gSyscallHelpers->closedir(dirp);
+}
+
+
+typedef void (*LoadFuncPtr)(void* shm, void* image, uint64_t timestamp);
+typedef void (*UnloadFuncPtr)(void* shm, void* image);
+
+static LoadFuncPtr   sLoadPtr = NULL;
+static UnloadFuncPtr sUnloadPtr = NULL;
+
+// Lookup of coresymbolication functions in host dyld.
+static void findCSProcs() {
+       struct dyld_all_image_infos* imageInfo = (struct dyld_all_image_infos*)(gSyscallHelpers->getProcessInfo());
+       const struct mach_header* hostDyldMH = imageInfo->dyldImageLoadAddress;
+
+       // find symbol table and slide of host dyld
+       uintptr_t slide = 0;
+       const macho_nlist* symbolTable = NULL;
+       const char* symbolTableStrings = NULL;
+       const struct dysymtab_command* dynSymbolTable = NULL;
+       const uint32_t cmd_count = hostDyldMH->ncmds;
+       const struct load_command* const cmds = (struct load_command*)(((char*)hostDyldMH)+sizeof(macho_header));
+       const struct load_command* cmd = cmds;
+       const uint8_t* linkEditBase = NULL;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               switch (cmd->cmd) {
+                       case LC_SEGMENT_COMMAND:
+                               {
+                                       const macho_segment_command* seg = (macho_segment_command*)cmd;
+                                       if ( (seg->fileoff == 0) && (seg->filesize != 0) )
+                                               slide = (uintptr_t)hostDyldMH - seg->vmaddr;
+                                       if ( strcmp(seg->segname, "__LINKEDIT") == 0 )
+                                               linkEditBase = (uint8_t*)(seg->vmaddr - seg->fileoff + slide);
+                               }
+                               break;
+                       case LC_SYMTAB:
+                               {
+                                       const struct symtab_command* symtab = (struct symtab_command*)cmd;
+                                       if ( linkEditBase == NULL )
+                                               return;
+                                       symbolTableStrings = (const char*)&linkEditBase[symtab->stroff];
+                                       symbolTable = (macho_nlist*)(&linkEditBase[symtab->symoff]);
+                               }
+                               break;
+                       case LC_DYSYMTAB:
+                               dynSymbolTable = (struct dysymtab_command*)cmd;
+                               break;
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+       }
+       if ( symbolTableStrings == NULL )
+               return;
+       if ( dynSymbolTable == NULL )
+               return;
+
+       // scan local symbols in host dyld looking for load/unload functions
+       const macho_nlist* const localsStart = &symbolTable[dynSymbolTable->ilocalsym];
+       const macho_nlist* const localsEnd= &localsStart[dynSymbolTable->nlocalsym];
+       for (const macho_nlist* s = localsStart; s < localsEnd; ++s) {
+               if ( ((s->n_type & N_TYPE) == N_SECT) && ((s->n_type & N_STAB) == 0) ) {
+                       const char* name = &symbolTableStrings[s->n_un.n_strx];
+                       if ( strcmp(name, "__Z28coresymbolication_load_imageP25CSCppDyldSharedMemoryPagePK11ImageLoadery") == 0 )
+                               sLoadPtr = (LoadFuncPtr)(s->n_value + slide);
+                       else if ( strcmp(name, "__Z30coresymbolication_unload_imageP25CSCppDyldSharedMemoryPagePK11ImageLoader") == 0 )
+                               sUnloadPtr = (UnloadFuncPtr)(s->n_value + slide);
+               }
+       }
+}
+
+//void coresymbolication_unload_image(void*, const ImageLoader*);
+void _Z28coresymbolication_load_imagePvPK11ImageLoadery(void* shm, void* image, uint64_t time) {
+       // look up function in host dyld just once
+       if ( sLoadPtr == NULL ) 
+               findCSProcs();
+       if ( sLoadPtr != NULL ) 
+               (*sLoadPtr)(shm, image, time);
+} 
+
+//void coresymbolication_load_image(void**, const ImageLoader*, uint64_t);
+void _Z30coresymbolication_unload_imagePvPK11ImageLoader(void* shm, void* image) {
+       // look up function in host dyld just once
+       if ( sUnloadPtr == NULL ) 
+               findCSProcs();
+       if ( sUnloadPtr != NULL ) 
+               (*sUnloadPtr)(shm, image);
+}
+
+
 int* __error(void) {
        return gSyscallHelpers->errnoAddress();
 } 
@@ -454,7 +573,6 @@ int* __error(void) {
 void mach_init() {
        mach_task_self_ = task_self_trap();
        //_task_reply_port = _mach_reply_port();
-       
 }
 
 mach_port_t mach_task_self_ = MACH_PORT_NULL;
index 4e21bec42a8c07780c72e5a030262fd693db0422..57b03c1d0486aba384929c1681134278da5a95aa 100644 (file)
@@ -32,6 +32,8 @@ extern "C" void start();
 
 #if __x86_64__ || __i386__ 
        #define address_of_start (void*)((uintptr_t)&start + 1)
+#elif __arm64__
+       #define address_of_start (void*)((uintptr_t)&start + 4)
 #elif __arm__
        #define address_of_start (void*)((uintptr_t)&start + 2)
 #endif
index b35eb50a2b4e7be57cfa9aaa0fde55d8166b0466..3336f66ed03f08fb2805946ea4f657d74e744388 100644 (file)
@@ -68,5 +68,19 @@ Lstart:
  
 #endif /* __arm__ */
 
+
+#if __arm64__
+    .align 2
+    .globl _start
+    .private_extern _start
+_start:
+       nop
+Lstart:
+       bl      _exit                   // result in x0 already in param reg x0
+       brk     #3
+
+#endif /* __arm64__ */
+
        .subsections_via_symbols
        
index 843347563f632caab32fab64675297c08ad3ac9a..b00937e2cc5147295d94b04049a5a22c2f58bfb5 100644 (file)
 
     .text
     .align 4,0x90
-       .globl _fast_stub_binding_helper_interface
-_fast_stub_binding_helper_interface:
+       .globl _stub_binding_helper_i386_old
+_stub_binding_helper_i386_old:
        pushl           $0
-    .globl _stub_binding_helper_interface
+    .globl _stub_binding_helper
     .globl _misaligned_stack_error
-_stub_binding_helper_interface:
+_stub_binding_helper:
        subl            $STACK_SIZE,%esp            # makes stack 16-byte aligned
        movl            %eax,EAX_SAVE(%esp)     
        movl            LP_OLD_BP_SAVE(%esp),%eax   # get lazy-pointer meta-parameter
@@ -133,8 +133,8 @@ _stub_binding_helper_interface2:
     
     .text
     .align 2,0x90
-    .globl _stub_binding_helper_interface
-_stub_binding_helper_interface:
+    .globl _stub_binding_helper
+_stub_binding_helper:
        pushq           %rbp
        movq            %rsp,%rbp
        subq            $STACK_SIZE,%rsp        # at this point stack is 16-byte aligned because two meta-parameters where pushed
@@ -196,8 +196,8 @@ _stub_binding_helper_interface:
   
        .text
        .align 2
-       .globl  _stub_binding_helper_interface
-_stub_binding_helper_interface:
+       .globl  _stub_binding_helper
+_stub_binding_helper:
        stmfd   sp!, {r0,r1,r2,r3,r7,lr}        // save registers
        add     r7, sp, #16                     // point FP to previous FP
 
index 7830d8db6489bcaf255203d753814075d334111a..625c320c4c33a047772a6f06928e7bc77508963d 100644 (file)
 // bool save_xxm = (*((uint32_t*)_COMM_PAGE_CPU_CAPABILITIES) & kHasAVX1_0) != 0;
 
 #if __x86_64__
-       // returns address of TLV in %rax, all other registers preserved
-       #define FP_SAVE                 -192
-       #define VECTOR_SAVE             -704
-       #define STACK_SIZE              704
 
+#define RDI_SAVE_RBP                   -8
+#define RSI_SAVE_RBP                   -16
+#define RDX_SAVE_RBP                   -24
+#define RCX_SAVE_RBP                   -32
+#define RBX_SAVE_RBP                   -40
+#define R8_SAVE_RBP                    -48
+#define R9_SAVE_RBP                    -56
+#define R10_SAVE_RBP                   -64
+#define R11_SAVE_RBP                   -72
+#define STATIC_STACK_SIZE              256     // extra padding to allow it to be 64-byte aligned
+
+#define XMM0_SAVE_RSP                  0x00
+#define XMM1_SAVE_RSP                  0x10
+#define XMM2_SAVE_RSP                  0x20
+#define XMM3_SAVE_RSP                  0x30
+#define XMM4_SAVE_RSP                  0x40
+#define XMM5_SAVE_RSP                  0x50
+#define XMM6_SAVE_RSP                  0x60
+#define XMM7_SAVE_RSP                  0x70
+
+
+       // returns address of TLV in %rax, all other registers preserved
        .globl _tlv_get_addr
        .private_extern _tlv_get_addr
 _tlv_get_addr:
@@ -41,109 +59,127 @@ _tlv_get_addr:
        addq    16(%rdi),%rax                   // add offset from descriptor
        ret
 LlazyAllocate:
-       pushq   %rbp
-       movq    %rsp, %rbp
-       subq    $STACK_SIZE,%rsp                                // fxsave uses 512 bytes of store, xsave uses 
-       movq    %rdi,-8(%rbp)
-       movq    %rsi,-16(%rbp)
-       movq    %rdx,-24(%rbp)
-       movq    %rcx,-32(%rbp)
-       movq    %r8,-40(%rbp)
-       movq    %r9,-48(%rbp)
-       movq    %r10,-56(%rbp)
-       movq    %r11,-64(%rbp)
-       fnsave  FP_SAVE(%rbp)
-       movq    $(_COMM_PAGE_CPU_CAPABILITIES), %rcx
-       movl    (%rcx), %ecx
-       testl   $kHasAVX1_0, %ecx
-       jne     L2
-       movdqa  %xmm0, VECTOR_SAVE+0x00(%rbp)
-       movdqa  %xmm1, VECTOR_SAVE+0x10(%rbp)
-       movdqa  %xmm2, VECTOR_SAVE+0x20(%rbp)
-       movdqa  %xmm3, VECTOR_SAVE+0x30(%rbp)
-       movdqa  %xmm4, VECTOR_SAVE+0x40(%rbp)
-       movdqa  %xmm5, VECTOR_SAVE+0x50(%rbp)
-       movdqa  %xmm6, VECTOR_SAVE+0x60(%rbp)
-       movdqa  %xmm7, VECTOR_SAVE+0x70(%rbp)
-       movdqa  %xmm8, VECTOR_SAVE+0x80(%rbp)
-       movdqa  %xmm9, VECTOR_SAVE+0x90(%rbp)
-       movdqa  %xmm10,VECTOR_SAVE+0xA0(%rbp)
-       movdqa  %xmm11,VECTOR_SAVE+0xB0(%rbp)
-       movdqa  %xmm12,VECTOR_SAVE+0xC0(%rbp)
-       movdqa  %xmm13,VECTOR_SAVE+0xD0(%rbp)
-       movdqa  %xmm14,VECTOR_SAVE+0xE0(%rbp)
-       movdqa  %xmm15,VECTOR_SAVE+0xF0(%rbp)
-       jmp             L3
-L2:    vmovdqu %ymm0, VECTOR_SAVE+0x00(%rbp)
-       vmovdqu %ymm1, VECTOR_SAVE+0x20(%rbp)
-       vmovdqu %ymm2, VECTOR_SAVE+0x40(%rbp)
-       vmovdqu %ymm3, VECTOR_SAVE+0x60(%rbp)
-       vmovdqu %ymm4, VECTOR_SAVE+0x80(%rbp)
-       vmovdqu %ymm5, VECTOR_SAVE+0xA0(%rbp)
-       vmovdqu %ymm6, VECTOR_SAVE+0xC0(%rbp)
-       vmovdqu %ymm7, VECTOR_SAVE+0xE0(%rbp)
-       vmovdqu %ymm8, VECTOR_SAVE+0x100(%rbp)
-       vmovdqu %ymm9, VECTOR_SAVE+0x120(%rbp)
-       vmovdqu %ymm10,VECTOR_SAVE+0x140(%rbp)
-       vmovdqu %ymm11,VECTOR_SAVE+0x160(%rbp)
-       vmovdqu %ymm12,VECTOR_SAVE+0x180(%rbp)
-       vmovdqu %ymm13,VECTOR_SAVE+0x1A0(%rbp)
-       vmovdqu %ymm14,VECTOR_SAVE+0x1C0(%rbp)
-       vmovdqu %ymm15,VECTOR_SAVE+0x1E0(%rbp)
-L3:    movq    -32(%rbp),%rcx
-       movq    8(%rdi),%rdi                    // get key from descriptor
-       call    _tlv_allocate_and_initialize_for_key
+       pushq           %rbp
+       movq            %rsp,%rbp
+       subq            $STATIC_STACK_SIZE,%rsp
+       movq            %rdi,RDI_SAVE_RBP(%rbp) # save registers that might be used as parameters
+       movq            %rsi,RSI_SAVE_RBP(%rbp)
+       movq            %rdx,RDX_SAVE_RBP(%rbp)
+       movq            %rcx,RCX_SAVE_RBP(%rbp)
+       movq            %rbx,RBX_SAVE_RBP(%rbp)
+       movq            %r8,  R8_SAVE_RBP(%rbp)
+       movq            %r9,  R9_SAVE_RBP(%rbp)
+       movq            %r10,R10_SAVE_RBP(%rbp)
+       movq            %r11,R11_SAVE_RBP(%rbp)
+
+       cmpl            $0, _inited(%rip)
+       jne                     Linited
+       movl            $0x01,%eax
+       cpuid           # get cpu features to check on xsave instruction support
+       andl            $0x08000000,%ecx                # check OSXSAVE bit
+       movl            %ecx,_hasXSave(%rip)
+       cmpl            $0, %ecx
+       jne                     LxsaveInfo
+       movl            $1, _inited(%rip)
+       jmp                     Lsse
+
+LxsaveInfo:
+       movl            $0x0D,%eax
+       movl            $0x00,%ecx
+       cpuid           # get xsave parameter info
+       movl            %eax,_features_lo32(%rip)
+       movl            %edx,_features_hi32(%rip)
+       movl            %ecx,_bufferSize32(%rip)
+       movl            $1, _inited(%rip)
+
+Linited:
+       cmpl            $0, _hasXSave(%rip)
+       jne                     Lxsave
+
+Lsse:
+       subq            $128, %rsp
+       movdqa      %xmm0, XMM0_SAVE_RSP(%rsp)
+       movdqa      %xmm1, XMM1_SAVE_RSP(%rsp)
+       movdqa      %xmm2, XMM2_SAVE_RSP(%rsp)
+       movdqa      %xmm3, XMM3_SAVE_RSP(%rsp)
+       movdqa      %xmm4, XMM4_SAVE_RSP(%rsp)
+       movdqa      %xmm5, XMM5_SAVE_RSP(%rsp)
+       movdqa      %xmm6, XMM6_SAVE_RSP(%rsp)
+       movdqa      %xmm7, XMM7_SAVE_RSP(%rsp)
+       jmp                     Lalloc
+
+Lxsave:
+       movl            _bufferSize32(%rip),%eax
+       movq            %rsp, %rdi
+       subq            %rax, %rdi                              # stack alloc buffer
+       andq            $-64, %rdi                              # 64-byte align stack
+       movq            %rdi, %rsp
+       # xsave requires buffer to be zero'ed out
+       movq            $0, %rcx
+       movq            %rdi, %r8
+       movq            %rdi, %r9
+       addq            %rax, %r9
+Lz:    movq            %rcx, (%r8)
+       addq            $8, %r8
+       cmpq            %r8,%r9
+       ja                      Lz
+
+       movl            _features_lo32(%rip),%eax
+       movl            _features_hi32(%rip),%edx
+       # call xsave with buffer on stack and eax:edx flag bits
+       # note: do not use xsaveopt, it assumes you are using the same
+       # buffer as previous xsaves, and this thread is on the same cpu.
+       xsave           (%rsp)
+
+Lalloc:
+       movq            RDI_SAVE_RBP(%rbp),%rdi
+       movq            8(%rdi),%rdi            // get key from descriptor
+       call            _tlv_allocate_and_initialize_for_key
+
+       cmpl            $0, _hasXSave(%rip)
+       jne                     Lxrstror
+
+       movdqa      XMM0_SAVE_RSP(%rsp),%xmm0
+       movdqa      XMM1_SAVE_RSP(%rsp),%xmm1
+       movdqa      XMM2_SAVE_RSP(%rsp),%xmm2
+       movdqa      XMM3_SAVE_RSP(%rsp),%xmm3
+       movdqa      XMM4_SAVE_RSP(%rsp),%xmm4
+       movdqa      XMM5_SAVE_RSP(%rsp),%xmm5
+       movdqa      XMM6_SAVE_RSP(%rsp),%xmm6
+       movdqa      XMM7_SAVE_RSP(%rsp),%xmm7
+       jmp                     Ldone
 
-       frstor  FP_SAVE(%rbp)
-       movq    $(_COMM_PAGE_CPU_CAPABILITIES), %rcx
-       movl    (%rcx), %ecx
-       testl   $kHasAVX1_0, %ecx
-       jne     L4
-       movdqa  VECTOR_SAVE+0x00(%rbp), %xmm0
-       movdqa  VECTOR_SAVE+0x10(%rbp), %xmm1
-       movdqa  VECTOR_SAVE+0x20(%rbp), %xmm2
-       movdqa  VECTOR_SAVE+0x30(%rbp), %xmm3
-       movdqa  VECTOR_SAVE+0x40(%rbp), %xmm4
-       movdqa  VECTOR_SAVE+0x50(%rbp), %xmm5
-       movdqa  VECTOR_SAVE+0x60(%rbp), %xmm6
-       movdqa  VECTOR_SAVE+0x70(%rbp), %xmm7
-       movdqa  VECTOR_SAVE+0x80(%rbp), %xmm8
-       movdqa  VECTOR_SAVE+0x90(%rbp), %xmm9
-       movdqa  VECTOR_SAVE+0xA0(%rbp), %xmm10
-       movdqa  VECTOR_SAVE+0xB0(%rbp), %xmm11
-       movdqa  VECTOR_SAVE+0xC0(%rbp), %xmm12
-       movdqa  VECTOR_SAVE+0xD0(%rbp), %xmm13
-       movdqa  VECTOR_SAVE+0xE0(%rbp), %xmm14
-       movdqa  VECTOR_SAVE+0xF0(%rbp), %xmm15
-       jmp             L5
-L4: vmovdqu    VECTOR_SAVE+0x00(%rbp),  %ymm0
-       vmovdqu VECTOR_SAVE+0x20(%rbp),  %ymm1
-       vmovdqu VECTOR_SAVE+0x40(%rbp),  %ymm2
-       vmovdqu VECTOR_SAVE+0x60(%rbp),  %ymm3
-       vmovdqu VECTOR_SAVE+0x80(%rbp),  %ymm4
-       vmovdqu VECTOR_SAVE+0xA0(%rbp),  %ymm5
-       vmovdqu VECTOR_SAVE+0xC0(%rbp),  %ymm6
-       vmovdqu VECTOR_SAVE+0xE0(%rbp),  %ymm7
-       vmovdqu VECTOR_SAVE+0x100(%rbp), %ymm8
-       vmovdqu VECTOR_SAVE+0x120(%rbp), %ymm9
-       vmovdqu VECTOR_SAVE+0x140(%rbp), %ymm10
-       vmovdqu VECTOR_SAVE+0x160(%rbp), %ymm11
-       vmovdqu VECTOR_SAVE+0x180(%rbp), %ymm12
-       vmovdqu VECTOR_SAVE+0x1A0(%rbp), %ymm13
-       vmovdqu VECTOR_SAVE+0x1C0(%rbp), %ymm14
-       vmovdqu VECTOR_SAVE+0x1E0(%rbp), %ymm15
-L5:    movq    -64(%rbp),%r11
-       movq    -56(%rbp),%r10
-       movq    -48(%rbp),%r9
-       movq    -40(%rbp),%r8
-       movq    -32(%rbp),%rcx
-       movq    -24(%rbp),%rdx
-       movq    -16(%rbp),%rsi
-       movq    -8(%rbp),%rdi
-       addq    16(%rdi),%rax                   // result = buffer + offset
-       addq    $STACK_SIZE,%rsp
-       popq    %rbp
+Lxrstror:
+       movq            %rax,%r11
+       movl            _features_lo32(%rip),%eax
+       movl            _features_hi32(%rip),%edx
+       # call xsave with buffer on stack and eax:edx flag bits
+       xrstor          (%rsp)
+       movq            %r11,%rax
+
+Ldone:
+       movq            RDI_SAVE_RBP(%rbp),%rdi
+       movq            RSI_SAVE_RBP(%rbp),%rsi
+       movq            RDX_SAVE_RBP(%rbp),%rdx
+       movq            RCX_SAVE_RBP(%rbp),%rcx
+       movq            RBX_SAVE_RBP(%rbp),%rbx
+       movq            R8_SAVE_RBP(%rbp),%r8
+       movq            R9_SAVE_RBP(%rbp),%r9
+       movq            R10_SAVE_RBP(%rbp),%r10
+       movq            R11_SAVE_RBP(%rbp),%r11
+       movq            %rbp,%rsp
+       popq            %rbp
+       addq            16(%rdi),%rax                   // result = buffer + offset
        ret
+
+       .data
+# Cached info from cpuid.
+_inited:                       .long 0
+_features_lo32:                .long 0
+_features_hi32:                .long 0
+_bufferSize32:         .long 0
+_hasXSave:                     .long 0
+
 #endif
 
 
@@ -184,6 +220,65 @@ LlazyAllocate:
        ret
 #endif
 
+#if __arm64__
+       // Parameters: X0 = descriptor
+       // Result:  X0 = address of TLV
+       // Note: all registers except X0, x16, and x17 are preserved
+       .align 2
+       .globl _tlv_get_addr
+       .private_extern _tlv_get_addr
+_tlv_get_addr:
+       ldr             x16, [x0, #8]                   // get key from descriptor
+       mrs             x17, TPIDRRO_EL0
+       and             x17, x17, #-8                   // clear low 3 bits???
+       ldr             x17, [x17, x16, lsl #3] // get thread allocation address for this key
+       cbz             x17, LlazyAllocate              // if NULL, lazily allocate
+       ldr             x16, [x0, #16]                  // get offset from descriptor
+       add             x0, x17, x16                    // return allocation+offset
+       ret             lr
+
+LlazyAllocate:
+       stp             fp, lr, [sp, #-16]!
+       mov             fp, sp
+       sub             sp, sp, #288
+       stp             x1, x2, [sp, #-16]!             // save all registers that C function might trash
+       stp             x3, x4, [sp, #-16]!
+       stp             x5, x6, [sp, #-16]!
+       stp             x7, x8, [sp, #-16]!
+       stp             x9, x10,  [sp, #-16]!
+       stp             x11, x12, [sp, #-16]!
+       stp             x13, x14, [sp, #-16]!
+       stp             x15, x16, [sp, #-16]!
+       stp             q0,  q1,  [sp, #-32]!
+       stp             q2,  q3,  [sp, #-32]!
+       stp             q4,  q5,  [sp, #-32]!
+       stp             q6,  q7,  [sp, #-32]!
+       stp             x0, x17,  [sp, #-16]!   // save descriptor
+
+       mov             x0, x16                                 // use key from descriptor as parameter
+       bl              _tlv_allocate_and_initialize_for_key
+       ldp             x16, x17, [sp], #16             // pop descriptor
+       ldr             x16, [x16, #16]                 // get offset from descriptor
+       add             x0, x0, x16                             // return allocation+offset
+
+       ldp             q6,  q7,  [sp], #32
+       ldp             q4,  q5,  [sp], #32
+       ldp             q2,  q3,  [sp], #32
+       ldp             q0,  q1,  [sp], #32
+       ldp             x15, x16, [sp], #16
+       ldp             x13, x14, [sp], #16
+       ldp             x11, x12, [sp], #16
+       ldp             x9, x10,  [sp], #16
+       ldp             x7, x8, [sp], #16
+       ldp             x5, x6, [sp], #16
+       ldp             x3, x4, [sp], #16
+       ldp             x1, x2, [sp], #16
+
+       mov             sp, fp
+       ldp             fp, lr, [sp], #16
+       ret             lr
+
+#endif
 
 #if 0
 #if __arm__
index b5fcd6d7815505b2d2bbdef34bcf6275b4b6dac0..01a73eb4602bd68cd2dd5dfa22b36165633c2701 100644 (file)
@@ -78,7 +78,7 @@ typedef void (*TermFunc)(void*);
 
 
 
-#if __has_feature(tls)
+#if __has_feature(tls) || __arm64__
 
 typedef struct TLVHandler {
        struct TLVHandler *next;
@@ -237,8 +237,8 @@ void* tlv_allocate_and_initialize_for_key(pthread_key_t key)
                                        if ( (sect->flags & SECTION_TYPE) == S_THREAD_LOCAL_INIT_FUNCTION_POINTERS ) {
                                                typedef void (*InitFunc)(void);
                                                InitFunc* funcs = (InitFunc*)(sect->addr + slide);
-                                               const uint32_t count = sect->size / sizeof(uintptr_t);
-                                               for (uint32_t i=count; i > 0; --i) {
+                                               const size_t count = sect->size / sizeof(uintptr_t);
+                                               for (size_t i=count; i > 0; --i) {
                                                        InitFunc func = funcs[i-1];
                                                        func();
                                                }
@@ -401,7 +401,7 @@ void _tlv_atexit(TermFunc func, void* objAddr)
         if ( list->allocCount == list->allocCount ) {
             // handle resizing allocation 
             uint32_t newAllocCount = list->allocCount * 2;
-            uint32_t newAllocSize = offsetof(struct TLVTerminatorList, entries[newAllocCount]);
+            size_t newAllocSize = offsetof(struct TLVTerminatorList, entries[newAllocCount]);
             struct TLVTerminatorList* newlist = (struct TLVTerminatorList*)malloc(newAllocSize);
             newlist->allocCount = newAllocCount;
             newlist->useCount = list->useCount;
index d6d19fcfd59c5a978b18bb0365083e7b6b3e5bdd..93cb583f8df889df0fe386b659a0feb092d841cd 100755 (executable)
@@ -17,9 +17,9 @@ echo "#!/bin/sh" > /var/root/testing/run-all-tests
 chmod +x /var/root/testing/run-all-tests
 
 # do every combination of OS version and architectures
-for os in "6.0" "3.0" 
+for os in "7.0" 
 do
-       for arch in armv7 armv6 thumb
+       for arch in armv7 arm64
        do
                # make copy of tests
                cp -r ${TEST_CASE_DIR}/../../unit-tests  /var/root/testing/unit-tests-${arch}-${os}
index 36b4ed92dcbc55f24acf0ed42d27e8ebe748eb47..40cfde7bdb6fe64594949a7a4975f4f8632fe78a 100644 (file)
@@ -24,7 +24,7 @@ IOSROOT       =
 
 ifeq "$(OS_NAME)" "iPhoneOS"
        #IOSROOT                = $(shell xcodebuild -version -sdk iphoneos.internal Path)
-       IOSROOT         = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.0.Internal.sdk
+       IOSROOT         = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.0.Internal.sdk
        CC                      = $(shell xcrun -sdk iphoneos.internal -find cc)  -arch ${ARCH} -miphoneos-version-min=$(OS_VERSION) -isysroot $(IOSROOT)
        CXX                     = $(shell xcrun -sdk iphoneos.internal -find c++) -arch ${ARCH} -miphoneos-version-min=$(OS_VERSION) -isysroot $(IOSROOT)
        LIPO            = $(shell xcrun -sdk iphoneos.internal -find lipo)
diff --git a/unit-tests/test-cases/dlclose-order/Makefile b/unit-tests/test-cases/dlclose-order/Makefile
new file mode 100644 (file)
index 0000000..6447f72
--- /dev/null
@@ -0,0 +1,49 @@
+##
+# Copyright (c) 2013 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+# foo depends on bar depends on baz
+# foo links with baz then bar
+# verify that baz terminators run before bar terminators
+
+
+all-check: all check
+
+check:
+       ./main libfoo.dylib
+       ./main libfoo2.dylib
+
+all:
+       ${CC} ${CCFLAGS}   -dynamiclib base.c -o libbase.dylib
+       ${CXX} ${CXXFLAGS} -dynamiclib baz.cxx libbase.dylib -o libbaz.dylib
+       ${CXX} ${CXXFLAGS} -dynamiclib bar.cxx libbaz.dylib libbase.dylib -o libbar.dylib
+       ${CC} ${CCFLAGS}   -dynamiclib foo.c libbar.dylib libbaz.dylib  -o libfoo.dylib
+       ${CC} ${CCFLAGS}   -dynamiclib foo.c libbaz.dylib libbar.dylib  -o libfoo2.dylib
+       ${CC} ${CCFLAGS}   main.c libbase.dylib -I${TESTROOT}/include  -o main
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libfoo.dylib libfoo2.dylib libbaz.dylib libbar.dylib libbase.dylib
+       
+
diff --git a/unit-tests/test-cases/dlclose-order/bar.cxx b/unit-tests/test-cases/dlclose-order/bar.cxx
new file mode 100644 (file)
index 0000000..94fddfe
--- /dev/null
@@ -0,0 +1,12 @@
+#include "base.h"
+
+
+class Bar {
+public:
+       Bar() { if ( bazInitied) barInitied = true; }
+       ~Bar() { if ( barInitied && !bazTeminated ) barTeminated = true; }
+};
+
+
+Bar bar;
+
diff --git a/unit-tests/test-cases/dlclose-order/base.c b/unit-tests/test-cases/dlclose-order/base.c
new file mode 100644 (file)
index 0000000..d128ed8
--- /dev/null
@@ -0,0 +1,8 @@
+#include "base.h"
+
+bool barInitied   = false;
+bool barTeminated = false;
+
+bool bazInitied   = false;
+bool bazTeminated = false;
+
diff --git a/unit-tests/test-cases/dlclose-order/base.h b/unit-tests/test-cases/dlclose-order/base.h
new file mode 100644 (file)
index 0000000..75b5960
--- /dev/null
@@ -0,0 +1,9 @@
+#include <stdbool.h>
+
+extern bool barInitied;
+extern bool barTeminated;
+
+extern bool bazInitied;
+extern bool bazTeminated;
+
+
diff --git a/unit-tests/test-cases/dlclose-order/baz.cxx b/unit-tests/test-cases/dlclose-order/baz.cxx
new file mode 100644 (file)
index 0000000..415a9c6
--- /dev/null
@@ -0,0 +1,12 @@
+#include "base.h"
+
+class Baz {
+public:
+       Baz() { bazInitied = true; }
+       ~Baz() { bazTeminated = true; }
+
+};
+
+
+Baz baz;
+
diff --git a/unit-tests/test-cases/dlclose-order/foo.c b/unit-tests/test-cases/dlclose-order/foo.c
new file mode 100644 (file)
index 0000000..39ab8be
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+int foo()
+{
+  return 1;
+}
diff --git a/unit-tests/test-cases/dlclose-order/main.c b/unit-tests/test-cases/dlclose-order/main.c
new file mode 100644 (file)
index 0000000..c776426
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+#include "base.h"
+
+
+int main(int argc, const char* argv[])
+{
+       // regular open
+       void* handle = dlopen(argv[1], RTLD_LAZY);
+       if ( handle == NULL ) {
+               FAIL("dlclose-order: dlopen(\"libfoo.dylib\", RTLD_LAZY) failed");
+               return EXIT_SUCCESS;
+       }
+       
+       // regular close
+       int result = dlclose(handle);
+       if ( result != 0 ) {
+               FAIL("dlclose-order: dlclose() failed");
+               return EXIT_SUCCESS;
+       }
+       
+       if ( !bazTeminated ) {
+               FAIL("dlclose-order: baz not terminated");
+               return EXIT_SUCCESS;
+       }
+       
+       if ( !barTeminated ) {
+               FAIL("dlclose-order: bar not terminated");
+               return EXIT_SUCCESS;
+       }
+       
+       PASS("dlclose-order");
+       return EXIT_SUCCESS;
+}
index ed9840e2d26bd0b2774d8cbbb10cd141ba397120..c1b3a3712b0c2e3e97756b268fb91905190b2355 100644 (file)
@@ -75,7 +75,7 @@ int main()
 
        // execute leaks command on myself
        char cmd[512];
-       sprintf(cmd, "leaks %u > /dev/null\n", getpid());
+       sprintf(cmd, "sudo leaks %u > /dev/null\n", getpid());
        int status = system(cmd);
        if ( status == EXIT_SUCCESS )
                PASS("dlopen-leak-threaded");
index d84b8e2f67b2dc163b2f98ac2b85dffc386c11e2..3ff66e51ef47a3761b1ff30d8a492b309d274c20 100644 (file)
@@ -42,7 +42,7 @@ int main()
 
        // execute leaks command on myself
        char cmd[512];
-       sprintf(cmd, "leaks %u > /dev/null\n", getpid());
+       sprintf(cmd, "sudo leaks %u > /dev/null\n", getpid());
        int result = system(cmd);
        if ( result == EXIT_SUCCESS )
                PASS("dlopen-leak");
index a953bff5a7af2b8b5bb39e4864ef501c78bdf2e7..33c608be0c5acdea9907c9fd1ceb9b307b80833d 100644 (file)
@@ -40,7 +40,7 @@ int main()
        
        // execute leaks command on myself
        char cmd[512];
-       sprintf(cmd, "leaks %u > /dev/null\n", getpid());
+       sprintf(cmd, "sudo leaks %u > /dev/null\n", getpid());
        int result = system(cmd);
        if ( result == EXIT_SUCCESS )
                PASS("dlopen-search-leak");
index 4d90de47e7e457f578f584d518a2dbc6b4e1bef4..48b5b72e776dd2fa57c61c36f4a6c539d4a18d44 100644 (file)
@@ -54,7 +54,7 @@ int main()
 
        // execute leaks command on myself
        char cmd[512];
-       sprintf(cmd, "leaks %u > /dev/null\n", getpid());
+       sprintf(cmd, "sudo leaks %u > /dev/null\n", getpid());
        int result = system(cmd);
        if ( result == EXIT_SUCCESS )
                PASS("dlopen_preflight-leak-image-deny-single");
index 3f04f2eb23662402f0d3a78622c7b2cbc3602796..09415970295fecbe7a9d166dd1d57d6557c9c4d1 100644 (file)
@@ -38,7 +38,7 @@ int main()
        
        // execute leaks command on myself
        char cmd[512];
-       sprintf(cmd, "leaks %u > /dev/null\n", getpid());
+       sprintf(cmd, "sudo leaks %u > /dev/null\n", getpid());
        int result = system(cmd);
        if ( result == EXIT_SUCCESS )
                PASS("dlopen_preflight-leak");
diff --git a/unit-tests/test-cases/image-remove-crash/Makefile b/unit-tests/test-cases/image-remove-crash/Makefile
new file mode 100644 (file)
index 0000000..050a99c
--- /dev/null
@@ -0,0 +1,17 @@
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+all-check: all check
+
+check:
+       ./main
+
+all:
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o foo.bundle foo.c -bundle
+       
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main foo.bundle 
+
diff --git a/unit-tests/test-cases/image-remove-crash/foo.c b/unit-tests/test-cases/image-remove-crash/foo.c
new file mode 100644 (file)
index 0000000..6924ac6
--- /dev/null
@@ -0,0 +1,3 @@
+
+void foo() {}
+
diff --git a/unit-tests/test-cases/image-remove-crash/main.c b/unit-tests/test-cases/image-remove-crash/main.c
new file mode 100644 (file)
index 0000000..612671f
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <stdbool.h>
+#include <mach-o/dyld.h>  
+#include <dlfcn.h>  
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+static bool sNotified = false;
+
+static void removeNotification2(const struct mach_header *mh, intptr_t vmaddr_slide)
+{
+}
+
+static void removeNotification(const struct mach_header *mh, intptr_t vmaddr_slide)
+{
+       // <rdar://problem/15025198> crash in dyld possible if remove callbacks added within a remove callback
+       _dyld_register_func_for_remove_image(removeNotification2);
+       _dyld_register_func_for_remove_image(removeNotification2);
+       _dyld_register_func_for_remove_image(removeNotification2);
+       _dyld_register_func_for_remove_image(removeNotification2);
+       _dyld_register_func_for_remove_image(removeNotification2);
+
+       sNotified = true;
+}
+
+int main(int argc, const char* argv[])
+{
+       // tell dyld we want to know when images go away
+       _dyld_register_func_for_remove_image(removeNotification);
+       
+       void* handle = dlopen("foo.bundle", RTLD_LAZY);
+       if ( handle == NULL ) {
+               FAIL("image-remove-crash: dlopen(foo.bundle) failed: %s", dlerror());
+               exit(0);
+       }
+       
+       int result = dlclose(handle);
+       if ( result != 0 ) {
+               FAIL("image-remove-crash: dlclose(handle) returned %d, %s", result, dlerror());
+               exit(0);
+       }
+
+       if ( sNotified )
+               PASS("image-remove-crash");
+       else
+               FAIL("image-remove-crash");
+               
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/image-state-deny-cache-leak/Makefile b/unit-tests/test-cases/image-state-deny-cache-leak/Makefile
new file mode 100644 (file)
index 0000000..48aff7d
--- /dev/null
@@ -0,0 +1,38 @@
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+all-check: all check
+
+check:
+       ./main
+
+all: 
+       ${CC} ${CCFLAGS} -dynamiclib -o libfoo1.dylib  foo.c -lz
+       ${CC} ${CCFLAGS} -dynamiclib -o libfoo2.dylib  foo.c  -weak-lz
+       ${CC} ${CCFLAGS} -Wno-deprecated-declarations  -I${TESTROOT}/include -o main main.c 
+
+clean:
+       ${RM} ${RMFLAGS} *~ main *.dylib
+
diff --git a/unit-tests/test-cases/image-state-deny-cache-leak/bar.c b/unit-tests/test-cases/image-state-deny-cache-leak/bar.c
new file mode 100644 (file)
index 0000000..30ade8f
--- /dev/null
@@ -0,0 +1,2 @@
+
+void bar() { }
diff --git a/unit-tests/test-cases/image-state-deny-cache-leak/foo.c b/unit-tests/test-cases/image-state-deny-cache-leak/foo.c
new file mode 100644 (file)
index 0000000..6924ac6
--- /dev/null
@@ -0,0 +1,3 @@
+
+void foo() {}
+
diff --git a/unit-tests/test-cases/image-state-deny-cache-leak/main.c b/unit-tests/test-cases/image-state-deny-cache-leak/main.c
new file mode 100644 (file)
index 0000000..edcb894
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2014 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdbool.h>  // fprintf(), NULL
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <stdbool.h>
+#include <string.h>
+#include <mach-o/dyld.h>  
+#include <mach-o/dyld_priv.h>  
+#include <dlfcn.h>  
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+//
+// By returning a string, we prevent that image from loading.
+// We just prevent any image with "libz" in its name from loading.
+//
+static const char* singleMappedHandler(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+{
+       //fprintf(stderr, "single mapped: %s\n", info[0].imageFilePath);
+       if ( strstr(info[0].imageFilePath, "libz") != NULL )
+               return "can't load libz";
+       return NULL;
+}
+
+
+int main(int argc, const char* argv[])
+{
+       // tell dyld we want to know when images are mapped
+  dyld_register_image_state_change_handler(dyld_image_state_mapped, false, singleMappedHandler);
+
+       void* handle = dlopen("libfoo1.dylib", RTLD_LAZY);
+       if ( handle != NULL ) {
+    FAIL("image-state-deny-cache-leak: dlopen(libfoo.dylib) should have failed");
+    return EXIT_SUCCESS;
+       }
+
+       handle = dlopen("libfoo2.dylib", RTLD_LAZY);
+       if ( handle == NULL ) {
+    FAIL("image-state-deny-cache-leak: dlopen(libfoo.dylib) should have succeeded");
+    return EXIT_SUCCESS;
+       }
+  dlclose(handle);
+
+  // execute leaks command on myself
+       char cmd[512];
+       sprintf(cmd, "sudo leaks %u > /dev/null\n", getpid());
+       int result = system(cmd);
+       if ( result == EXIT_SUCCESS )
+               PASS("image-state-deny-cache-leak");
+       else
+               FAIL("image-state-deny-cache-leak");
+
+
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/image-state-deny-leak/Makefile b/unit-tests/test-cases/image-state-deny-leak/Makefile
new file mode 100644 (file)
index 0000000..364f994
--- /dev/null
@@ -0,0 +1,39 @@
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+all-check: all check
+
+check:
+       ./main
+
+all: 
+       ${CC} ${CCFLAGS} -dynamiclib -o libbar1.dylib  bar.c
+       ${CC} ${CCFLAGS} -dynamiclib -o libbar2.dylib  bar.c
+       ${CC} ${CCFLAGS} -dynamiclib -o libfoo.dylib  foo.c libbar1.dylib -weak_library libbar2.dylib
+       ${CC} ${CCFLAGS} -Wno-deprecated-declarations  -I${TESTROOT}/include -o main main.c 
+
+clean:
+       ${RM} ${RMFLAGS} *~ main *.dylib
+
diff --git a/unit-tests/test-cases/image-state-deny-leak/bar.c b/unit-tests/test-cases/image-state-deny-leak/bar.c
new file mode 100644 (file)
index 0000000..30ade8f
--- /dev/null
@@ -0,0 +1,2 @@
+
+void bar() { }
diff --git a/unit-tests/test-cases/image-state-deny-leak/foo.c b/unit-tests/test-cases/image-state-deny-leak/foo.c
new file mode 100644 (file)
index 0000000..6924ac6
--- /dev/null
@@ -0,0 +1,3 @@
+
+void foo() {}
+
diff --git a/unit-tests/test-cases/image-state-deny-leak/main.c b/unit-tests/test-cases/image-state-deny-leak/main.c
new file mode 100644 (file)
index 0000000..42e369e
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdbool.h>  // fprintf(), NULL
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <stdbool.h>
+#include <string.h>
+#include <mach-o/dyld.h>  
+#include <mach-o/dyld_priv.h>  
+#include <dlfcn.h>  
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+//
+// By returning a string, we prevent that image from loading.
+// We just prevent any image with "bar" in its name from loading.
+//
+
+const char* sBlockName = NULL;
+
+static const char* singleMappedHandler(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+{
+       //fprintf(stderr, "single mapped: %s\n", info[0].imageFilePath);
+       if ( strstr(info[0].imageFilePath, sBlockName) != NULL )
+               return "can't load blocked name";
+       return NULL;
+}
+
+
+int main(int argc, const char* argv[])
+{
+       // tell dyld we want to know when images are mapped
+  dyld_register_image_state_change_handler(dyld_image_state_mapped, false, singleMappedHandler);
+
+  sBlockName = "libbar1";
+       void* handle = dlopen("libfoo.dylib", RTLD_LAZY);
+       if ( handle != NULL ) {
+    FAIL("image-state-deny-leak: dlopen(libfoo.dylib) should have failed");
+    return EXIT_SUCCESS;
+       }
+
+  sBlockName = "libbar2";
+       handle = dlopen("libfoo.dylib", RTLD_LAZY);
+       if ( handle == NULL ) {
+    FAIL("image-state-deny-leak: dlopen(libfoo.dylib) should have succeeded");
+    return EXIT_SUCCESS;
+       }
+
+  // execute leaks command on myself
+       char cmd[512];
+       sprintf(cmd, "sudo leaks %u > /dev/null \n", getpid());
+       int result = system(cmd);
+       if ( result == EXIT_SUCCESS )
+               PASS("image-state-deny-leak");
+       else
+               FAIL("image-state-deny-leak");
+
+
+               
+       return EXIT_SUCCESS;
+}
index 077a8a2fcd2f2a99b756643eef01a6aed6a47cc3..18041ac430966276737d467443ce6de327744a14 100644 (file)
@@ -26,7 +26,7 @@
 
 char* mystrdup(const char* in)
 {
-       return "hello";
+       return strdup("hello");
 }
 
 DYLD_INTERPOSE(mystrdup, strdup)
index 077a8a2fcd2f2a99b756643eef01a6aed6a47cc3..18041ac430966276737d467443ce6de327744a14 100644 (file)
@@ -26,7 +26,7 @@
 
 char* mystrdup(const char* in)
 {
-       return "hello";
+       return strdup("hello");
 }
 
 DYLD_INTERPOSE(mystrdup, strdup)
diff --git a/unit-tests/test-cases/interpose-dynamic-basic/Makefile b/unit-tests/test-cases/interpose-dynamic-basic/Makefile
new file mode 100644 (file)
index 0000000..b1cf89d
--- /dev/null
@@ -0,0 +1,37 @@
+##
+# Copyright (c) 2014 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+all-check: all check
+
+check:
+       ./main
+
+all:  
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main 
+
diff --git a/unit-tests/test-cases/interpose-dynamic-basic/main.c b/unit-tests/test-cases/interpose-dynamic-basic/main.c
new file mode 100644 (file)
index 0000000..b302512
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2014 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <string.h>
+#include <dlfcn.h>
+#include <mach-o/dyld_priv.h>
+
+extern const struct mach_header __dso_handle;
+
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+typedef char* (*DupProc)(const char*);
+
+char* mystrdup(const char* in)
+{
+       return "hello";
+}
+
+static const struct dyld_interpose_tuple sTable[] = { {&mystrdup, &strdup} };
+
+int main()
+{
+       const char* preCall = strdup("123");
+  DupProc preProc = &strdup;
+  
+  dyld_dynamic_interpose(&__dso_handle, sTable, 1);
+  
+       const char* postCall = strdup("123");
+  DupProc postProc = &strdup;
+  
+  if ( strcmp(preCall, "123") != 0 ) {
+      FAIL("interpose-dynamic-basic control strdup failed");
+      return EXIT_SUCCESS;
+  }
+  
+  if ( strcmp(postCall, "hello") != 0 ) {
+      FAIL("interpose-dynamic-basic interposed lazy strdup failed");
+      return EXIT_SUCCESS;
+  }
+  
+  if ( preProc == postProc ) {
+      FAIL("interpose-dynamic-basic interposed non-lazy strdup failed");
+      return EXIT_SUCCESS;
+  }
+    
+  PASS("interpose-dynamic-basic");
+  
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/interpose-dynamic-dlsym/Makefile b/unit-tests/test-cases/interpose-dynamic-dlsym/Makefile
new file mode 100644 (file)
index 0000000..410d9ae
--- /dev/null
@@ -0,0 +1,38 @@
+##
+# Copyright (c) 2014 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+all-check: all check
+
+check:
+       ./main
+
+all:  
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libfoo.dylib
+
diff --git a/unit-tests/test-cases/interpose-dynamic-dlsym/foo.c b/unit-tests/test-cases/interpose-dynamic-dlsym/foo.c
new file mode 100644 (file)
index 0000000..5bfa892
--- /dev/null
@@ -0,0 +1,26 @@
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <string.h>
+#include <dlfcn.h>
+#include <crt_externs.h>
+#include <mach-o/dyld_priv.h>
+
+
+int foo() { return 0; }
+
+int alt_foo() { return 10; }
+
+
+
+
+static const struct dyld_interpose_tuple sTable[] = { {&alt_foo, &foo} };
+
+
+__attribute__((constructor))
+void init()
+{
+  // switch main executable to use alt_foo() when it calls foo()
+  dyld_dynamic_interpose((const struct mach_header*)_NSGetMachExecuteHeader(), sTable, 1);
+
+}
+
diff --git a/unit-tests/test-cases/interpose-dynamic-dlsym/main.c b/unit-tests/test-cases/interpose-dynamic-dlsym/main.c
new file mode 100644 (file)
index 0000000..da21a5c
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2014 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <string.h>
+#include <dlfcn.h>
+#include <mach-o/dyld_priv.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+typedef int (*FooProc)();
+
+int main()
+{
+       void* handle = dlopen("libfoo.dylib", RTLD_LAZY);
+       if ( handle == NULL ) {
+               FAIL("interpose-dynamic-dlsym: dlopen() error: %s", dlerror());
+               return 0;
+       }
+       FooProc dlsym_foo = (FooProc)dlsym(handle, "foo");
+       if ( dlsym_foo == NULL ) {
+               FAIL("interpose-dynamic-dlsym: dlsym() error: %s", dlerror());
+               return 0;
+       }
+
+  int result = (*dlsym_foo)();
+  if ( result == 10 )
+      PASS("interpose-dynamic-dlsym");
+  else
+      FAIL("interpose-dynamic-dlsym");
+  
+       return 0;
+}
diff --git a/unit-tests/test-cases/interpose-dynamic-lazy/Makefile b/unit-tests/test-cases/interpose-dynamic-lazy/Makefile
new file mode 100644 (file)
index 0000000..61586cc
--- /dev/null
@@ -0,0 +1,38 @@
+##
+# Copyright (c) 2014 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+all-check: all check
+
+check:
+       ./main
+
+all:  
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libfoo.dylib
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libfoo.dylib
+
diff --git a/unit-tests/test-cases/interpose-dynamic-lazy/foo.c b/unit-tests/test-cases/interpose-dynamic-lazy/foo.c
new file mode 100644 (file)
index 0000000..49b5897
--- /dev/null
@@ -0,0 +1,27 @@
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <string.h>
+#include <dlfcn.h>
+#include <crt_externs.h>
+#include <mach-o/dyld_priv.h>
+
+
+
+int foo() { return 0; }
+
+int alt_foo() { return 10; }
+
+
+
+
+static const struct dyld_interpose_tuple sTable[] = { {&alt_foo, &foo} };
+
+
+__attribute__((constructor))
+void init()
+{
+
+  dyld_dynamic_interpose((const struct mach_header*)_NSGetMachExecuteHeader(), sTable, 1);
+
+}
+
diff --git a/unit-tests/test-cases/interpose-dynamic-lazy/main.c b/unit-tests/test-cases/interpose-dynamic-lazy/main.c
new file mode 100644 (file)
index 0000000..89e9ad9
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <string.h>
+#include <dlfcn.h>
+#include <mach-o/dyld_priv.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+extern int foo();
+
+int main()
+{
+  int result = foo();
+  if ( result == 10 )
+      PASS("interpose-dynamic-lazy");
+  else
+      FAIL("interpose-dynamic-lazy");
+  
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/rpath-no-trailing-slash/Makefile b/unit-tests/test-cases/rpath-no-trailing-slash/Makefile
new file mode 100644 (file)
index 0000000..e10933d
--- /dev/null
@@ -0,0 +1,46 @@
+##
+# Copyright (c) 2014 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+PWD = $(shell pwd)
+
+#
+# a main executable linked with -rpath used to locate a dylib it links against
+#
+
+all-check: all check
+
+check:
+       ./hole/main
+
+all: main
+
+       
+main:
+       mkdir -p hole
+       ${CC} foo.c -dynamiclib -o hole/libfoo.dylib -install_name @rpath/libfoo.dylib
+       ${CC} -I${TESTROOT}/include main.c -o hole/main hole/libfoo.dylib -Wl,-rpath,@executable_path
+
+clean:
+       ${RM} -rf *~  hole
diff --git a/unit-tests/test-cases/rpath-no-trailing-slash/foo.c b/unit-tests/test-cases/rpath-no-trailing-slash/foo.c
new file mode 100644 (file)
index 0000000..3695dc9
--- /dev/null
@@ -0,0 +1,3 @@
+void foo()
+{
+}
diff --git a/unit-tests/test-cases/rpath-no-trailing-slash/main.c b/unit-tests/test-cases/rpath-no-trailing-slash/main.c
new file mode 100644 (file)
index 0000000..97bfaa2
--- /dev/null
@@ -0,0 +1,14 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <mach-o/dyld.h>
+
+#include "test.h"
+
+extern void foo();
+
+int main()
+{
+       foo();
+       PASS("rpath-no-trailing-slash");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/symbol-resolver-lazy-prebound/bar.o b/unit-tests/test-cases/symbol-resolver-lazy-prebound/bar.o
new file mode 100644 (file)
index 0000000..9257269
Binary files /dev/null and b/unit-tests/test-cases/symbol-resolver-lazy-prebound/bar.o differ
diff --git a/unit-tests/test-cases/text-perm-alt-segment/Makefile b/unit-tests/test-cases/text-perm-alt-segment/Makefile
new file mode 100644 (file)
index 0000000..163719d
--- /dev/null
@@ -0,0 +1,54 @@
+##
+# Copyright (c) 2013 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+### 
+### This test case is to verify __TEXT relocations work in dylibs
+### 
+### 
+
+
+ifeq "i386" "$(ARCH)"
+       EXTRA_DEP = libfoo.dylib
+else
+
+endif
+
+all-check: all check
+
+check:
+       ./main
+
+all:  ${EXTRA_DEP}
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c ${EXTRA_DEP}
+
+libfoo.dylib:
+       ${CC} ${CCFLAGS} foo.c -c
+       ${LD} -r -arch ${ARCH} foo.o -rename_section __TEXT __text MYTEXT mytext -o foo2.o
+       ${CC} ${CCFLAGS} -dynamiclib foo2.o -o libfoo.dylib -Wl,-segprot,MYTEXT,rwx,r-x -read_only_relocs suppress
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libfoo.dylib foo.o foo2.o
+
diff --git a/unit-tests/test-cases/text-perm-alt-segment/foo.c b/unit-tests/test-cases/text-perm-alt-segment/foo.c
new file mode 100644 (file)
index 0000000..9f41b6b
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>  // fprintf(), NULL
+
+int x = 5;
+
+__attribute__((constructor))
+void myInit() {
+       x = 10;
+}
+
+
+__attribute__((section("MYTEXT,myconst,regular,pure_instructions")))
+const void* p = &myInit;
+
+
diff --git a/unit-tests/test-cases/text-perm-alt-segment/main.c b/unit-tests/test-cases/text-perm-alt-segment/main.c
new file mode 100644 (file)
index 0000000..e6f9eed
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <stdbool.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+int main(int argc, const char* argv[])
+{
+       PASS("text-reloc-alt-segment");
+       return EXIT_SUCCESS;
+}
+
+
index 977b5a813b8e7e7d980d83d242c3644f87184ba9..cf25175610e49d6fe213c1e9d9d3a7c80f952f53 100644 (file)
@@ -36,7 +36,7 @@ check:
 all: main 
 
 main : main.c 
-       clang -arch ${ARCH} ${CCFLAGS} -I${TESTROOT}/include main.c -o main 
+       ${CC} -arch ${ARCH} ${CCFLAGS} -I${TESTROOT}/include main.c -o main 
 
 
 clean:
index 0fa52405efec5ff8d5ab52c4576510a267fff8cf..1bbdc613c99e6e311cda6c1f24f5e417e346a121 100644 (file)
@@ -26,6 +26,9 @@
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
+__attribute__((weak))
+void foobar() {
+}
 
 __thread int a;
 __thread int b = 5;
@@ -35,45 +38,82 @@ __thread static int d = 5;
 
 static void* work(void* arg)
 {
+  uintptr_t offset = (uintptr_t)arg;
        //fprintf(stderr, "self=%p, &a=%p\n", pthread_self(), get_a());
+  void* result = malloc(10);
        if ( a != 0 ) {
-               FAIL("tlv-basic: get_a() non-zero");
+               FAIL("tlv-basic: a non-zero on slow-path");
                exit(0);
        }
        if ( b != 5 ) {
-               FAIL("tlv-basic: get_b() not five");
+               FAIL("tlv-basic: b not five");
                exit(0);
        }
+  
        if ( c != 0 ) {
-               FAIL("tlv-basic: get_c() non-zero");
+               FAIL("tlv-basic: c non-zero");
                exit(0);
        }
+  
        if ( d != 5 ) {
-               FAIL("tlv-basic: get_d() not five");
+               FAIL("tlv-basic: gd not five");
                exit(0);
        }
-       return NULL;
+  
+  for(int i=0; i < 10000; ++i) {
+    a = 3 + offset + i;
+    b = 7 + offset + i;
+    c = 11 + offset + i;
+    d = 13 + offset + i;
+    foobar();
+    if ( a != 3 + offset + i ) {
+      FAIL("tlv-basic: a not three");
+      exit(0);
+    }
+    if ( b != 7 + offset + i ) {
+      FAIL("tlv-basic: b not seven");
+      exit(0);
+    }
+    if ( c != 11 + offset + i ) {
+      FAIL("tlv-basic: c not eleven");
+      exit(0);
+    }
+    if ( d != 13 + offset + i ) {
+      FAIL("tlv-basic: d not thirteen");
+      exit(0);
+    }
+  }
+
+       return result;
 }
 
 int main()
 {
        pthread_t worker1;
-       if ( pthread_create(&worker1, NULL, work, NULL) != 0 ) {
+       if ( pthread_create(&worker1, NULL, work, (void*)1) != 0 ) {
                FAIL("pthread_create failed");
                exit(0);
        }
 
        pthread_t worker2;
-       if ( pthread_create(&worker2, NULL, work, NULL) != 0 ) {
+       if ( pthread_create(&worker2, NULL, work, (void*)10) != 0 ) {
                FAIL("pthread_create failed");
                exit(0);
        }
 
+       pthread_t worker3;
+       if ( pthread_create(&worker3, NULL, work, (void*)100) != 0 ) {
+               FAIL("pthread_create failed");
+               exit(0);
+       }
+  
        void* result;
        //fprintf(stderr, "waiting for worker 1\n");
        pthread_join(worker1, &result);
        //fprintf(stderr, "waiting for worker 2\n");
        pthread_join(worker2, &result);
+       //fprintf(stderr, "waiting for worker 3\n");
+       pthread_join(worker3, &result);
 
        work(NULL);
 
index ff8103e69db836d3913b4a9f58fe1dcd7c6742ac..90110419795e634b19d02dfe058884c9631b4657 100644 (file)
@@ -34,8 +34,8 @@ check:
        ./main
 
 all:  
-       clang -arch ${ARCH} ${CCFLAGS} -I${TESTROOT}/include foo.c -dynamiclib -o libfoo.dylib 
-       clang -arch ${ARCH} ${CCFLAGS} -I${TESTROOT}/include main.c libfoo.dylib -o main 
+       ${CC} -arch ${ARCH} ${CCFLAGS} -I${TESTROOT}/include foo.c -dynamiclib -o libfoo.dylib 
+       ${CC} -arch ${ARCH} ${CCFLAGS} -I${TESTROOT}/include main.c libfoo.dylib -o main 
 
 
 clean:
index a0a54a1b16240208e221fe5068ad73bc0efb90bf..bc48b5c932287708d5a5747cc8764f622613b82a 100644 (file)
@@ -40,14 +40,15 @@ check_1:
 
 all_1: 
        ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib common.c -o libcommon.dylib  
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib u.c libcommon.dylib -o libu.dylib  
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib u2.c libcommon.dylib -o libu2.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib u.c libcommon.dylib -o libu.dylib -Wl,-upward_library,libu2.dylib
        ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib c.c libcommon.dylib -o libc.dylib -Wl,-upward_library,libu.dylib
        ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib b.c libcommon.dylib -o libb.dylib libc.dylib
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c  libb.dylib libu.dylib libcommon.dylib -o main
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c  libb.dylib libcommon.dylib -o main
 
 
 clean:
-       ${RM} ${RMFLAGS} *~ main libu.dylib libb.dylib libc.dylib libcommon.dylib
+       ${RM} ${RMFLAGS} *~ main libu.dylib libu2.dylib libb.dylib libc.dylib libcommon.dylib
 
 
        
index c7038356e49db97ec25e096d799cfe441cc68f65..663e4a19b4a2a0e7e81070f2fb08b94f53ce9f42 100644 (file)
@@ -3,27 +3,35 @@
 
 static bool b = false;
 static bool u = false;
+static bool u2 = false;
 static bool isOk = true;
 
 void setB()
 {
-       if ( u || b )
+       if ( u || b || u2 )
                isOk = false;
        b = true;
 }
 
 void setU()
 {
-       if ( u )
+       if ( u  || u2 )
                isOk = false;
        u = true;
 }
 
+void setU2()
+{
+       if ( u2 )
+               isOk = false;
+       u2 = true;
+}
+
 // return true iff
 // setB() was called, then setU()
 bool ok()
 {
        //fprintf(stderr, "isOk=%d, u=%d, b=%d\n", isOk, u, b);
-       return isOk && u && b;
+       return isOk && u && b && u2;
 }
 
index 0094023fc225c96ae07b5f7ee6773d8b02d821f6..05427dcbbaf0db04f6471ed7c19bad31385833aa 100644 (file)
@@ -2,6 +2,7 @@
 
 extern void setB();
 extern void setU();
+extern void setU2();
 
 extern bool ok();
 
diff --git a/unit-tests/test-cases/upward-dylib-init-order/u2.c b/unit-tests/test-cases/upward-dylib-init-order/u2.c
new file mode 100644 (file)
index 0000000..7add33f
--- /dev/null
@@ -0,0 +1,10 @@
+#include <stdio.h>
+#include "common.h"
+
+
+static __attribute__((constructor)) void myInit() 
+{
+       setU2();
+       //fprintf(stderr, "init u2\n");
+}
+