--- /dev/null
+#include "<DEVELOPER_DIR>/AppleInternal/XcodeConfig/SimulatorSupport.xcconfig"
+
+// Set INSTALL_PATH[sdk=macosx*] when SimulatorSupport.xcconfig is unavailable
+INSTALL_PATH[sdk=macosx*] = $(INSTALL_PATH_ACTUAL)
.br
DYLD_VERSIONED_LIBRARY_PATH
.br
+DYLD_PRINT_TO_FILE
+.br
DYLD_ROOT_PATH
.br
DYLD_SHARED_REGION
.br
DYLD_BIND_AT_LAUNCH
.br
-DYLD_NO_FIX_PREBINDING
-.br
DYLD_DISABLE_DOFS
.br
DYLD_PRINT_APIS
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.
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
--- /dev/null
+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
F908137111D3FB5000626CC1 /* usr|local|include|mach-o */,
F908137211D3FB5000626CC1 /* usr|share|man|man1 */,
F908137311D3FB5000626CC1 /* usr|share|man|man3 */,
- F9F479FE152A63F2008F75C2 /* simulator clean up */,
);
dependencies = (
F9B4D78012AD9736000605A6 /* PBXTargetDependency */,
/* 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)",
--- /dev/null
+<?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>
-/*
- * _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);
-
-
//
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
//
#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
#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.
-#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.
#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
}
/* -*- 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@
*
};
+struct arm64
+{
+ typedef Pointer64<LittleEndian> P;
+
+};
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>
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>
}
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;
}
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());
}
}
#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 */
#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"
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);
}
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; }
uint64_t fSize;
uint64_t fFileOffset;
uint64_t fFileSize;
+ uint64_t fAlignment;
uint32_t fPermissions;
uint64_t fNewAddress;
void* fMappedAddress;
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;
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; }
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;
bool fMainExecutableLookupLinkage;
bool fIsDylib;
bool fHasDyldInfo;
+ bool fHasTooManyWritableSegments;
mutable const uint8_t* fDyldInfoExports;
uuid_t fUUID;
};
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;
}
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";
}
}
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));
}
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";
}
}
+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 = §ionsStart[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 = §ionsStart[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 = §ionsStart[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;
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:
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()) )
}
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());
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 <>
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__
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();
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
}
}
+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>
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);
}
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);) {
#define __MACH_O_TRIE__
#include <algorithm>
+#include <vector>
#include "MachOFileAbstraction.hpp"
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;
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 ) {
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:
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;
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()
{
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:
uint32_t newEntsize = sizeof(objc_ivar_t<A>))
: entsize(newEntsize), count(newCount)
{ }
-
+private:
+ // use newIvarList instead
+ void* operator new (size_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:
uint32_t newEntsize = sizeof(objc_property_t<A>))
: entsize(newEntsize), count(newCount)
{ }
-
+private:
+ // use newPropertyList instead
+ void* operator new (size_t);
};
template <typename A>
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:
}
objc_protocol_list_t(uint32_t newCount) : count(newCount) { }
-
+private:
+ // use newProtocolList instead
+ void* operator new (size_t);
};
#include "dsc_iterator.h"
#include "dsc_extractor.h"
+#include "MachOTrie.hpp"
#include <vector>
+#include <set>
#include <map>
#include <unordered_map>
#include <algorithm>
};
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;
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);
macho_section<P>* const sectionsEnd = §ionsStart[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);
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());
}
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());
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()];
}
}
+ // 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;
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;
}
// 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);
// 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) );
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 ) {
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;
}
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 )
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);
// 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));
});
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];
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;
}
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;
}
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;
}
}
dispatch_release(writer_queue);
munmap(mapped_cache, statbuf.st_size);
- return cumulativeResult;
+ return result;
}
#include "CacheFileAbstraction.hpp"
-
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;
// 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 )
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());
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;
}
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 )
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;
}
#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;
#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"
#include "MachOFileAbstraction.hpp"
#include "CacheFileAbstraction.hpp"
-
enum Mode {
modeNone,
modeList,
modeDependencies,
modeSlideInfo,
modeLinkEdit,
- modeInfo
+ modeInfo,
+ modeSize
};
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
*/
#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
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;;
}
+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)
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);
}
options.printUUIDs = false;
options.printVMAddrs = false;
options.printDylibVersions = false;
+ options.printInodes = false;
options.dependentsOfPath = NULL;
for (uint32_t i = 1; i < argc; i++) {
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;
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 {
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>;
case modeLinkEdit:
callback = process_linkedit<x86_64>;
break;
+ case modeSize:
+ callback = collect_size<x86_64>;
+ break;
case modeNone:
case modeInfo:
case modeSlideInfo:
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:
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);
});
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);
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; }
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;
};
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)
{
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') ) {
{
//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);
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 ) {
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:
default:
return "arm";
}
+ case CPU_TYPE_ARM64:
+ return "arm64";
default:
return "unknown";
}
{
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;
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;
StringPool::StringPool()
- : fBufferUsed(0), fBufferAllocated(48*1024*1024)
+ : fBufferUsed(0), fBufferAllocated(64*1024*1024)
{
fBuffer = (char*)malloc(fBufferAllocated);
}
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);
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 {
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),
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 ) {
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);
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 ) {
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;
}
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)
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;
}
}
}
+ // align __TEXT region
+ currentExecuteAddress = regionAlign(currentExecuteAddress);
// layout DATA for dylibs
const uint64_t startWritableAddress = sharedRegionStartWritableAddress(currentExecuteAddress);
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);
}
// 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) {
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 {
// 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;
}
}
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 ) {
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;
}
}
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;
}
}
}
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
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 = §ionsStart[seg->nsects()];
// 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);
seg.setFileOffset(linkEditsFileOffset);
}
}
- }
-
+ }
+
// return new end of cache
- return (uint8_t*)fFirstLinkEditSegment->mappedAddress() + fLinkEditsTotalOptimizedSize;
+ return (uint8_t*)fFirstLinkEditSegment->mappedAddress() + regionAlign(fLinkEditsTotalOptimizedSize);
}
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>
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());
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>)];
}
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
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;
// 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;
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);
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;
*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;
}
-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)
}
-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
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);
}
-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;
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;
{
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;
bool keepSignatures = false;
bool explicitCacheDir = false;
bool dontMapLocalSymbols = false;
+ bool relaunchForHaswell = false;
const char* cacheDir = NULL;
try {
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];
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 )
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();
}
// 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
#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
// 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 ) {
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);
--- /dev/null
+
+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
+
+
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);
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);
}
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);
(*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
}
-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);
// 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;
}
}
// 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;
}
}
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);
}
#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"
#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
#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;
ImageLoader* mainExecutable;
const char* imageSuffix;
const char** rootPaths;
+ const dyld_interpose_tuple* dynamicInterposeArray;
+ size_t dynamicInterposeCount;
PrebindMode prebindUsage;
SharedRegionMode sharedRegionMode;
bool dyldLoadedAtSameAddressNeededBySharedCache;
} images[1];
};
+ struct UninitedUpwards
+ {
+ uintptr_t count;
+ ImageLoader* images[1];
+ };
+
// constructor is protected, but anyone can delete an image
virtual ~ImageLoader();
// 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.
//
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;
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;
};
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;
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;
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;
// 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);
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:
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:
*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 )
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) )
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;
break;
case LC_ID_DYLIB:
{
- fDylibIDOffset = (uint8_t*)cmd - fMachOData;
+ fDylibIDOffset = (uint32_t)((uint8_t*)cmd - fMachOData);
}
break;
case LC_RPATH:
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));
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));
if ( (sect->flags & S_ATTR_EXT_RELOC) != 0 )
return true;
}
+#endif
return false;
}
// 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;
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;
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;
#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
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;
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;
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 ) {
}
}
+
bool ImageLoaderMachO::getUUID(uuid_t uuid) const
{
const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
#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
{
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;
}
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
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;
#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;
// 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)
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
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) ) {
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) ) {
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 )
// 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 ) {
{
// 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;
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) )
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&);
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);
#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__
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 ) {
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
// 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)
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);
}
// nowhere to be found
- throwSymbolNotFound(context, symbolName, this->getPath(), target->getPath());
+ throwSymbolNotFound(context, symbolName, this->getPath(), "", target->getPath());
}
}
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];
}
}
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());
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
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
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;
}
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
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;
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__
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
}
}
}
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 = §ionsStart[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;
}
}
}
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;
// 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
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;
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;
{
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;
//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);
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);
}
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)();
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);
}
}
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 );
}
// 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");
}
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;
*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 ) {
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);
}
}
}
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;
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];
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;
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];
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;
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];
}
}
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];
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:
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;
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:
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) ) {
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:
}
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;
}
}
+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
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; }
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);
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);
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);
/* -*- 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@
*
#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)
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;
//
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;
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
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.
}
-//#define ALTERNATIVE_LOGFILE "/dev/console"
#if !TARGET_IPHONE_SIMULATOR
static int sLogfile = STDERR_FILENO;
#endif
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, ...)
// <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
}
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 ) {
}
}
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);
}
}
}
}
-#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
}
*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);
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++) {
}
}
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++) {
}
}
}
-#endif
}
static unsigned int imageCount()
{
- return sAllImages.size();
+ return (unsigned int)sAllImages.size();
}
t.to = to;
sDynamicReferences.push_back(t);
}
-
+
static void addImage(ImageLoader* image)
{
// add to master list
// 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
}
-void runImageTerminators(ImageLoader* image)
+void runImageStaticTerminators(ImageLoader* image)
{
// if in termination list, pull it out and run terminator
bool mightBeMore;
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)
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()
{
// 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()
}
-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
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);
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);
}
}
}
- 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);
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);
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);
}
{
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)
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';
// 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));
}
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';
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__
#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;
throw "host_info() failed";
sHostCPU = info.cpu_type;
sHostCPUsubtype = info.cpu_subtype;
+ mach_port_deallocate(mach_task_self(), hostPort);
#endif
#endif
}
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;
}
uint32_t getImageCount()
{
- return sAllImages.size();
+ return (uint32_t)sAllImages.size();
}
ImageLoader* getIndexedImage(unsigned int index)
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);
}
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;
// 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;
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';
// 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 },
};
#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)
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;
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
}
}
#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
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);
}
#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;
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
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)
{
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);
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);
}
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;
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);
// <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);
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
// 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;
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]);
#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"
#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
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 ) {
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__
// 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);
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");
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__
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
}
}
// 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;
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;
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;
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)
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;
}
}
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");
}
// 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 ) {
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;
#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
}
}
void registerRemoveCallback(ImageCallback func)
{
+ // <rdar://problem/15025198> ignore calls to register a notification during a notification
+ if ( sRemoveImageCallbacksInUse )
+ return;
sRemoveImageCallbacks.push_back(func);
}
// 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);
}
// 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
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)) ) {
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
}
}
#endif // SUPPORT_VERSIONED_PATHS
+
#if 0
static void printAllImages()
{
}
// 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;
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;
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));
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,
&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))
{
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");
#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];
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 )
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();
}
}
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;
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);
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();
#define DEPRECATED_APIS_SUPPORTED 1
#endif
+static bool sDynamicInterposing = false;
#if DEPRECATED_APIS_SUPPORTED
static char sLastErrorFilePath[1024];
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
{"__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
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);
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 )
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
#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;
}
}
// 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;
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);
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 )
-#if __IPHONE_OS_VERSION_MIN_REQUIRED
bool dyld_shared_cache_some_image_overridden()
{
#if DYLD_SHARED_CACHE_SUPPORT
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;
+}
#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
#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
static
bool
names_match(
-char *install_name,
+const char *install_name,
const char* libraryName)
{
- char *basename;
+ const char *basename;
unsigned long n;
/*
* 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
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
* 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);
}
/*
* 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))
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
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 )
#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 {
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
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;
}
_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);
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)
// 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 ) {
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);
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);
// 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,
&hasPerThreadBufferFor_dlerror,
&isLaunchdOwned,
&vm_allocate,
- &mmap};
+ &mmap,
+ &__cxa_finalize_ranges};
//
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;
#endif
-#if __i386__ || __x86_64__ || __arm__
+#if __i386__ || __x86_64__ || __arm__ || __arm64__
__attribute__((visibility("hidden")))
void* _dyld_fast_stub_entry(void* loadercache, long lazyinfo)
{
return p(addr);
}
-#if __IPHONE_OS_VERSION_MIN_REQUIRED
bool dyld_shared_cache_some_image_overridden()
{
DYLD_NO_LOCK_THIS_BLOCK;
_dyld_func_lookup("__dyld_shared_cache_some_image_overridden", (void**)&p);
return p();
}
-#endif
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
#include "mach-o/dyld_priv.h"
#include "dyldLibSystemInterface.h"
+
extern void _ZN4dyld3logEPKcz(const char*, ...);
extern struct LibSystemHelpers* _ZN4dyld17gLibSystemHelpersE;
-
-#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");
}
}
-#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
{
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;
#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
return (*myDyldSection.lookup)(dyld_func_name, address);
}
-#endif //! TARGET_IPHONE_SIMULATOR
-
#include <stdint.h>
+struct __cxa_range_t { const void* addr; size_t length; };
+
#if __cplusplus
namespace dyld {
#endif
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*);
// 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
}
#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
// 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;
.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
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__ */
.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
__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
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.
#elif __x86_64__ || __i386__
int3
nop
+#elif __arm64__
+ brk #3
#else
#error unknown architecture
#endif
#ifndef __DYLD_SYSCALL_HELPERS__
#define __DYLD_SYSCALL_HELPERS__
+#include <dirent.h>
#if __cplusplus
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;
+++ /dev/null
-/* -*- 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;
-
// 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];
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);
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];
= {
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;
#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__
#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
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
#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
+
#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
}
+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
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();
}
void mach_init() {
mach_task_self_ = task_self_trap();
//_task_reply_port = _mach_reply_port();
-
}
mach_port_t mach_task_self_ = MACH_PORT_NULL;
#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
#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
.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
.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
.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
// 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:
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
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__
-#if __has_feature(tls)
+#if __has_feature(tls) || __arm64__
typedef struct TLVHandler {
struct TLVHandler *next;
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();
}
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;
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}
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)
--- /dev/null
+##
+# 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
+
+
--- /dev/null
+#include "base.h"
+
+
+class Bar {
+public:
+ Bar() { if ( bazInitied) barInitied = true; }
+ ~Bar() { if ( barInitied && !bazTeminated ) barTeminated = true; }
+};
+
+
+Bar bar;
+
--- /dev/null
+#include "base.h"
+
+bool barInitied = false;
+bool barTeminated = false;
+
+bool bazInitied = false;
+bool bazTeminated = false;
+
--- /dev/null
+#include <stdbool.h>
+
+extern bool barInitied;
+extern bool barTeminated;
+
+extern bool bazInitied;
+extern bool bazTeminated;
+
+
--- /dev/null
+#include "base.h"
+
+class Baz {
+public:
+ Baz() { bazInitied = true; }
+ ~Baz() { bazTeminated = true; }
+
+};
+
+
+Baz baz;
+
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
// 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");
// 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");
// 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");
// 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");
// 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");
--- /dev/null
+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
+
--- /dev/null
+
+void foo() {}
+
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+##
+# 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
+
--- /dev/null
+
+void bar() { }
--- /dev/null
+
+void foo() {}
+
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+##
+# 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
+
--- /dev/null
+
+void bar() { }
--- /dev/null
+
+void foo() {}
+
--- /dev/null
+/*
+ * 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;
+}
char* mystrdup(const char* in)
{
- return "hello";
+ return strdup("hello");
}
DYLD_INTERPOSE(mystrdup, strdup)
char* mystrdup(const char* in)
{
- return "hello";
+ return strdup("hello");
}
DYLD_INTERPOSE(mystrdup, strdup)
--- /dev/null
+##
+# 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
+
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+##
+# 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
+
--- /dev/null
+#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);
+
+}
+
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+##
+# 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
+
--- /dev/null
+#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);
+
+}
+
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+##
+# 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
--- /dev/null
+void foo()
+{
+}
--- /dev/null
+#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;
+}
--- /dev/null
+##
+# 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
+
--- /dev/null
+/*
+ * 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;
+
+
--- /dev/null
+/*
+ * 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;
+}
+
+
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:
#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+__attribute__((weak))
+void foobar() {
+}
__thread int a;
__thread int b = 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);
./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:
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
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;
}
extern void setB();
extern void setU();
+extern void setU2();
extern bool ok();
--- /dev/null
+#include <stdio.h>
+#include "common.h"
+
+
+static __attribute__((constructor)) void myInit()
+{
+ setU2();
+ //fprintf(stderr, "init u2\n");
+}
+