<rdar://problem/9855733> genCaches fails: "header size miscalculation 0x00006000"
dyld-200.2
+<rdar://problem/9818687> ARCH_NAME for armv7k is defined as "armv7s"
<rdar://problem/9784634> dsc_iterator.cpp needs cases for v7 variants
dyld-200
+<rdar://problem/9673497> dyld fails to build for armv7s
<rdar://problem/8942979> update_dyld_shared_cache should accept an 'overlay' along with a 'root' directory option
Remove PowerPC support
-.Dd Nov 7, 2011
+.Dd Aug 7, 2012
.Os
.Dt DLOPEN 3
.Sh NAME
.Fn dlopen
searches for a compatible Mach-O file in the directories specified by a set of environment variables and
the process's current working directory.
-When set, the environment variables must contain a colon-separated list of directory paths,
-which can be absolute or relative to the current working directory. The environment variables
-are LD_LIBRARY_PATH, DYLD_LIBRARY_PATH, and DYLD_FALLBACK_LIBRARY_PATH, but if the path specified
-is formatted like a framework, then DYLD_FRAMEWORK_PATH and DYLD_FALLBACK_FRAMEWORK_PATH are
-used instead.
-The non-fallback variables have no default value. The default value of DYLD_FALLBACK_LIBRARY_PATH
-is $HOME/lib:/usr/local/lib:/usr/lib, and DYLD_FALLBACK_FRAMEWORK_PATH is
-$HOME/Library/Frameworks:/Library/Frameworks:/Network/Library/Frameworks:/System/Library/Frameworks.
-.Fn dlopen
-searches the directories specified in the environment variables in the order they are listed.
+When set, the environment variables contain a colon-separated list of directory paths,
+which can be absolute or relative to the current working directory.
.Pp
When
.Fa path
-doesn't contain a slash character (i.e. it is just a leaf name and therefore not a framework),
+does not contain a slash character (i.e. it is just a leaf name),
.Fn dlopen
-searches the following the following until it finds a compatible Mach-O file: $LD_LIBRARY_PATH,
+searches the following until it finds a compatible Mach-O file: $LD_LIBRARY_PATH,
$DYLD_LIBRARY_PATH, current working directory, $DYLD_FALLBACK_LIBRARY_PATH.
.Pp
When
.Fa path
-contains a slash (i.e. a full path or a partial path)
+looks like a framework path (e.g. /stuff/foo.framework/foo),
.Fn dlopen
-searches the following the following until it finds a compatible Mach-O file:
-$DYLD_LIBRARY_PATH (with leaf name from
+searches the following until it finds a compatible Mach-O file:
+$DYLD_FRAMEWORK_PATH (with framework partial path from
+.Fa path
+), then the supplied
+.Fa path
+(using current working directory for relative paths), then
+$DYLD_FALLBACK_FRAMEWORK_PATH (with framework partial path from
.Fa path
+).
+.Pp
+When
+.Fa path
+contains a slash but is not a framework path (i.e. a full path or a partial path to a dylib),
+.Fn dlopen
+searches the following until it finds a compatible Mach-O file:
+$DYLD_LIBRARY_PATH (with leaf name from
+.Fa path
), then the supplied
.Fa path
-(using current working directory for partial paths).
+(using current working directory for relative paths), then
+$DYLD_FALLBACK_LIBRARY_PATH (with leaf name from
+.Fa path
+).
+.Pp
+Note: If DYLD_FALLBACK_LIBRARY_PATH is not set, dlopen operates as if
+DYLD_FALLBACK_LIBRARY_PATH was set to $HOME/lib:/usr/local/lib:/usr/lib.
+.Pp
+Note: If DYLD_FALLBACK_FRAMEWORK_PATH is not set, dlopen operates as if
+DYLD_FALLBACK_FRAMEWORK_PATH was set to $HOME/Library/Frameworks:/Library/Frameworks:/Network/Library/Frameworks:/System/Library/Frameworks.
.Pp
Note: There are no configuration files to control dlopen searching.
.Pp
.Fn dlopen
fails, it returns a null pointer, and sets an error condition which may be interrogated with
.Fn dlerror .
-.Sh AUTHORS
-Mac OS X 10.3 incorporated the dlcompat package written by Jorge Acereda <jacereda@users.sourceforge.net>
-and Peter O'Gorman <ogorman@users.sourceforge.net>.
-.Pp
-In Mac OS X 10.4, dlopen was rewritten to be a native part of dyld.
.Pp
.Sh SEE ALSO
.Xr dlopen_preflight 3
.Xr dlclose 3
.Xr dlsym 3
.Xr dlerror 3
-.Xr dyld 3
+.Xr dyld 1
.Xr ld 1
name.
.Sh SEE ALSO
.Xr dlopen 3
-.Xr dlsym 3
.Xr dlerror 3
.Xr dyld 3
.Xr ld 1
F908137111D3FB5000626CC1 /* usr|local|include|mach-o */,
F908137211D3FB5000626CC1 /* usr|share|man|man1 */,
F908137311D3FB5000626CC1 /* usr|share|man|man3 */,
+ F9F479FE152A63F2008F75C2 /* simulator clean up */,
);
dependencies = (
F9B4D78012AD9736000605A6 /* PBXTargetDependency */,
F908136D11D3FB3A00626CC1 /* dyld.3 in usr|share|man|man3 */ = {isa = PBXBuildFile; fileRef = EF799FF0070D27BB00F78484 /* dyld.3 */; };
F908136E11D3FB3A00626CC1 /* dlopen_preflight.3 in usr|share|man|man3 */ = {isa = PBXBuildFile; fileRef = F9E572000A66EF41007D9BE9 /* dlopen_preflight.3 */; };
F913FADA0630A8AE00B7AE9D /* dyldAPIsInLibSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F913FAD90630A8AE00B7AE9D /* dyldAPIsInLibSystem.cpp */; };
+ F93666E0163B4C42002ECADA /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F93666DF163B4C42002ECADA /* CoreFoundation.framework */; };
+ F93666E2163B4C58002ECADA /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F93666E1163B4C58002ECADA /* Security.framework */; };
F93937470A94FC4700070A07 /* update_dyld_shared_cache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F93937460A94FC4700070A07 /* update_dyld_shared_cache.cpp */; };
F94DB9040F0A9B1700323715 /* ImageLoaderMachOClassic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F94DB9000F0A9B1700323715 /* ImageLoaderMachOClassic.cpp */; };
F94DB9050F0A9B1700323715 /* ImageLoaderMachOCompressed.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F94DB9020F0A9B1700323715 /* ImageLoaderMachOCompressed.cpp */; settings = {COMPILER_FLAGS = "-O3"; }; };
F908135111D3ED9000626CC1 /* usr|include|mach-o */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
- dstPath = "/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 = /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 = "/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 */,
F9C69EFC14EC8AB8009CAE2E /* usr|local|include */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
- dstPath = /usr/local/include;
+ dstPath = "$(INSTALL_PATH_PREFIX)//usr/local/include";
dstSubfolderSpec = 0;
files = (
F9C69EFE14EC8AD2009CAE2E /* objc-shared-cache.h in usr|local|include */,
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>"; };
+ F93666E1163B4C58002ECADA /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = /System/Library/Frameworks/Security.framework; sourceTree = "<absolute>"; };
F93937320A94FAF700070A07 /* update_dyld_shared_cache */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = update_dyld_shared_cache; sourceTree = BUILT_PRODUCTS_DIR; };
F939373E0A94FC4700070A07 /* Architectures.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Architectures.hpp; sourceTree = "<group>"; };
F939373F0A94FC4700070A07 /* CacheFileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CacheFileAbstraction.hpp; sourceTree = "<group>"; };
F93937410A94FC4700070A07 /* FileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = FileAbstraction.hpp; sourceTree = "<group>"; };
F93937430A94FC4700070A07 /* MachOFileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = MachOFileAbstraction.hpp; sourceTree = "<group>"; };
F93937440A94FC4700070A07 /* MachOLayout.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = MachOLayout.hpp; sourceTree = "<group>"; };
- F93937460A94FC4700070A07 /* update_dyld_shared_cache.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = update_dyld_shared_cache.cpp; sourceTree = "<group>"; };
- F939F219078F1A2100AC144F /* dyld_debug.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dyld_debug.h; path = "include/mach-o/dyld_debug.h"; sourceTree = "<group>"; };
+ F93937460A94FC4700070A07 /* update_dyld_shared_cache.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = update_dyld_shared_cache.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
F94DB9000F0A9B1700323715 /* ImageLoaderMachOClassic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ImageLoaderMachOClassic.cpp; path = src/ImageLoaderMachOClassic.cpp; sourceTree = "<group>"; };
F94DB9010F0A9B1700323715 /* ImageLoaderMachOClassic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ImageLoaderMachOClassic.h; path = src/ImageLoaderMachOClassic.h; sourceTree = "<group>"; };
F94DB9020F0A9B1700323715 /* ImageLoaderMachOCompressed.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ImageLoaderMachOCompressed.cpp; path = src/ImageLoaderMachOCompressed.cpp; sourceTree = "<group>"; };
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>"; };
+ 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>"; };
F98D274C0AA79D7400416316 /* dyld_images.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dyld_images.h; path = "include/mach-o/dyld_images.h"; sourceTree = "<group>"; };
F9A6D70B116FBBD10051CC16 /* threadLocalHelpers.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = threadLocalHelpers.s; path = src/threadLocalHelpers.s; sourceTree = "<group>"; };
F9AB709D0BA75730002F6068 /* dyldLibSystemInterface.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dyldLibSystemInterface.h; path = src/dyldLibSystemInterface.h; sourceTree = "<group>"; };
F9AC7E930B7BB67700FEB38B /* version.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = version.c; sourceTree = BUILT_PRODUCTS_DIR; };
+ F9AFEA3216F15CE300CB5161 /* start_glue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = start_glue.h; path = src/start_glue.h; sourceTree = "<group>"; };
F9B01E3D0739ABDE00CF981B /* dyld.exp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.exports; name = dyld.exp; path = src/dyld.exp; sourceTree = SOURCE_ROOT; };
F9C69EFD14EC8ABF009CAE2E /* objc-shared-cache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objc-shared-cache.h"; path = "include/objc-shared-cache.h"; sourceTree = "<group>"; };
F9CE30781208F1B50098B590 /* dsc_extractor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dsc_extractor.cpp; sourceTree = "<group>"; };
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ F93666E2163B4C58002ECADA /* Security.framework in Frameworks */,
+ F93666E0163B4C42002ECADA /* CoreFoundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F939373D0A94FC4700070A07 /* launch-cache */ = {
isa = PBXGroup;
children = (
+ F93666E1163B4C58002ECADA /* Security.framework */,
+ F93666DF163B4C42002ECADA /* CoreFoundation.framework */,
F939373E0A94FC4700070A07 /* Architectures.hpp */,
F939373F0A94FC4700070A07 /* CacheFileAbstraction.hpp */,
F93937400A94FC4700070A07 /* dyld_cache_format.h */,
F9ED4C990630A76000DF4E74 /* Products */,
F939373D0A94FC4700070A07 /* launch-cache */,
);
+ indentWidth = 4;
sourceTree = "<group>";
+ tabWidth = 4;
+ usesTabs = 1;
};
F9ED4C990630A76000DF4E74 /* Products */ = {
isa = PBXGroup;
F9ED4CCE0630A7F100DF4E74 /* dyldNew.cpp */,
F9ED4CCF0630A7F100DF4E74 /* dyldStartup.s */,
F9D49CCB1458B95200F86ADD /* start_glue.s */,
+ F9AFEA3216F15CE300CB5161 /* start_glue.h */,
F99EFC0D0EAD60E8001032B8 /* dyld_stub_binder.s */,
F9ED4CD00630A7F100DF4E74 /* glue.c */,
+ F981BB8B170FC24400A686D6 /* dyldSyscallInterface.h */,
F9ED4CD10630A7F100DF4E74 /* ImageLoader.cpp */,
F9ED4CD20630A7F100DF4E74 /* ImageLoader.h */,
F9ED4CD30630A7F100DF4E74 /* ImageLoaderMachO.cpp */,
F98D274C0AA79D7400416316 /* dyld_images.h */,
F9ED4CE80630A80600DF4E74 /* dyld_gdb.h */,
F9ED4CE90630A80600DF4E74 /* dyld_priv.h */,
- F939F219078F1A2100AC144F /* dyld_debug.h */,
F9ED4CEA0630A80600DF4E74 /* dyld.h */,
F99EE6AE06B48D4200BF1992 /* dlfcn.h */,
F9C69EFD14EC8ABF009CAE2E /* objc-shared-cache.h */,
isa = PBXNativeTarget;
buildConfigurationList = F93937340A94FB2900070A07 /* Build configuration list for PBXNativeTarget "update_dyld_shared_cache" */;
buildPhases = (
+ F91083C91702592700831889 /* create dyld_cache_config.h */,
F939372F0A94FAF700070A07 /* Sources */,
F93937300A94FAF700070A07 /* Frameworks */,
F9D238DD0A9E2FEE002B55C7 /* usr|share|man|man1 */,
shellScript = "if [ \"${PLATFORM_NAME}\" = \"iphoneos\" ] \nthen\n\tmkdir -p ${DSTROOT}//System/Library/Caches/com.apple.dyld\n\techo \"existence of this file enables dyld to have dylibs override shared cache\" > ${DSTROOT}//System/Library/Caches/com.apple.dyld/enable-dylibs-to-override-cache\nfi\n";
showEnvVarsInLog = 0;
};
+ F91083C91702592700831889 /* create dyld_cache_config.h */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "create dyld_cache_config.h";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/dyld_cache_config.h",
+ );
+ 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";
+ showEnvVarsInLog = 0;
+ };
F991E3030FF1A4EC0082CCC9 /* do not install duplicates */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 8;
);
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/Platforms/iPhoneOS.platform/usr/lib\"\n mv \"${DSTROOT}/Developer/Platforms/iPhoneOS.platform/usr/local/lib/dsc_extractor.bundle\" \"${DSTROOT}/Developer/Platforms/iPhoneOS.platform/usr/lib/dsc_extractor.bundle\"\nfi";
+ 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";
showEnvVarsInLog = 0;
};
F99B8EB60FEC236500701838 /* suppress macosx dyld_shared_cache_util */ = {
);
runOnlyForDeploymentPostprocessing = 0;
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";
+ 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;
+ };
+ F9F479FE152A63F2008F75C2 /* simulator clean up */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "simulator clean up";
+ outputPaths = (
+ );
+ 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";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
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_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_THREADSAFE_STATICS = NO;
+ GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
GCC_WARN_EFFECTIVE_CPLUSPLUS_VIOLATIONS = NO;
GCC_WARN_MISSING_PARENTHESES = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = "$(SRCROOT)/include";
+ OTHER_CPLUSPLUSFLAGS = (
+ "-stdlib=libc++",
+ "$(OTHER_CFLAGS)",
+ );
+ OTHER_LDFLAGS = "-stdlib=libc++";
PRODUCT_NAME = update_dyld_shared_cache;
VALID_ARCHS = "x86_64 i386";
};
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = s;
GCC_THREADSAFE_STATICS = 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";
LOCAL = "$(LOCAL_$(RC_TARGET_CONFIG))";
LOCAL_iPhone = local;
+ OTHER_CPLUSPLUSFLAGS = (
+ "-stdlib=libc++",
+ "$(OTHER_CFLAGS)",
+ );
+ OTHER_LDFLAGS = "-stdlib=libc++";
PRODUCT_NAME = update_dyld_shared_cache;
STRIP_INSTALLED_PRODUCT = YES;
STRIP_STYLE = debugging;
ALWAYS_SEARCH_USER_PATHS = NO;
COPY_PHASE_STRIP = YES;
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";
PRODUCT_NAME = dyld_shared_cache_util;
GCC_OPTIMIZATION_LEVEL = 0;
INSTALL_PATH = "$(INSTALL_LOCATION)/usr/local/lib";
MACH_O_TYPE = mh_bundle;
- OTHER_LDFLAGS = "-Wl,-exported_symbol,_dyld_shared_cache_extract_dylibs_progress";
+ OTHER_CPLUSPLUSFLAGS = (
+ "-stdlib=libc++",
+ "$(OTHER_CFLAGS)",
+ );
+ OTHER_LDFLAGS = (
+ "-stdlib=libc++",
+ "-Wl,-exported_symbol,_dyld_shared_cache_extract_dylibs_progress",
+ );
PRODUCT_NAME = dsc_extractor;
};
name = Debug;
GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
INSTALL_PATH = "$(INSTALL_LOCATION)/usr/local/lib";
MACH_O_TYPE = mh_bundle;
- OTHER_LDFLAGS = "-Wl,-exported_symbol,_dyld_shared_cache_extract_dylibs_progress";
+ OTHER_CPLUSPLUSFLAGS = (
+ "-stdlib=libc++",
+ "$(OTHER_CFLAGS)",
+ );
+ OTHER_LDFLAGS = (
+ "-stdlib=libc++",
+ "-Wl,-exported_symbol,_dyld_shared_cache_extract_dylibs_progress",
+ );
PRODUCT_NAME = dsc_extractor;
ZERO_LINK = NO;
};
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;
CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
- EXPORTED_SYMBOLS_FILE = "$(SRCROOT)/src/dyld.exp";
+ 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;
"./launch-cache",
);
INSTALL_PATH = /usr/lib;
+ LD_GENERATE_MAP_FILE = YES;
OTHER_CFLAGS = "";
+ OTHER_CPLUSPLUSFLAGS = (
+ "-stdlib=libc++",
+ "$(OTHER_CFLAGS)",
+ );
OTHER_LDFLAGS = (
"-seg1addr",
"$(BASE_ADDRESS_$(CURRENT_ARCH))",
"@$(DERIVED_SOURCES_DIR)/archives.txt",
"-nostdlib",
- "-Wl,-e,__dyld_start",
"-Wl,-dylinker",
"-Wl,-dylinker_install_name,/usr/lib/dyld",
+ "-stdlib=libc++",
+ "$(ALIGNMENT_$(CURRENT_ARCH))",
+ "$(ENTRY_$(PLATFORM_NAME))",
);
- PRODUCT_NAME = dyld;
+ 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";
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;
CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- EXPORTED_SYMBOLS_FILE = "$(SRCROOT)/src/dyld.exp";
+ 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;
"./launch-cache",
);
INSTALL_PATH = /usr/lib;
+ LD_GENERATE_MAP_FILE = YES;
ORDER_FILE = "$(SRCROOT)/src/dyld.order";
"OTHER_CFLAGS[arch=armv6]" = "-mthumb";
+ OTHER_CPLUSPLUSFLAGS = (
+ "-stdlib=libc++",
+ "$(OTHER_CFLAGS)",
+ );
OTHER_LDFLAGS = (
"-seg1addr",
"$(BASE_ADDRESS_$(CURRENT_ARCH))",
"@$(DERIVED_SOURCES_DIR)/archives.txt",
"-nostdlib",
- "-Wl,-e,__dyld_start",
"-Wl,-dylinker",
"-Wl,-dylinker_install_name,/usr/lib/dyld",
+ "-stdlib=libc++",
+ "$(ALIGNMENT_$(CURRENT_ARCH))",
+ "$(ENTRY_$(PLATFORM_NAME))",
);
- PRODUCT_NAME = dyld;
+ 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";
isa = XCBuildConfiguration;
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_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
HEADER_SEARCH_PATHS = "$(SRCROOT)/include";
INSTALL_PATH = /usr/lib/system;
- PRODUCT_NAME = dyld;
+ 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_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;
WARNING_CFLAGS = (
"-Wmost",
"-Wno-four-char-constants",
);
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;
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)",
+ );
OTHER_LDFLAGS = (
- "-nodefaultlibs",
- "-Wl,-upward-lSystem",
+ "-nostdlib",
+ "$(LIBSYSTEM_LIBS)",
"-umbrella",
System,
+ "$(EXPORT_OPTIONS_$(PLATFORM_NAME))",
+ "-L$(SDKROOT)/usr/lib/system",
);
- PRODUCT_NAME = dyld;
+ PRODUCT_NAME = "$(PRODUCT_NAME_$(PLATFORM_NAME))";
+ PRODUCT_NAME_iphoneos = dyld;
+ PRODUCT_NAME_iphonesimulator = dyld_sim;
+ PRODUCT_NAME_macosx = dyld;
SEPARATE_STRIP = YES;
STRIP_INSTALLED_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
GCC_OPTIMIZATION_LEVEL = 0;
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
INSTALL_PATH = /usr/local/lib;
+ OTHER_CPLUSPLUSFLAGS = (
+ "-stdlib=libc++",
+ "$(OTHER_CFLAGS)",
+ );
PRODUCT_NAME = dsc;
};
name = Debug;
GCC_WARN_UNUSED_VARIABLE = YES;
INSTALLHDRS_COPY_PHASE = YES;
INSTALL_PATH = "$(INSTALL_LOCATION)/usr/local/lib";
+ OTHER_CPLUSPLUSFLAGS = (
+ "-stdlib=libc++",
+ "$(OTHER_CFLAGS)",
+ );
PRODUCT_NAME = dsc;
ZERO_LINK = NO;
};
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
#include <stdbool.h>
-#include <AvailabilityMacros.h>
+#include <Availability.h>
/*
* Structure filled in by dladdr().
*/
extern void * dlsym(void * __handle, const char * __symbol);
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
-extern bool dlopen_preflight(const char* __path) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
+extern bool dlopen_preflight(const char* __path) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
#endif /* not POSIX */
/*
- * NSVersionOfRunTimeLibrary() returns the current_version number that the main executable was linked
+ * NSVersionOfLinkTimeLibrary() returns the current_version number that the main executable was linked
* against at build time. The libraryName parameter would be "bar" for /path/libbar.3.dylib and
* "Foo" for /path/Foo.framework/Versions/A/Foo. It returns -1 if the main executable did not link
* against the specified library.
+++ /dev/null
-/*
- * Copyright (c) 1999 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@
- */
-#ifndef _DYLD_DEBUG_
-#define _DYLD_DEBUG_
-
-#include <mach/mach.h>
-#ifndef DYLD_BUILD /* do not include this when building dyld itself */
-#include <mach-o/dyld.h>
-#endif /* !defined(DYLD_BUILD) */
-
-#include <AvailabilityMacros.h>
-
-/*
- * The dyld debugging API is deprecated as of Mac OS X 10.4
- */
-enum dyld_debug_return {
- DYLD_SUCCESS,
- DYLD_INCONSISTENT_DATA,
- DYLD_INVALID_ARGUMENTS,
- DYLD_FAILURE
-};
-
-struct dyld_debug_module {
- struct mach_header *header;
- unsigned long vmaddr_slide;
- unsigned long module_index;
-};
-
-enum dyld_event_type {
- DYLD_IMAGE_ADDED,
- DYLD_MODULE_BOUND,
- DYLD_MODULE_REMOVED,
- DYLD_MODULE_REPLACED,
- DYLD_PAST_EVENTS_END,
- DYLD_IMAGE_REMOVED
-};
-
-struct dyld_event {
- enum dyld_event_type type;
- struct dyld_debug_module arg[2];
-};
-
-extern enum dyld_debug_return _dyld_debug_defining_module(
- mach_port_t target_task,
- unsigned long send_timeout,
- unsigned long rcv_timeout,
- boolean_t inconsistent_data_ok,
- char *name,
- struct dyld_debug_module *module) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4;
-
-extern enum dyld_debug_return _dyld_debug_is_module_bound(
- mach_port_t target_task,
- unsigned long send_timeout,
- unsigned long rcv_timeout,
- boolean_t inconsistent_data_ok,
- struct dyld_debug_module module,
- boolean_t *bound) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4;
-
-extern enum dyld_debug_return _dyld_debug_bind_module(
- mach_port_t target_task,
- unsigned long send_timeout,
- unsigned long rcv_timeout,
- boolean_t inconsistent_data_ok,
- struct dyld_debug_module module) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4;
-
-extern enum dyld_debug_return _dyld_debug_module_name(
- mach_port_t target_task,
- unsigned long send_timeout,
- unsigned long rcv_timeout,
- boolean_t inconsistent_data_ok,
- struct dyld_debug_module module,
- char **image_name,
- unsigned long *image_nameCnt,
- char **module_name,
- unsigned long *module_nameCnt) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4;
-
-extern enum dyld_debug_return _dyld_debug_subscribe_to_events(
- mach_port_t target_task,
- unsigned long send_timeout,
- unsigned long rcv_timeout,
- boolean_t inconsistent_data_ok,
- void (*dyld_event_routine)(struct dyld_event event)) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4;
-
-/*
- * _dyld_debug_add_event_subscriber() uses the mig interface functions below
- * to dispatch the dyld event messages from the subscriber port specified.
- */
-extern enum dyld_debug_return _dyld_debug_add_event_subscriber(
- mach_port_t target_task,
- unsigned long send_timeout,
- unsigned long rcv_timeout,
- boolean_t inconsistent_data_ok,
- mach_port_t subscriber) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4;
-
-/*
- * These structures should be produced by mig(1) from the mig generated files
- * but they are not. These are really only needed so the correct size of the
- * request and reply messages can be allocated.
- */
-struct _dyld_event_message_request {
-#ifdef __MACH30__
- mach_msg_header_t head;
- NDR_record_t NDR;
- struct dyld_event event;
- mach_msg_trailer_t trailer;
-#else
- msg_header_t head;
- msg_type_t eventType;
- struct dyld_event event;
-#endif
-};
-struct _dyld_event_message_reply {
-#ifdef __MACH30__
- mach_msg_header_t head;
- NDR_record_t NDR;
- struct dyld_event event;
-#else
- msg_header_t head;
- msg_type_t RetCodeType;
- kern_return_t RetCode;
-#endif
-};
-#ifndef mig_internal
-/*
- * _dyld_event_server() is the mig generated routine to dispatch dyld event
- * messages.
- */
-extern boolean_t _dyld_event_server(
-#ifdef __MACH30__
- mach_msg_header_t *request,
- mach_msg_header_t *reply);
-#else
- struct _dyld_event_message_request *request,
- struct _dyld_event_message_reply *reply);
-#endif
-#endif /* mig_internal */
-
-#ifndef SHLIB
-/*
- * _dyld_event_server_callback() is the routine called by _dyld_event_server()
- * that must be written by users of _dyld_event_server().
- */
-extern
-#ifdef __MACH30__
-kern_return_t
-#else
-void
-#endif
-_dyld_event_server_callback(
-#ifdef __MACH30__
- mach_port_t subscriber,
-#else
- port_t subscriber,
-#endif
- struct dyld_event event);
-#endif /* SHLIB */
-
-/*
- * This is the state of the target task while we are sending a message to it.
- */
-struct _dyld_debug_task_state {
- mach_port_t debug_port;
- mach_port_t debug_thread;
- unsigned int debug_thread_resume_count;
- unsigned int task_resume_count;
- mach_port_t *threads;
- unsigned int thread_count;
-};
-
-/*
- * _dyld_debug_make_runnable() is called before sending messages to the
- * dynamic link editor. Basically it assures that the debugging
- * thread is the only runnable thread in the task to receive the
- * message. It also assures that the debugging thread is indeed
- * runnable if it was suspended. The function will make sure each
- * thread in the remote task is suspended and resumed the same number
- * of times, so in the end the suspend count of each individual thread
- * is the same.
- */
-extern enum dyld_debug_return _dyld_debug_make_runnable(
- mach_port_t target_task,
- struct _dyld_debug_task_state *state) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4;
-
-/*
- * _dyld_debug_restore_runnable() is called after sending messages to the
- * dynamic link editor. It undoes what _dyld_debug_make_runnable() did to the
- * task and put it back the way it was.
- */
-extern enum dyld_debug_return _dyld_debug_restore_runnable(
- mach_port_t target_task,
- struct _dyld_debug_task_state *state) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4;
-
-/*
- * To provide more detailed information when the APIs of the dyld debug
- * interfaces fail (return DYLD_FAILURE) the following structure is filled in.
- * After it is filled in the function registered with
- * set_dyld_debug_error_func() is called with a pointer to that struct.
- *
- * The local_error field is a unique number for each possible error condition
- * in the source code in that makes up the dyld debug APIs. The source file
- * and line number in the cctools libdyld directory where the dyld debug APIs
- * are implemented are set into the file_name and line_number fields. The
- * field dyld_debug_return is filled in with that would be returned by the
- * API (usually DYLD_FAILURE). The other fields will be zero or filled in by
- * the error code from the mach system call, or UNIX system call that failed.
- */
-struct dyld_debug_error_data {
- enum dyld_debug_return dyld_debug_return;
- kern_return_t mach_error;
- int dyld_debug_errno;
- unsigned long local_error;
- char *file_name;
- unsigned long line_number;
-};
-
-extern void _dyld_debug_set_error_func(
- void (*func)(struct dyld_debug_error_data *e)) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4;
-
-#ifndef DYLD_BUILD /* do not include this when building dyld itself */
-
-extern enum dyld_debug_return _dyld_debug_task_from_core(
- NSObjectFileImage coreFileImage,
- mach_port_t *core_task) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4;
-
-#endif /* !defined(DYLD_BUILD) */
-
-#endif /* _DYLD_DEBUG_ */
*
*/
-enum dyld_image_mode { dyld_image_adding=0, dyld_image_removing=1 };
+enum dyld_image_mode { dyld_image_adding=0, dyld_image_removing=1, dyld_image_info_change=2 };
struct dyld_image_info {
const struct mach_header* imageLoadAddress; /* base address image is mapped into */
const char* errorSymbol;
/* the following field is only in version 12 (Mac OS X 10.7, iOS 4.3) and later */
uintptr_t sharedCacheSlide;
+ /* the following field is only in version 13 (Mac OS X 10.9, iOS 7.0) and later */
+ uint8_t sharedCacheUUID[16];
+ /* the following field is only in version 14 (Mac OS X 10.9, iOS 7.0) and later */
+ uintptr_t reserved[16];
};
-extern struct dyld_all_image_infos dyld_all_image_infos;
-
-/*
- * Beginning in Mac OS X 10.6, rather than looking up the symbol "_dyld_all_image_infos"
- * in dyld's symbol table, you can add DYLD_ALL_IMAGE_INFOS_OFFSET_OFFSET to the mach_header
- * for dyld and read the 32-bit unsigned int at that location. Adding that value to dyld's
- * mach_header address gets you the address of dyld_all_image_infos in dyld.
- */
-#define DYLD_ALL_IMAGE_INFOS_OFFSET_OFFSET 0x1010
-
/*
+// Convienence constants for return values from dyld_get_sdk_version() and friends.
+#define DYLD_MACOSX_VERSION_10_4 0x000A0400
+#define DYLD_MACOSX_VERSION_10_5 0x000A0500
+#define DYLD_MACOSX_VERSION_10_6 0x000A0600
+#define DYLD_MACOSX_VERSION_10_7 0x000A0700
+#define DYLD_MACOSX_VERSION_10_8 0x000A0800
+#define DYLD_MACOSX_VERSION_10_9 0x000A0900
+
+#define DYLD_IOS_VERSION_2_0 0x00020000
+#define DYLD_IOS_VERSION_2_1 0x00020100
+#define DYLD_IOS_VERSION_2_2 0x00020200
+#define DYLD_IOS_VERSION_3_0 0x00030000
+#define DYLD_IOS_VERSION_3_1 0x00030100
+#define DYLD_IOS_VERSION_3_2 0x00030200
+#define DYLD_IOS_VERSION_4_0 0x00040000
+#define DYLD_IOS_VERSION_4_1 0x00040100
+#define DYLD_IOS_VERSION_4_2 0x00040200
+#define DYLD_IOS_VERSION_4_3 0x00040300
+#define DYLD_IOS_VERSION_5_0 0x00050000
+#define DYLD_IOS_VERSION_5_1 0x00050100
+#define DYLD_IOS_VERSION_6_0 0x00060000
+#define DYLD_IOS_VERSION_6_1 0x00060100
+#define DYLD_IOS_VERSION_7_0 0x00070000
//
// This is finds the SDK version a binary was built against.
// Returns zero on error, or if SDK version could not be determined.
//
// Exists in Mac OS X 10.8 and later
+// Exists in iOS 6.0 and later
extern uint32_t dyld_get_sdk_version(const struct mach_header* mh);
// Returns zero on error, or if SDK version could not be determined.
//
// Exists in Mac OS X 10.8 and later
+// Exists in iOS 6.0 and later
extern uint32_t dyld_get_program_sdk_version();
// Returns zero on error, or if no min OS recorded in binary.
//
// Exists in Mac OS X 10.8 and later
+// Exists in iOS 6.0 and later
extern uint32_t dyld_get_min_os_version(const struct mach_header* mh);
// Returns zero on error, or if no min OS recorded in binary.
//
// Exists in Mac OS X 10.8 and later
+// Exists in iOS 6.0 and later
extern uint32_t dyld_get_program_min_os_version();
extern bool dyld_shared_cache_some_image_overridden();
#endif
+
+
+//
+// Returns if the process is setuid or is code signed with entitlements.
+//
+// Exists in Mac OS X 10.9 and later
+extern bool dyld_process_is_restricted();
+
+
+//
+// <rdar://problem/13820686> for OpenGL to tell dyld it is ok to deallocate a memory based image when done.
+//
+// Exists in Mac OS X 10.9 and later
+#define NSLINKMODULE_OPTION_CAN_UNLOAD 0x20
+
#if __cplusplus
#include <stdint.h>
#include <stdlib.h>
#ifdef SELOPT_WRITE
-#include <ext/hash_map>
+#include <unordered_map>
#endif
/*
DO NOT INCLUDE ANY objc HEADERS HERE
typedef int32_t objc_stringhash_offset_t;
typedef uint8_t objc_stringhash_check_t;
+static uint64_t lookup8( uint8_t *k, size_t length, uint64_t level);
+
#ifdef SELOPT_WRITE
// Perfect hash code is at the end of this file.
}
};
+struct hashstr {
+ size_t operator()(const char *s) const {
+ return (size_t)lookup8((uint8_t *)s, strlen(s), 0);
+ }
+};
+
// cstring => cstring's vmaddress
// (used for selector names and class names)
-typedef __gnu_cxx::hash_map<const char *, uint64_t, __gnu_cxx::hash<const char *>, eqstr> string_map;
+typedef std::unordered_map<const char *, uint64_t, hashstr, eqstr> string_map;
// class name => (class vmaddress, header_info vmaddress)
-typedef __gnu_cxx::hash_multimap<const char *, std::pair<uint64_t, uint64_t>, __gnu_cxx::hash<const char *>, eqstr> class_map;
+typedef std::unordered_multimap<const char *, std::pair<uint64_t, uint64_t>, hashstr, eqstr> class_map;
static perfect_hash make_perfect(const string_map& strings);
#endif
-static uint64_t lookup8( uint8_t *k, size_t length, uint64_t level);
// Precomputed perfect hash table of strings.
// Base class for precomputed selector table and class table.
objc_stringhash_offset_t *offsets() { return (objc_stringhash_offset_t *)&checkbytes()[capacity]; }
const objc_stringhash_offset_t *offsets() const { return (const objc_stringhash_offset_t *)&checkbytes()[capacity]; }
- uint32_t hash(const char *key) const
+ uint32_t hash(const char *key, size_t keylen) const
{
- uint64_t val = lookup8((uint8_t*)key, strlen(key), salt);
+ uint64_t val = lookup8((uint8_t*)key, keylen, salt);
uint32_t index = (uint32_t)(val>>shift) ^ scramble[tab[val&mask]];
return index;
}
+ uint32_t hash(const char *key) const
+ {
+ return hash(key, strlen(key));
+ }
+
// The check bytes areused to reject strings that aren't in the table
// without paging in the table's cstring data. This checkbyte calculation
// catches 4785/4815 rejects when launching Safari; a perfect checkbyte
// would catch 4796/4815.
- objc_stringhash_check_t checkbyte(const char *key) const
+ objc_stringhash_check_t checkbyte(const char *key, size_t keylen) const
{
return
((key[0] & 0x7) << 5)
|
- (strlen(key) & 0x1f);
+ ((uint8_t)keylen & 0x1f);
}
+ objc_stringhash_check_t checkbyte(const char *key) const
+ {
+ return checkbyte(key, strlen(key));
+ }
+
+
#define INDEX_NOT_FOUND (~(uint32_t)0)
uint32_t getIndex(const char *key) const
{
- uint32_t h = hash(key);
+ size_t keylen = strlen(key);
+ uint32_t h = hash(key, keylen);
// Use check byte to reject without paging in the table's cstrings
objc_stringhash_check_t h_check = checkbytes()[h];
- objc_stringhash_check_t key_check = checkbyte(key);
+ objc_stringhash_check_t key_check = checkbyte(key, keylen);
bool check_fail = (h_check != key_check);
#if ! SELOPT_DEBUG
if (check_fail) return INDEX_NOT_FOUND;
#endif
- const char *result = (const char *)this + offsets()[h];
+ // fixme change &zero to 0 in the next version-breaking update
+ objc_stringhash_offset_t offset = offsets()[h];
+ if (offset == offsetof(objc_stringhash_t,zero)) return INDEX_NOT_FOUND;
+ const char *result = (const char *)this + offset;
if (0 != strcmp(key, result)) return INDEX_NOT_FOUND;
#if SELOPT_DEBUG
uint64_t slideInfoSize() const INLINE { return E::get64(fields.slideInfoSize); }
void set_slideInfoSize(uint64_t value) INLINE { E::set64(fields.slideInfoSize, value); }
+ uint64_t localSymbolsOffset() const INLINE { return E::get64(fields.localSymbolsOffset); }
+ void set_localSymbolsOffset(uint64_t value) INLINE { E::set64(fields.localSymbolsOffset, value); }
+
+ uint64_t localSymbolsSize() const INLINE { return E::get64(fields.localSymbolsSize); }
+ void set_localSymbolsSize(uint64_t value) INLINE { E::set64(fields.localSymbolsSize, value); }
+
+ const uint8_t* uuid() const INLINE { return fields.uuid; }
+ void set_uuid(const uint8_t value[16]) INLINE { memcpy(fields.uuid, value, 16); }
+
private:
dyld_cache_header fields;
};
+template <typename E>
+class dyldCacheLocalSymbolsInfo {
+public:
+ uint32_t nlistOffset() const INLINE { return E::get32(fields.nlistOffset); }
+ void set_nlistOffset(uint32_t value) INLINE { E::set32(fields.nlistOffset, value); }
+
+ uint32_t nlistCount() const INLINE { return E::get32(fields.nlistCount); }
+ void set_nlistCount(uint32_t value) INLINE { E::set32(fields.nlistCount, value); }
+
+ uint32_t stringsOffset() const INLINE { return E::get32(fields.stringsOffset); }
+ void set_stringsOffset(uint32_t value) INLINE { E::set32(fields.stringsOffset, value); }
+
+ uint32_t stringsSize() const INLINE { return E::get32(fields.stringsSize); }
+ void set_stringsSize(uint32_t value) INLINE { E::set32(fields.stringsSize, value); }
+
+ uint32_t entriesOffset() const INLINE { return E::get32(fields.entriesOffset); }
+ void set_entriesOffset(uint32_t value) INLINE { E::set32(fields.entriesOffset, value); }
+
+ uint32_t entriesCount() const INLINE { return E::get32(fields.entriesCount); }
+ void set_entriesCount(uint32_t value) INLINE { E::set32(fields.entriesCount, value); }
+
+private:
+ dyld_cache_local_symbols_info fields;
+};
+
+
+template <typename E>
+class dyldCacheLocalSymbolEntry {
+public:
+ uint32_t dylibOffset() const INLINE { return E::get32(fields.dylibOffset); }
+ void set_dylibOffset(uint32_t value) INLINE { E::set32(fields.dylibOffset, value); }
+
+ uint32_t nlistStartIndex() const INLINE { return E::get32(fields.nlistStartIndex); }
+ void set_nlistStartIndex(uint32_t value) INLINE { E::set32(fields.nlistStartIndex, value); }
+
+ uint32_t nlistCount() const INLINE { return E::get32(fields.nlistCount); }
+ void set_nlistCount(uint32_t value) INLINE { E::set32(fields.nlistCount, value); }
+
+private:
+ dyld_cache_local_symbols_entry fields;
+};
+
+
+
+
#endif // __DYLD_CACHE_ABSTRACTION__
#include <vector>
#include <set>
-#include <ext/hash_map>
-#include <ext/hash_set>
+#include <unordered_map>
+#include <unordered_set>
#include "MachOFileAbstraction.hpp"
#include "Architectures.hpp"
#define EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER 0x10
#endif
+#ifndef EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
+ #define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02
+#endif
template <typename A>
class Binder : public Rebaser<A>
{
public:
+ class CStringHash {
+ public:
+ size_t operator()(const char* __s) const {
+ size_t __h = 0;
+ for ( ; *__s; ++__s)
+ __h = 5 * __h + *__s;
+ return __h;
+ };
+ };
struct CStringEquals {
bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
};
- typedef __gnu_cxx::hash_map<const char*, class Binder<A>*, __gnu_cxx::hash<const char*>, CStringEquals> Map;
+ typedef std::unordered_map<const char*, class Binder<A>*, CStringHash, CStringEquals> Map;
Binder(const MachOLayoutAbstraction&, uint64_t dyldBaseAddress);
void bind(std::vector<void*>&);
void optimize();
void addResolverClient(Binder<A>* clientDylib, const char* symbolName);
- void addResolverLazyPointerMappedAddress(const char* symbolName,
- typename A::P::uint_t lpVMAddr);
private:
typedef typename A::P P;
typedef typename A::P::E E;
typedef typename A::P::uint_t pint_t;
struct BinderAndReExportFlag { Binder<A>* binder; bool reExport; };
struct SymbolReExport { const char* exportName; int dylibOrdinal; const char* importName; };
- typedef __gnu_cxx::hash_map<const char*, pint_t, __gnu_cxx::hash<const char*>, CStringEquals> NameToAddrMap;
- typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> NameSet;
+ typedef std::unordered_map<const char*, pint_t, CStringHash, CStringEquals> NameToAddrMap;
+ typedef std::unordered_set<const char*, CStringHash, CStringEquals> NameSet;
struct ClientAndSymbol { Binder<A>* client; const char* symbolName; };
struct SymbolAndLazyPointer { const char* symbolName; pint_t lpVMAddr; };
const char* symbolName, bool lazyPointer, bool weakImport,
std::vector<void*>& pointersInData);
pint_t resolveUndefined(const macho_nlist<P>* undefinedSymbol);
- bool findExportedSymbolAddress(const char* name, pint_t* result, Binder<A>** foundIn, bool* isResolverSymbol);
+ bool findExportedSymbolAddress(const char* name, pint_t* result, Binder<A>** foundIn,
+ bool* isResolverSymbol, bool* isAbsolute);
void bindStub(uint8_t elementSize, uint8_t* location, pint_t vmlocation, pint_t value);
const char* parentUmbrella();
pint_t runtimeAddressFromNList(const macho_nlist<P>* sym);
std::vector<BinderAndReExportFlag> fDependentDylibs;
NameToAddrMap fHashTable;
NameSet fSymbolResolvers;
+ NameSet fAbsoluteSymbols;
std::vector<SymbolReExport> fReExportedSymbols;
uint64_t fDyldBaseAddress;
const macho_nlist<P>* fSymbolTable;
bool fOriginallyPrebound;
bool fReExportedSymbolsResolved;
std::vector<ClientAndSymbol> fClientAndSymbols;
- std::vector<SymbolAndLazyPointer> fSymbolAndLazyPointers;
+ NameToAddrMap fResolverLazyPointers;
};
template <>
mach_o::trie::parseTrie(exportsStart, exportsEnd, exports);
pint_t baseAddress = layout.getSegments()[0].newAddress();
for(std::vector<mach_o::trie::Entry>::iterator it = exports.begin(); it != exports.end(); ++it) {
- if ( (it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_REGULAR ) {
- if ( (it->flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) ) {
- fSymbolResolvers.insert(it->name);
- }
- if ( it->flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
- //fprintf(stderr, "found re-export %s in %s\n", sym.exportName, this->getDylibID());
- SymbolReExport sym;
- sym.exportName = it->name;
- sym.dylibOrdinal = it->other;
- sym.importName = it->importName;
- if ( (sym.importName == NULL) || (sym.importName[0] == '\0') )
- sym.importName = sym.exportName;
- fReExportedSymbols.push_back(sym);
- // fHashTable entry will be added in first call to findExportedSymbolAddress()
- }
- else {
+ switch ( it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK ) {
+ case EXPORT_SYMBOL_FLAGS_KIND_REGULAR:
+ if ( (it->flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) ) {
+ fSymbolResolvers.insert(it->name);
+ }
+ if ( it->flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
+ //fprintf(stderr, "found re-export %s in %s\n", sym.exportName, this->getDylibID());
+ SymbolReExport sym;
+ sym.exportName = it->name;
+ sym.dylibOrdinal = it->other;
+ sym.importName = it->importName;
+ if ( (sym.importName == NULL) || (sym.importName[0] == '\0') )
+ sym.importName = sym.exportName;
+ fReExportedSymbols.push_back(sym);
+ // fHashTable entry will be added in first call to findExportedSymbolAddress()
+ }
+ else {
+ fHashTable[it->name] = it->address + baseAddress;
+ }
+ break;
+ case EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL:
fHashTable[it->name] = it->address + baseAddress;
- }
- }
- else {
- throwf("non-regular symbol binding not supported for %s in %s", it->name, layout.getFilePath());
+ break;
+ case EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE:
+ fHashTable[it->name] = it->address;
+ fAbsoluteSymbols.insert(it->name);
+ break;
+ default:
+ throwf("non-regular symbol binding not supported for %s in %s", it->name, layout.getFilePath());
+ break;
}
//fprintf(stderr, "0x%08llX %s\n", it->address + baseAddress, it->name);
}
if ( fDynamicInfo->tocoff() == 0 ) {
const macho_nlist<P>* start = &fSymbolTable[fDynamicInfo->iextdefsym()];
const macho_nlist<P>* end = &start[fDynamicInfo->nextdefsym()];
- fHashTable.resize(fDynamicInfo->nextdefsym()); // set initial bucket count
+ fHashTable.reserve(fDynamicInfo->nextdefsym()); // set initial bucket count
for (const macho_nlist<P>* sym=start; sym < end; ++sym) {
const char* name = &fStrings[sym->n_strx()];
fHashTable[name] = runtimeAddressFromNList(sym);
}
else {
int32_t count = fDynamicInfo->ntoc();
- fHashTable.resize(count); // set initial bucket count
+ fHashTable.reserve(count); // set initial bucket count
const struct dylib_table_of_contents* toc = (dylib_table_of_contents*)&this->fLinkEditBase[fDynamicInfo->tocoff()];
for (int32_t i = 0; i < count; ++i) {
const uint32_t index = E::get32(toc[i].symbol_index);
++thisLeafName;
for (typename std::vector<BinderAndReExportFlag>::iterator it = fDependentDylibs.begin(); it != fDependentDylibs.end(); ++it) {
if ( ! it->reExport ) {
- const char* parentUmbrellaName = it->binder->parentUmbrella();
- if ( parentUmbrellaName != NULL ) {
- if ( strcmp(parentUmbrellaName, thisLeafName) == 0 )
- it->reExport = true;
+ Binder<A>* dep = it->binder;
+ if ( dep != NULL ) {
+ const char* parentUmbrellaName = dep->parentUmbrella();
+ if ( parentUmbrellaName != NULL ) {
+ if ( strcmp(parentUmbrellaName, thisLeafName) == 0 )
+ it->reExport = true;
+ }
}
}
}
else
binder = fDependentDylibs[libraryOrdinal-1].binder;
pint_t targetSymbolAddress;
- bool isResolverSymbol;
+ bool isResolverSymbol = false;
+ bool isAbsolute = false;
Binder<A>* foundIn;
if ( weakImport && (binder == NULL) ) {
targetSymbolAddress = 0;
foundIn = NULL;
- isResolverSymbol = false;
}
else {
- if ( ! binder->findExportedSymbolAddress(symbolName, &targetSymbolAddress, &foundIn, &isResolverSymbol) )
+ if ( ! binder->findExportedSymbolAddress(symbolName, &targetSymbolAddress, &foundIn, &isResolverSymbol, &isAbsolute) )
throwf("could not bind symbol %s in %s expected in %s", symbolName, this->getDylibID(), binder->getDylibID());
}
// don't bind lazy pointers to resolver stubs in shared cache
if ( lazyPointer && isResolverSymbol ) {
- if ( foundIn == this ) {
- // record location of lazy pointer for other dylibs to re-use
- pint_t lpVMAddr = segments[segmentIndex].newAddress() + segmentOffset;
- foundIn->addResolverLazyPointerMappedAddress(symbolName, lpVMAddr);
- //fprintf(stderr, "resolver %s in %s has lazy pointer with segmentOffset=0x%08llX\n", symbolName, this->getDylibID(), segmentOffset);
- }
- else {
- // record that this dylib has a lazy pointer to a resolver function
+ if ( foundIn != this ) {
+ // record that this dylib has a lazy pointer to a resolver function
foundIn->addResolverClient(this, symbolName);
// fprintf(stderr, "have lazy pointer to resolver %s in %s\n", symbolName, this->getDylibID());
}
default:
throw "bad bind type";
}
- pointersInData.push_back(mappedAddr);
+ if ( !isAbsolute )
+ pointersInData.push_back(mappedAddr);
}
}
pint_t addr;
bool isResolver;
+ bool isAbsolute;
Binder<A>* foundIn;
- if ( ! binder->findExportedSymbolAddress(symbolName, &addr, &foundIn, &isResolver) )
+ if ( ! binder->findExportedSymbolAddress(symbolName, &addr, &foundIn, &isResolver, &isAbsolute) )
throwf("could not resolve undefined symbol %s in %s expected in %s", symbolName, this->getDylibID(), binder->getDylibID());
return addr;
}
}
template <typename A>
-bool Binder<A>::findExportedSymbolAddress(const char* name, pint_t* result, Binder<A>** foundIn, bool* isResolverSymbol)
+bool Binder<A>::findExportedSymbolAddress(const char* name, pint_t* result, Binder<A>** foundIn, bool* isResolverSymbol, bool* isAbsolute)
{
*foundIn = NULL;
// since re-export chains can be any length, re-exports cannot be resolved in setDependencies()
for (typename std::vector<SymbolReExport>::iterator it=fReExportedSymbols.begin(); it != fReExportedSymbols.end(); ++it) {
pint_t targetSymbolAddress;
bool isResolver;
+ bool isAb;
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;
- if ( ! binder->findExportedSymbolAddress(it->importName, &targetSymbolAddress, foundIn, &isResolver) )
+ if ( ! binder->findExportedSymbolAddress(it->importName, &targetSymbolAddress, foundIn, &isResolver, &isAb) )
throwf("could not bind symbol %s in %s expected in %s", it->importName, this->getDylibID(), binder->getDylibID());
- if ( isResolver )
- throw "bad mach-o binary, re-export of resolvers symbols not supported in dyld shared cache";
+ if ( isResolver )
+ fSymbolResolvers.insert(name);
fHashTable[it->exportName] = targetSymbolAddress;
}
*isResolverSymbol = true;
}
+ // search this dylib
typename NameToAddrMap::iterator pos = fHashTable.find(name);
if ( pos != fHashTable.end() ) {
*result = pos->second;
//fprintf(stderr, "findExportedSymbolAddress(%s) => 0x%08llX in %s\n", name, (uint64_t)*result, this->getDylibID());
*foundIn = this;
+ *isAbsolute = (fAbsoluteSymbols.count(name) != 0);
return true;
}
- // search re-exports
+ // search re-exported dylibs
for (typename std::vector<BinderAndReExportFlag>::iterator it = fDependentDylibs.begin(); it != fDependentDylibs.end(); ++it) {
if ( it->reExport ) {
- if ( it->binder->findExportedSymbolAddress(name, result, foundIn, isResolverSymbol) )
+ if ( it->binder->findExportedSymbolAddress(name, result, foundIn, isResolverSymbol, isAbsolute) )
return true;
}
}
fClientAndSymbols.push_back(x);
}
-// Record that this dylib has an lazy pointer that points within itself for use
-// with a resolver function.
-template <typename A>
-void Binder<A>::addResolverLazyPointerMappedAddress(const char* symbolName, pint_t lpVMAddr)
-{
- SymbolAndLazyPointer x;
- x.symbolName = symbolName;
- x.lpVMAddr = lpVMAddr;
- fSymbolAndLazyPointers.push_back(x);
-}
template <typename A>
typename A::P::uint_t Binder<A>::findLazyPointerFor(const char* symbolName)
{
- for (typename std::vector<SymbolAndLazyPointer>::iterator it = fSymbolAndLazyPointers.begin(); it != fSymbolAndLazyPointers.end(); ++it) {
- if ( strcmp(it->symbolName, symbolName) == 0 )
- return it->lpVMAddr;
- }
+ static const bool log = false;
+
+ // first check cache
+ typename NameToAddrMap::iterator pos = fResolverLazyPointers.find(symbolName);
+ if ( pos != fResolverLazyPointers.end() ) {
+ if ( log ) fprintf(stderr, "found cached shared lazy pointer at 0x%llX for %s in %s\n", (uint64_t)(pos->second), symbolName, this->getDylibID());
+ return pos->second;
+ }
+
+ // do slow lookup in lazy pointer section
+ const uint32_t* const indirectTable = (uint32_t*)&this->fLinkEditBase[fDynamicInfo->indirectsymoff()];
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this->fHeader + sizeof(macho_header<P>));
+ const uint32_t cmd_count = this->fHeader->ncmds();
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+ const macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
+ const macho_section<P>* const sectionsStart = (macho_section<P>*)((uint8_t*)seg + sizeof(macho_segment_command<P>));
+ const macho_section<P>* const sectionsEnd = §ionsStart[seg->nsects()];
+ for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+ uint8_t sectionType = sect->flags() & SECTION_TYPE;
+ if ( sectionType == S_LAZY_SYMBOL_POINTERS) {
+ uint32_t elementCount = sect->size() / sizeof(pint_t);
+ const uint32_t indirectTableOffset = sect->reserved1();
+ pint_t vmlocation = sect->addr();
+ for (uint32_t j=0; j < elementCount; ++j, vmlocation += sizeof(pint_t)) {
+ uint32_t symbolIndex = E::get32(indirectTable[indirectTableOffset + j]);
+ switch ( symbolIndex ) {
+ case INDIRECT_SYMBOL_ABS:
+ case INDIRECT_SYMBOL_LOCAL:
+ break;
+ default:
+ const macho_nlist<P>* aSymbol = &fSymbolTable[symbolIndex];
+ const char* aName = &fStrings[aSymbol->n_strx()];
+ //fprintf(stderr, " sect=%s, index=%d, symbolIndex=%d, sym=%s\n", sect->sectname(), j, symbolIndex, &fStrings[undefinedSymbol->n_strx()]);
+ if ( strcmp(aName, symbolName) == 0 ) {
+ fResolverLazyPointers[symbolName] = vmlocation;
+ if ( log ) fprintf(stderr, "found slow-path shared lazy pointer at 0x%llX for %s in %s\n", (uint64_t)vmlocation, symbolName, this->getDylibID());
+ return vmlocation;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+ }
+
+ if ( log ) fprintf(stderr, "NOT found shared lazy pointer for %s in %s\n", symbolName, this->getDylibID());
return 0;
}
#include <vector>
#include <set>
-#include <ext/hash_map>
+#include <unordered_map>
#include "MachOFileAbstraction.hpp"
#include "Architectures.hpp"
// need getDyldInfoExports because export info uses ULEB encoding and size could grow
virtual const uint8_t* getDyldInfoExports() const = 0;
virtual void setDyldInfoExports(const uint8_t* newExports) const = 0;
+ virtual void uuid(uuid_t u) const = 0;
};
virtual uint64_t getReadOnlyVMSize() const { return fVMReadOnlySize; }
virtual const uint8_t* getDyldInfoExports() const { return fDyldInfoExports; }
virtual void setDyldInfoExports(const uint8_t* newExports) const { fDyldInfoExports = newExports; }
+ virtual void uuid(uuid_t u) const { memcpy(u, fUUID, 16); }
private:
typedef typename A::P P;
bool fIsDylib;
bool fHasDyldInfo;
mutable const uint8_t* fDyldInfoExports;
+ uuid_t fUUID;
};
const std::vector<MachOLayoutAbstraction*>& allLayouts() const { return fLayouts; }
private:
+ class CStringHash {
+ public:
+ size_t operator()(const char* __s) const {
+ size_t __h = 0;
+ for ( ; *__s; ++__s)
+ __h = 5 * __h + *__s;
+ return __h;
+ };
+ };
struct CStringEquals {
bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
};
- typedef __gnu_cxx::hash_map<const char*, const UniversalMachOLayout*, __gnu_cxx::hash<const char*>, CStringEquals> PathToNode;
+ typedef std::unordered_map<const char*, const UniversalMachOLayout*, CStringHash, CStringEquals> PathToNode;
static bool requestedSlice(const std::set<ArchPair>* onlyArchs, cpu_type_t cpuType, cpu_subtype_t cpuSubType);
fDylibID.name = NULL;
fDylibID.currentVersion = 0;
fDylibID.compatibilityVersion = 0;
-
+ bzero(fUUID, sizeof(fUUID));
+
const macho_header<P>* mh = (const macho_header<P>*)machHeader;
if ( mh->cputype() != arch() )
throw "Layout object is wrong architecture";
fHasDyldInfo = true;
dyldInfo = (struct macho_dyld_info_command<P>*)cmd;
break;
+ case LC_UUID:
+ {
+ const macho_uuid_command<P>* uc = (macho_uuid_command<P>*)cmd;
+ memcpy(&fUUID, uc->uuid(), 16);
+ }
+ break;
}
cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
}
template <typename A>
Rebaser<A>::Rebaser(const MachOLayoutAbstraction& layout)
- : fLayout(layout), fOrignalVMRelocBaseAddress(NULL), fLinkEditBase(NULL),
+ : fLayout(layout), fOrignalVMRelocBaseAddress(0), fLinkEditBase(0),
fSymbolTable(NULL), fDynamicSymbolTable(NULL), fDyldInfo(NULL), fSplittingSegments(false),
fOrignalVMRelocBaseAddressValid(false), fSkipSplitSegInfoStart(0), fSkipSplitSegInfoEnd(0)
{
#define NO_ULEB
#include "Architectures.hpp"
#include "MachOFileAbstraction.hpp"
+#include "CacheFileAbstraction.hpp"
#include "dsc_iterator.h"
#include "dsc_extractor.h"
#include <vector>
#include <map>
-#include <ext/hash_map>
+#include <unordered_map>
#include <algorithm>
#include <dispatch/dispatch.h>
uint64_t sizem;
};
+class CStringHash {
+public:
+ size_t operator()(const char* __s) const {
+ size_t __h = 0;
+ for ( ; *__s; ++__s)
+ __h = 5 * __h + *__s;
+ return __h;
+ };
+};
class CStringEquals {
public:
bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
};
-typedef __gnu_cxx::hash_map<const char*, std::vector<seg_info>, __gnu_cxx::hash<const char*>, CStringEquals> NameToSegments;
+typedef std::unordered_map<const char*, std::vector<seg_info>, CStringHash, CStringEquals> NameToSegments;
template <typename A>
-int optimize_linkedit(macho_header<typename A::P>* mh, const void* mapped_cache, uint64_t* newSize)
+int optimize_linkedit(macho_header<typename A::P>* mh, uint32_t textOffsetInCache, const void* mapped_cache, uint64_t* newSize)
{
typedef typename A::P P;
typedef typename A::P::E E;
dataInCodeSize = dataInCode->datasize();
memcpy((char*)mh + newDataInCodeOffset, (char*)mapped_cache + dataInCode->dataoff(), dataInCodeSize);
}
+
+ // 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;
+ 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());
+ macho_nlist<P>* allLocalNlists = (macho_nlist<P>*)(((uint8_t*)localInfo) + localInfo->nlistOffset());
+ const uint32_t entriesCount = localInfo->entriesCount();
+ for (uint32_t i=0; i < entriesCount; ++i) {
+ if ( entries[i].dylibOffset() == textOffsetInCache ) {
+ uint32_t localNlistStart = entries[i].nlistStartIndex();
+ localNlistCount = entries[i].nlistCount();
+ localNlists = &allLocalNlists[localNlistStart];
+ localStrings = ((char*)localInfo) + localInfo->stringsOffset();
+ 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()];
+ uint32_t newSymCount = symtab->nsyms();
+ if ( localNlists != NULL ) {
+ newSymCount = localNlistCount;
+ for (const macho_nlist<P>* s = mergedSymTabStart; s != mergedSymTabend; ++s) {
+ // skip any locals in cache
+ if ( (s->n_type() & (N_TYPE|N_EXT)) == N_SECT )
+ continue;
+ ++newSymCount;
+ }
+ }
+
// 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 + symtab->nsyms()*sizeof(macho_nlist<P>);
+ const uint32_t newIndSymTabOffset = newSymTabOffset + newSymCount*sizeof(macho_nlist<P>);
const uint32_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;
- uint32_t* newIndSymTab = (uint32_t*)((char*)mh + newIndSymTabOffset);
const uint32_t* mergedIndSymTab = (uint32_t*)((char*)mapped_cache + dynamicSymTab->indirectsymoff());
- const macho_nlist<P>* const mergedSymTabStart = (macho_nlist<P>*)(((uint8_t*)mapped_cache) + symtab->symoff());
- const macho_nlist<P>* const mergedSymTabend = &mergedSymTabStart[symtab->nsyms()];
const char* mergedStringPoolStart = (char*)mapped_cache + symtab->stroff();
macho_nlist<P>* t = newSymTabStart;
int poolOffset = 0;
+ uint32_t symbolsCopied = 0;
newStringPoolStart[poolOffset++] = '\0'; // first pool entry is always empty string
for (const macho_nlist<P>* s = mergedSymTabStart; s != mergedSymTabend; ++s) {
+ // if we have better local symbol info, skip any locals here
+ if ( (localNlists != NULL) && ((s->n_type() & (N_TYPE|N_EXT)) == N_SECT) )
+ continue;
*t = *s;
t->set_n_strx(poolOffset);
strcpy(&newStringPoolStart[poolOffset], &mergedStringPoolStart[s->n_strx()]);
poolOffset += (strlen(&newStringPoolStart[poolOffset]) + 1);
++t;
+ ++symbolsCopied;
+ }
+ if ( localNlists != NULL ) {
+ // update load command to reflect new count of locals
+ dynamicSymTab->set_ilocalsym(symbolsCopied);
+ dynamicSymTab->set_nlocalsym(localNlistCount);
+ // copy local symbols
+ for (uint32_t i=0; i < localNlistCount; ++i) {
+ const char* localName = &localStrings[localNlists[i].n_strx()];
+ *t = localNlists[i];
+ t->set_n_strx(poolOffset);
+ strcpy(&newStringPoolStart[poolOffset], localName);
+ poolOffset += (strlen(localName) + 1);
+ ++t;
+ ++symbolsCopied;
+ }
}
+
+ if ( newSymCount != symbolsCopied ) {
+ fprintf(stderr, "symbol count miscalculation\n");
+ return -1;
+ }
+
// pointer align string pool size
while ( (poolOffset % sizeof(pint_t)) != 0 )
++poolOffset;
// copy indirect symbol table
+ uint32_t* newIndSymTab = (uint32_t*)((char*)mh + newIndSymTabOffset);
memcpy(newIndSymTab, mergedIndSymTab, dynamicSymTab->nindirectsyms()*sizeof(uint32_t));
// update load commands
dataInCode->set_dataoff(newDataInCodeOffset);
dataInCode->set_datasize(dataInCodeSize);
}
+ symtab->set_nsyms(symbolsCopied);
symtab->set_symoff(newSymTabOffset);
symtab->set_stroff(newStringPoolOffset);
symtab->set_strsize(poolOffset);
lastSlash[1] = '\0';
struct stat stat_buf;
if ( stat(dirs, &stat_buf) != 0 ) {
- const char* afterSlash = &dirs[1];
+ char* afterSlash = &dirs[1];
char* slash;
while ( (slash = strchr(afterSlash, '/')) != NULL ) {
*slash = '\0';
uint32_t nfat_archs = 0;
uint32_t offsetInFatFile = 4096;
uint8_t *base_ptr = &dylib_data.front();
-
+
#define FH reinterpret_cast<fat_header*>(base_ptr)
#define FA reinterpret_cast<fat_arch*>(base_ptr + (8 + (nfat_archs - 1) * sizeof(fat_arch)))
// Write regular segments into the buffer
uint32_t totalSize = 0;
-
+ uint32_t textOffsetInCache = 0;
for( std::vector<seg_info>::const_iterator it=segments.begin(); it != segments.end(); ++it) {
if(strcmp(it->segName, "__TEXT") == 0 ) {
- const macho_header<P> *textMH = reinterpret_cast<macho_header<P>*>((uint8_t*)mapped_cache+it->offset);
+ textOffsetInCache = it->offset;
+ const macho_header<P> *textMH = reinterpret_cast<macho_header<P>*>((uint8_t*)mapped_cache+textOffsetInCache);
FA->cputype = OSSwapHostToBigInt32(textMH->cputype());
FA->cpusubtype = OSSwapHostToBigInt32(textMH->cpusubtype());
// optimize linkedit
uint64_t newSize = dylib_data.size();
- optimize_linkedit<A>(((macho_header<P>*)(base_ptr+offsetInFatFile)), mapped_cache, &newSize);
+ optimize_linkedit<A>(((macho_header<P>*)(base_ptr+offsetInFatFile)), textOffsetInCache, mapped_cache, &newSize);
// update fat header with new file size
dylib_data.resize(offsetInFatFile+newSize);
}
close(cache_fd);
-
+
// instantiate arch specific dylib maker
size_t (*dylib_create_func)(const void*, std::vector<uint8_t>&, const std::vector<seg_info>&) = NULL;
if ( strcmp((char*)mapped_cache, "dyld_v1 i386") == 0 )
}
// iterate through all images in cache and build map of dylibs and segments
- __block NameToSegments map;
- dyld_shared_cache_iterate_segments_with_slide(mapped_cache,
- ^(const char* dylib, const char* segName, uint64_t offset, uint64_t sizem,
- uint64_t mappedddress, uint64_t slide) {
- map[dylib].push_back(seg_info(segName, offset, sizem));
- });
+ __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) {
+ map[dylibInfo->path].push_back(seg_info(segInfo->name, segInfo->fileOffset, segInfo->fileSize));
+ });
+
+ if(result != 0) {
+ fprintf(stderr, "Error: dyld_shared_cache_iterate_segments_with_slide failed.\n");
+ munmap(mapped_cache, statbuf.st_size);
+ return result;
+ }
// for each dylib instantiate a dylib file
dispatch_group_t group = dispatch_group_create();
strcat(dylib_path, "/");
strcat(dylib_path, it->first);
- //printf("%s with %lu segments\n", dylib_path, segments.size());
+ //printf("%s with %lu segments\n", dylib_path, it->second.size());
// make sure all directories in this path exist
make_dirs(dylib_path);
#if 0
+// test program
+#include <stdio.h>
+#include <stddef.h>
+#include <dlfcn.h>
+
typedef int (*extractor_proc)(const char* shared_cache_file_path, const char* extraction_root_path,
void (^progress)(unsigned current, unsigned total));
return 1;
}
- void* handle = dlopen("/Developer/Platforms/iPhoneOS.platform/usr/lib/dsc_extractor.bundle", RTLD_LAZY);
+ //void* handle = dlopen("/Volumes/my/src/dyld/build/Debug/dsc_extractor.bundle", RTLD_LAZY);
+ void* handle = dlopen("/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/usr/lib/dsc_extractor.bundle", RTLD_LAZY);
if ( handle == NULL ) {
fprintf(stderr, "dsc_extractor.bundle could not be loaded\n");
return 1;
fprintf(stderr, "dyld_shared_cache_extract_dylibs_progress() => %d\n", result);
return 0;
}
+
+
#endif
/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
*
- * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2009-2012 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
// convert an address in the shared region where the cache would normally be mapped, into an address where the cache is currently mapped
template <typename E>
- const uint8_t* mappedAddress(const uint8_t* cache, uint64_t addr)
+ const uint8_t* mappedAddress(const uint8_t* cache, const uint8_t* cacheEnd, uint64_t addr)
{
const dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)cache;
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())) ) {
- return &cache[mappings[i].file_offset() + addr - mappings[i].address()];
+ uint32_t cacheOffset = mappings[i].file_offset() + addr - mappings[i].address();
+ const uint8_t* result = &cache[cacheOffset];
+ if ( result < cacheEnd )
+ return result;
+ else
+ return NULL;
}
}
return NULL;
// call the callback block on each segment in this image
template <typename A>
- void walkSegments(const uint8_t* cache, const char* dylibPath, const uint8_t* machHeader, uint64_t slide, dyld_shared_cache_iterator_slide_t callback)
+ int walkSegments(const uint8_t* cache, const uint8_t* cacheEnd, const uint8_t* firstSeg, const char* dylibPath, 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.isAlias = (dylibPath < (char*)firstSeg); // paths for aliases are store between cache header and first segment
+ dylibInfo.machHeader = machHeader;
+ dylibInfo.path = dylibPath;
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 )
+ return -1;
const uint32_t cmd_count = mh->ncmds();
const macho_load_command<P>* cmd = cmds;
+ // scan for LC_UUID
+ dylibInfo.uuid = NULL;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ if ( cmd->cmd() == LC_UUID ) {
+ const uuid_command* uc = (const uuid_command*)cmd;
+ dylibInfo.uuid = &uc->uuid;
+ break;
+ }
+ cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+ }
+ // callback for each LC_SEGMENT
+ cmd = cmds;
for (uint32_t i = 0; i < cmd_count; ++i) {
if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
macho_segment_command<P>* segCmd = (macho_segment_command<P>*)cmd;
uint64_t sizem = segCmd->vmsize();
if ( strcmp(segCmd->segname(), "__LINKEDIT") == 0 ) {
// clip LINKEDIT size if bigger than cache file
- const dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)cache;
- const dyldCacheFileMapping<E>* mappings = (dyldCacheFileMapping<E>*)&cache[header->mappingOffset()];
- if ( mappings[2].file_offset() <= fileOffset ) {
- if ( sizem > mappings[2].size() )
- sizem = mappings[2].file_offset() + mappings[2].size() - fileOffset;
- }
+ if ( (fileOffset+sizem) > (uint64_t)(cacheEnd-cache) )
+ sizem = (cacheEnd-cache)-fileOffset;
}
- callback(dylibPath, segCmd->segname(), fileOffset, sizem, segCmd->vmaddr()+slide, slide);
+ segInfo.version = 1;
+ segInfo.name = segCmd->segname();
+ segInfo.fileOffset = fileOffset;
+ segInfo.fileSize = sizem;
+ segInfo.address = segCmd->vmaddr();
+ callback(&dylibInfo, &segInfo);
}
cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
}
+ return 0;
}
// call walkSegments on each image in the cache
template <typename A>
- int walkImages(const uint8_t* cache, dyld_shared_cache_iterator_slide_t callback)
+ int walkImages(const uint8_t* cache, uint32_t size, void (^callback)(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo))
{
+ // Sanity check there is at least a header
+ if ( (size > 0) && (size < 0x7000) )
+ return -1;
typedef typename A::P::E E;
typedef typename A::P P;
- typedef typename A::P::uint_t pint_t;
- const dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)cache;
- uint64_t slide = 0;
- if ( header->mappingOffset() >= 0x48 ) {
- const dyldCacheFileMapping<E>* mappings = (dyldCacheFileMapping<E>*)&cache[header->mappingOffset()];
- uint64_t storedPointerToHeader = P::getP(*((pint_t*)&cache[mappings[1].file_offset()]));
- slide = storedPointerToHeader - mappings[0].address();
- }
- const dyldCacheImageInfo<E>* dylibs = (dyldCacheImageInfo<E>*)&cache[header->imagesOffset()];
+ const dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)cache;
+ const dyldCacheImageInfo<E>* dylibs = (dyldCacheImageInfo<E>*)&cache[header->imagesOffset()];
+ const dyldCacheFileMapping<E>* mappings = (dyldCacheFileMapping<E>*)&cache[header->mappingOffset()];
+ uint64_t greatestMappingOffset = 0;
+ for (uint32_t i=0; i < header->mappingCount(); ++i) {
+ if ( (size != 0) && (mappings[i].file_offset() > size) )
+ return -1;
+ uint64_t endOffset = mappings[i].file_offset()+mappings[i].size();
+ if ( (size != 0) && (endOffset > size) )
+ return -1;
+ if ( endOffset > greatestMappingOffset )
+ greatestMappingOffset = endOffset;
+ }
+ const uint8_t* cacheEnd = &cache[size];
+ if ( size == 0 ) {
+ // Zero size means old API is being used, assume all mapped
+ cacheEnd = &cache[greatestMappingOffset];
+ }
+ else {
+ // verifiy mappings are not bigger than size
+ if ( size < greatestMappingOffset )
+ return -1;
+ }
+ // verify all image infos are mapped
+ if ( (const uint8_t*)&dylibs[header->imagesCount()] > cacheEnd )
+ return -1;
+ const uint8_t* firstSeg = NULL;
for (uint32_t i=0; i < header->imagesCount(); ++i) {
const char* dylibPath = (char*)cache + dylibs[i].pathFileOffset();
- const uint8_t* machHeader = mappedAddress<E>(cache, dylibs[i].address());
- walkSegments<A>(cache, dylibPath, machHeader, slide, callback);
+ if ( (const uint8_t*)dylibPath > cacheEnd )
+ return -1;
+ const uint8_t* machHeader = mappedAddress<E>(cache, cacheEnd, dylibs[i].address());
+ if ( machHeader == NULL )
+ return -1;
+ if ( machHeader > cacheEnd )
+ return -1;
+ if ( firstSeg == NULL )
+ firstSeg = machHeader;
+ int result = walkSegments<A>(cache, cacheEnd, firstSeg, dylibPath, machHeader, callback);
+ if ( result != 0 )
+ return result;
}
return 0;
}
// this routine will call the callback block once for each segment
// in each dylib in the shared cache file.
// Returns -1 if there was an error, otherwise 0.
-int dyld_shared_cache_iterate_segments_with_slide(const void* shared_cache_file, dyld_shared_cache_iterator_slide_t callback)
-{
+extern int dyld_shared_cache_iterate(const void* shared_cache_file, uint32_t shared_cache_size,
+ void (^callback)(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo)) {
const uint8_t* cache = (uint8_t*)shared_cache_file;
if ( strcmp((char*)cache, "dyld_v1 i386") == 0 )
- return dyld::walkImages<x86>(cache, callback);
+ 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, callback);
+ return dyld::walkImages<x86_64>(cache, shared_cache_size, callback);
else if ( strcmp((char*)cache, "dyld_v1 armv5") == 0 )
- return dyld::walkImages<arm>(cache, callback);
+ return dyld::walkImages<arm>(cache, shared_cache_size, callback);
else if ( strcmp((char*)cache, "dyld_v1 armv6") == 0 )
- return dyld::walkImages<arm>(cache, callback);
+ return dyld::walkImages<arm>(cache, shared_cache_size, callback);
else if ( strcmp((char*)cache, "dyld_v1 armv7") == 0 )
- return dyld::walkImages<arm>(cache, callback);
+ return dyld::walkImages<arm>(cache, shared_cache_size, callback);
else if ( strncmp((char*)cache, "dyld_v1 armv7", 14) == 0 )
- return dyld::walkImages<arm>(cache, callback);
+ return dyld::walkImages<arm>(cache, shared_cache_size, callback);
else
return -1;
}
+
+// implement old version by calling new version
+int dyld_shared_cache_iterate_segments_with_slide(const void* shared_cache_file, dyld_shared_cache_iterator_slide_t callback)
+{
+ return dyld_shared_cache_iterate(shared_cache_file, 0, ^(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo) {
+ callback(dylibInfo->path, segInfo->name, segInfo->fileOffset, segInfo->fileSize, segInfo->address, 0);
+ });
+}
+
// implement non-block version by calling block version
int dyld_shared_cache_iterate_segments_with_slide_nb(const void* shared_cache_file, dyld_shared_cache_iterator_slide_nb_t func, void* userData)
{
/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
*
- * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2009-2012 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
*/
#include <stdint.h>
+#include <uuid/uuid.h>
+
+struct dyld_shared_cache_dylib_info {
+ uint32_t version; // initial 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
+};
+typedef struct dyld_shared_cache_dylib_info dyld_shared_cache_dylib_info;
+
+struct dyld_shared_cache_segment_info {
+ uint64_t version; // initial version 1
+ const char* name; // of segment
+ uint64_t fileOffset; // of segment in cache file
+ uint64_t fileSize; // of segment
+ uint64_t address; // of segment when cache mapped with ASLR (sliding) off
+ // above fields all exist in version 1
+};
+typedef struct dyld_shared_cache_segment_info dyld_shared_cache_segment_info;
+
#ifdef __cplusplus
extern "C" {
#endif
+// Given a pointer and size of an in-memory copy of a dyld shared cache file,
+// this routine will call the callback block once for each segment in each dylib
+// in the shared cache file.
+// Returns -1 if there was an error, otherwise 0.
+extern int dyld_shared_cache_iterate(const void* shared_cache_file, uint32_t shared_cache_size,
+ void (^callback)(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo));
+
+
+
+//
+// The following iterator functions are deprecated:
+//
typedef void (^dyld_shared_cache_iterator_t)(const char* dylibName, const char* segName, uint64_t offset, uint64_t size, uint64_t mappedddress);
typedef void (^dyld_shared_cache_iterator_slide_t)(const char* dylibName, const char* segName, uint64_t offset, uint64_t size, uint64_t mappedddress, uint64_t slide);
typedef void (*dyld_shared_cache_iterator_nb_t)(const char* dylibName, const char* segName, uint64_t offset, uint64_t sizem, uint64_t mappedddress, void* userData);
typedef void (*dyld_shared_cache_iterator_slide_nb_t)(const char* dylibName, const char* segName, uint64_t offset, uint64_t sizem, uint64_t mappedddress, uint64_t slide, void* userData);
-// Given a pointer to an in-memory copy of a dyld shared cache file,
-// this routine will call the callback block once for each segment
-// in each dylib in the shared cache file.
-// Returns -1 if there was an error, otherwise 0.
-extern int dyld_shared_cache_iterate_segments(const void* shared_cache_file, dyld_shared_cache_iterator_t callback);
-extern int dyld_shared_cache_iterate_segments_with_slide(const void* shared_cache_file, dyld_shared_cache_iterator_slide_t callback);
-extern int dyld_shared_cache_iterate_segments_nb(const void* shared_cache_file, dyld_shared_cache_iterator_nb_t callback, void* userData);
-extern int dyld_shared_cache_iterate_segments_with_slide_nb(const void* shared_cache_file, dyld_shared_cache_iterator_slide_nb_t callback, void* userData);
+extern int dyld_shared_cache_iterate_segments(const void* shared_cache_file, dyld_shared_cache_iterator_t callback) __attribute__((deprecated));
+extern int dyld_shared_cache_iterate_segments_with_slide(const void* shared_cache_file, dyld_shared_cache_iterator_slide_t callback) __attribute__((deprecated));
+extern int dyld_shared_cache_iterate_segments_nb(const void* shared_cache_file, dyld_shared_cache_iterator_nb_t callback, void* userData) __attribute__((deprecated));
+extern int dyld_shared_cache_iterate_segments_with_slide_nb(const void* shared_cache_file, dyld_shared_cache_iterator_slide_nb_t callback, void* userData) __attribute__((deprecated));
#ifdef __cplusplus
uint64_t codeSignatureSize; // size of code signature blob (zero means to end of file)
uint64_t slideInfoOffset; // file offset of kernel slid info
uint64_t slideInfoSize; // size of kernel slid info
+ uint64_t localSymbolsOffset; // file offset of where local symbols are stored
+ uint64_t localSymbolsSize; // size of local symbols information
+ uint8_t uuid[16]; // unique value for each shared cache file
};
struct dyld_cache_mapping_info {
};
+struct dyld_cache_local_symbols_info
+{
+ uint32_t nlistOffset; // offset into this chunk of nlist entries
+ uint32_t nlistCount; // count of nlist entries
+ uint32_t stringsOffset; // offset into this chunk of string pool
+ uint32_t stringsSize; // byte count of string pool
+ uint32_t entriesOffset; // offset into this chunk of array of dyld_cache_local_symbols_entry
+ uint32_t entriesCount; // number of elements in dyld_cache_local_symbols_entry array
+};
+
+struct dyld_cache_local_symbols_entry
+{
+ uint32_t dylibOffset; // offset in cache file of start of dylib
+ uint32_t nlistStartIndex; // start index of locals for this dylib
+ uint32_t nlistCount; // number of local symbols for this dylib
+};
+
+
#define MACOSX_DYLD_SHARED_CACHE_DIR "/var/db/dyld/"
#define IPHONE_DYLD_SHARED_CACHE_DIR "/System/Library/Caches/com.apple.dyld/"
/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
*
- * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2009-2012 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <mach-o/arch.h>
#include <mach-o/loader.h>
-#include <vector>
#include <map>
-#include <set>
#include "dsc_iterator.h"
#include "dyld_cache_format.h"
#include "CacheFileAbstraction.hpp"
-#define OP_NULL 0
-#define OP_LIST_DEPENDENCIES 1
-#define OP_LIST_DYLIBS 2
-#define OP_LIST_LINKEDIT 3
-
-#define UUID_BYTES 16
+enum Mode {
+ modeNone,
+ modeList,
+ modeMap,
+ modeDependencies,
+ modeSlideInfo,
+ modeLinkEdit,
+ modeInfo
+};
-// Define this here so we can work with or without block support
-typedef void (*segment_callback_t)(const char* dylib, const char* segName, uint64_t offset, uint64_t sizem,
- uint64_t mappedddress, uint64_t slide, void* userData);
+struct Options {
+ Mode mode;
+ const char* dependentsOfPath;
+ const void* mappedCache;
+ bool printUUIDs;
+ bool printVMAddrs;
+ bool printDylibVersions;
+};
-struct seg_callback_args {
- char *target_path;
- uint32_t target_found;
- void *mapped_cache;
- uint32_t op;
- uint8_t print_uuids;
- uint8_t print_vmaddrs;
- uint8_t print_dylib_versions;
+struct Results {
+ std::map<uint32_t, const char*> pageToContent;
+ uint64_t linkeditBase;
+ bool dependentTargetFound;
};
+
+
+
+
void usage() {
- fprintf(stderr, "Usage: dscutil -list [ -uuid ] [-vmaddr] | -dependents <dylib-path> [ -versions ] | -linkedit [ shared-cache-file ]\n");
+ fprintf(stderr, "Usage: dyld_shared_cache_util -list [ -uuid ] [-vmaddr] | -dependents <dylib-path> [ -versions ] | -linkedit | -map [ shared-cache-file ] | -slide_info | -info\n");
}
/*
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";
#else
#endif
}
-/*
- * Get a vector of all the load commands from the header pointed to by headerAddr
- */
-template <typename A>
-std::vector<macho_load_command<typename A::P>* > get_load_cmds(void *headerAddr) {
- typedef typename A::P P;
- typedef typename A::P::E E;
-
- std::vector<macho_load_command<P>* > cmd_vector;
-
- const macho_header<P>* mh = (const macho_header<P>*)headerAddr;
- uint32_t ncmds = mh->ncmds();
- const macho_load_command<P>* const cmds = (macho_load_command<P>*)((long)mh + sizeof(macho_header<P>));
- const macho_load_command<P>* cmd = cmds;
-
- for (uint32_t i = 0; i < ncmds; i++) {
- cmd_vector.push_back((macho_load_command<P>*)cmd);
- cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
- }
- return cmd_vector;
-}
+typedef void (*segment_callback_t)(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo,
+ const Options& options, Results& results);
+
+
/*
* List dependencies from the mach-o header at headerAddr
* in the same format as 'otool -L'
*/
template <typename A>
-void list_dependencies(const char *dylib, void *headerAddr, uint8_t print_dylib_versions) {
+void print_dependencies(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo,
+ const Options& options, Results& results) {
typedef typename A::P P;
typedef typename A::P::E E;
- std::vector< macho_load_command<P>* > cmds;
- cmds = get_load_cmds<A>(headerAddr);
- for(typename std::vector<macho_load_command<P>*>::iterator it = cmds.begin(); it != cmds.end(); ++it) {
- uint32_t cmdType = (*it)->cmd();
- if (cmdType == LC_LOAD_DYLIB ||
- cmdType == LC_ID_DYLIB ||
- cmdType == LC_LOAD_WEAK_DYLIB ||
- cmdType == LC_REEXPORT_DYLIB ||
- cmdType == LC_LOAD_UPWARD_DYLIB) {
- macho_dylib_command<P>* dylib_cmd = (macho_dylib_command<P>*)*it;
- const char *name = dylib_cmd->name();
- uint32_t compat_vers = dylib_cmd->compatibility_version();
- uint32_t current_vers = dylib_cmd->current_version();
-
- if (print_dylib_versions) {
- printf("\t%s", name);
- if ( compat_vers != 0xFFFFFFFF )
- printf("(compatibility version %u.%u.%u, current version %u.%u.%u)\n",
- (compat_vers >> 16),
- (compat_vers >> 8) & 0xff,
- (compat_vers) & 0xff,
- (current_vers >> 16),
- (current_vers >> 8) & 0xff,
- (current_vers) & 0xff);
- else
- printf("\n");
- } else {
- printf("\t%s\n", name);
- }
+ if ( strcmp(options.dependentsOfPath, dylibInfo->path) != 0 )
+ return;
+ if ( strcmp(segInfo->name, "__TEXT") != 0 )
+ return;
+
+ const macho_dylib_command<P>* dylib_cmd;
+ const macho_header<P>* mh = (const macho_header<P>*)dylibInfo->machHeader;
+ const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uintptr_t)dylibInfo->machHeader + sizeof(macho_header<P>));
+ const uint32_t cmd_count = mh->ncmds();
+ const macho_load_command<P>* cmd = cmds;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ switch ( cmd->cmd() ) {
+ case LC_LOAD_DYLIB:
+ case LC_ID_DYLIB:
+ case LC_REEXPORT_DYLIB:
+ case LC_LOAD_WEAK_DYLIB:
+ case LC_LOAD_UPWARD_DYLIB:
+ dylib_cmd = (macho_dylib_command<P>*)cmd;
+ if ( options.printDylibVersions ) {
+ uint32_t compat_vers = dylib_cmd->compatibility_version();
+ uint32_t current_vers = dylib_cmd->current_version();
+ printf("\t%s", dylib_cmd->name());
+ if ( compat_vers != 0xFFFFFFFF ) {
+ printf("(compatibility version %u.%u.%u, current version %u.%u.%u)\n",
+ (compat_vers >> 16),
+ (compat_vers >> 8) & 0xff,
+ (compat_vers) & 0xff,
+ (current_vers >> 16),
+ (current_vers >> 8) & 0xff,
+ (current_vers) & 0xff);
+ }
+ else {
+ printf("\n");
+ }
+ }
+ else {
+ printf("\t%s\n", dylib_cmd->name());
+ }
+ break;
}
+ cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
}
+ results.dependentTargetFound = true;
}
/*
- * Print out a dylib from the shared cache, optionally including the UUID
+ * Print out a dylib from the shared cache, optionally including the UUID or unslid load address
*/
template <typename A>
-void print_dylib(const char *dylib, void *headerAddr, uint64_t slide, struct seg_callback_args *args) {
- typedef typename A::P P;
- typedef typename A::P::E E;
- char uuid_str[UUID_BYTES*3];
- uint8_t got_uuid = 0;
- uint64_t vmaddr = 0;
-
- std::vector< macho_load_command<P>* > cmds;
- cmds = get_load_cmds<A>(headerAddr);
- for(typename std::vector<macho_load_command<P>*>::iterator it = cmds.begin(); it != cmds.end(); ++it) {
- uint32_t cmdType = (*it)->cmd();
- if (cmdType == LC_UUID) {
- macho_uuid_command<P>* uuid_cmd = (macho_uuid_command<P>*)*it;
- const uint8_t *uuid = uuid_cmd->uuid();
- sprintf(uuid_str, "<%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X>",
- uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
- uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
- got_uuid = 1;
- }
- else if (cmdType == LC_SEGMENT) {
- macho_segment_command<P>* seg_cmd = (macho_segment_command<P>*)*it;
- if (strcmp(seg_cmd->segname(), "__TEXT") == 0) {
- vmaddr = seg_cmd->vmaddr();
- }
- }
- }
+void print_list(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 (args->print_vmaddrs)
- printf("0x%08llX ", vmaddr+slide);
- if (args->print_uuids) {
- if (got_uuid)
- printf("%s ", uuid_str);
+ if ( options.printVMAddrs )
+ printf("0x%08llX ", segInfo->address);
+ if ( options.printUUIDs ) {
+ if ( dylibInfo->uuid != NULL ) {
+ const uint8_t* uuid = (uint8_t*)dylibInfo->uuid;;
+ printf("<%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X> ",
+ uuid[0], uuid[1], uuid[2], uuid[3],
+ uuid[4], uuid[5], uuid[6], uuid[7],
+ uuid[8], uuid[9], uuid[10], uuid[11],
+ uuid[12], uuid[13], uuid[14], uuid[15]);
+ }
else
printf("< no uuid in dylib > ");
}
- printf("%s\n", dylib);
+ if ( dylibInfo->isAlias )
+ printf("[alias] %s\n", dylibInfo->path);
+ else
+ printf("%s\n", dylibInfo->path);
}
-uint64_t sLinkeditBase = 0;
-std::map<uint32_t, char*> sPageToContent;
-
-
-static void add_linkedit(uint32_t pageStart, uint32_t pageEnd, char* message)
+static void add_linkedit(uint32_t pageStart, uint32_t pageEnd, const char* message, Results& results)
{
for (uint32_t p = pageStart; p <= pageEnd; p += 4096) {
- std::map<uint32_t, char*>::iterator pos = sPageToContent.find(p);
- if ( pos == sPageToContent.end() ) {
- sPageToContent[p] = strdup(message);
+ std::map<uint32_t, const char*>::iterator pos = results.pageToContent.find(p);
+ if ( pos == results.pageToContent.end() ) {
+ results.pageToContent[p] = strdup(message);
}
else {
- char* oldMessage = pos->second;
+ const char* oldMessage = pos->second;
char* newMesssage;
asprintf(&newMesssage, "%s, %s", oldMessage, message);
- sPageToContent[p] = newMesssage;
- free(oldMessage);
+ results.pageToContent[p] = newMesssage;
+ ::free((void*)oldMessage);
}
}
}
* get LINKEDIT info for dylib
*/
template <typename A>
-void process_linkedit(const char* dylib, void* headerAddr) {
+void process_linkedit(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo,
+ const Options& options, Results& results) {
typedef typename A::P P;
typedef typename A::P::E E;
- // filter out symlinks by only handling first path found for each mach header
- static std::set<void*> seenImages;
- if ( seenImages.count(headerAddr) != 0 )
+ // filter out symlinks
+ if ( dylibInfo->isAlias )
return;
- seenImages.insert(headerAddr);
- const macho_header<P>* mh = (const macho_header<P>*)headerAddr;
+ const macho_header<P>* mh = (const macho_header<P>*)dylibInfo->machHeader;
uint32_t ncmds = mh->ncmds();
const macho_load_command<P>* const cmds = (macho_load_command<P>*)((long)mh + sizeof(macho_header<P>));
const macho_load_command<P>* cmd = cmds;
if ( cmd->cmd() == LC_DYLD_INFO_ONLY ) {
macho_dyld_info_command<P>* dyldInfo = (macho_dyld_info_command<P>*)cmd;
char message[1000];
- const char* shortName = strrchr(dylib, '/') + 1;
+ const char* shortName = strrchr(dylibInfo->path, '/') + 1;
// add export trie info
if ( dyldInfo->export_size() != 0 ) {
//printf("export_off=0x%X\n", dyldInfo->export_off());
uint32_t exportPageOffsetStart = dyldInfo->export_off() & (-4096);
uint32_t exportPageOffsetEnd = (dyldInfo->export_off() + dyldInfo->export_size()) & (-4096);
sprintf(message, "exports from %s", shortName);
- add_linkedit(exportPageOffsetStart, exportPageOffsetEnd, message);
+ add_linkedit(exportPageOffsetStart, exportPageOffsetEnd, message, results);
}
// add binding info
if ( dyldInfo->bind_size() != 0 ) {
uint32_t bindPageOffsetStart = dyldInfo->bind_off() & (-4096);
uint32_t bindPageOffsetEnd = (dyldInfo->bind_off() + dyldInfo->bind_size()) & (-4096);
sprintf(message, "bindings from %s", shortName);
- add_linkedit(bindPageOffsetStart, bindPageOffsetEnd, message);
+ add_linkedit(bindPageOffsetStart, bindPageOffsetEnd, message, results);
}
// add lazy binding info
if ( dyldInfo->lazy_bind_size() != 0 ) {
uint32_t lazybindPageOffsetStart = dyldInfo->lazy_bind_off() & (-4096);
uint32_t lazybindPageOffsetEnd = (dyldInfo->lazy_bind_off() + dyldInfo->lazy_bind_size()) & (-4096);
sprintf(message, "lazy bindings from %s", shortName);
- add_linkedit(lazybindPageOffsetStart, lazybindPageOffsetEnd, message);
+ add_linkedit(lazybindPageOffsetStart, lazybindPageOffsetEnd, message, results);
}
// add weak binding info
if ( dyldInfo->weak_bind_size() != 0 ) {
uint32_t weakbindPageOffsetStart = dyldInfo->weak_bind_off() & (-4096);
uint32_t weakbindPageOffsetEnd = (dyldInfo->weak_bind_off() + dyldInfo->weak_bind_size()) & (-4096);
sprintf(message, "weak bindings from %s", shortName);
- add_linkedit(weakbindPageOffsetStart, weakbindPageOffsetEnd, message);
+ add_linkedit(weakbindPageOffsetStart, weakbindPageOffsetEnd, message, results);
}
}
cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
}
-
/*
- * This callback is used with dsc_iterator, and called once for each segment in the target shared cache
+ * Print out a .map file similar to what update_dyld_shared_cache created when the cache file was built
*/
template <typename A>
-void segment_callback(const char *dylib, const char *segName, uint64_t offset, uint64_t sizem,
- uint64_t mappedAddress, uint64_t slide, void *userData) {
- typedef typename A::P P;
- typedef typename A::P::E E;
- struct seg_callback_args *args = (struct seg_callback_args *)userData;
- if (strncmp(segName, "__TEXT", 6) == 0) {
- int target_match = args->target_path ? (strcmp(args->target_path, dylib) == 0) : 0;
- if (!args->target_path || target_match) {
- if (target_match) {
- args->target_found = 1;
- }
- void *headerAddr = (void*)((long)args->mapped_cache + (long)offset);
- switch (args->op) {
- case OP_LIST_DEPENDENCIES:
- list_dependencies<A>(dylib, headerAddr, args->print_dylib_versions);
- break;
- case OP_LIST_DYLIBS:
- print_dylib<A>(dylib, headerAddr, slide, args);
- break;
- case OP_LIST_LINKEDIT:
- process_linkedit<A>(dylib, headerAddr);
- default:
- break;
- }
- }
- }
- else if (strncmp(segName, "__LINKEDIT", 6) == 0) {
- sLinkeditBase = mappedAddress - offset;
- }
+void print_map(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo, const Options& options, Results& results) {
+ if ( !dylibInfo->isAlias )
+ printf("0x%08llX - 0x%08llX %s %s\n", segInfo->address, segInfo->address + segInfo->fileSize, segInfo->name, dylibInfo->path);
}
+static void checkMode(Mode mode) {
+ if ( mode != modeNone ) {
+ fprintf(stderr, "Error: select one of: -list, -dependents, -info, -slide_info, -linkedit, or -map\n");
+ usage();
+ exit(1);
+ }
+}
+
+int main (int argc, const char* argv[]) {
+ const char* sharedCachePath = default_shared_cache_path();
-int main (int argc, char **argv) {
- struct seg_callback_args args;
- const char *shared_cache_path = NULL;
- void *mapped_cache;
- struct stat statbuf;
- int cache_fd;
- char c;
- bool print_slide_info = false;
-
- args.target_path = NULL;
- args.op = OP_NULL;
- args.print_uuids = 0;
- args.print_vmaddrs = 0;
- args.print_dylib_versions = 0;
- args.target_found = 0;
+ Options options;
+ options.mode = modeNone;
+ options.printUUIDs = false;
+ options.printVMAddrs = false;
+ options.printDylibVersions = false;
+ options.dependentsOfPath = NULL;
- for (uint32_t optind = 1; optind < argc; optind++) {
- char *opt = argv[optind];
+ for (uint32_t i = 1; i < argc; i++) {
+ const char* opt = argv[i];
if (opt[0] == '-') {
if (strcmp(opt, "-list") == 0) {
- if (args.op) {
- fprintf(stderr, "Error: select one of -list or -dependents\n");
- usage();
- exit(1);
- }
- args.op = OP_LIST_DYLIBS;
- } else if (strcmp(opt, "-dependents") == 0) {
- if (args.op) {
- fprintf(stderr, "Error: select one of -list or -dependents\n");
- usage();
- exit(1);
- }
- if (!(++optind < argc)) {
+ checkMode(options.mode);
+ options.mode = modeList;
+ }
+ else if (strcmp(opt, "-dependents") == 0) {
+ checkMode(options.mode);
+ options.mode = modeDependencies;
+ options.dependentsOfPath = argv[++i];
+ if ( i >= argc ) {
fprintf(stderr, "Error: option -depdendents requires an argument\n");
usage();
exit(1);
}
- args.op = OP_LIST_DEPENDENCIES;
- args.target_path = argv[optind];
- } else if (strcmp(opt, "-uuid") == 0) {
- args.print_uuids = 1;
- } else if (strcmp(opt, "-versions") == 0) {
- args.print_dylib_versions = 1;
- } else if (strcmp(opt, "-vmaddr") == 0) {
- args.print_vmaddrs = 1;
- } else if (strcmp(opt, "-linkedit") == 0) {
- args.op = OP_LIST_LINKEDIT;
- } else if (strcmp(opt, "-slide_info") == 0) {
- print_slide_info = true;
- } else {
+ }
+ else if (strcmp(opt, "-linkedit") == 0) {
+ checkMode(options.mode);
+ options.mode = modeLinkEdit;
+ }
+ else if (strcmp(opt, "-info") == 0) {
+ checkMode(options.mode);
+ options.mode = modeInfo;
+ }
+ else if (strcmp(opt, "-slide_info") == 0) {
+ checkMode(options.mode);
+ options.mode = modeSlideInfo;
+ }
+ else if (strcmp(opt, "-map") == 0) {
+ checkMode(options.mode);
+ options.mode = modeMap;
+ }
+ else if (strcmp(opt, "-uuid") == 0) {
+ options.printUUIDs = true;
+ }
+ else if (strcmp(opt, "-versions") == 0) {
+ options.printDylibVersions = true;
+ }
+ else if (strcmp(opt, "-vmaddr") == 0) {
+ options.printVMAddrs = true;
+ }
+ else {
fprintf(stderr, "Error: unrecognized option %s\n", opt);
usage();
exit(1);
}
- } else {
- shared_cache_path = opt;
+ }
+ else {
+ sharedCachePath = opt;
}
}
- if ( !print_slide_info ) {
- if (args.op == OP_NULL) {
- fprintf(stderr, "Error: select one of -list or -dependents\n");
- usage();
- exit(1);
- }
+ if ( options.mode == modeNone ) {
+ fprintf(stderr, "Error: select one of -list, -dependents, -info, -linkedit, or -map\n");
+ usage();
+ exit(1);
+ }
- if (args.print_uuids && args.op != OP_LIST_DYLIBS)
+ if ( options.mode != modeSlideInfo ) {
+ if ( options.printUUIDs && (options.mode != modeList) )
fprintf(stderr, "Warning: -uuid option ignored outside of -list mode\n");
- if (args.print_vmaddrs && args.op != OP_LIST_DYLIBS)
+
+ if ( options.printVMAddrs && (options.mode != modeList) )
fprintf(stderr, "Warning: -vmaddr option ignored outside of -list mode\n");
- if (args.print_dylib_versions && args.op != OP_LIST_DEPENDENCIES)
+
+ if ( options.printDylibVersions && (options.mode != modeDependencies) )
fprintf(stderr, "Warning: -versions option ignored outside of -dependents mode\n");
- if (args.op == OP_LIST_DEPENDENCIES && !args.target_path) {
+ if ( (options.mode == modeDependencies) && (options.dependentsOfPath == NULL) ) {
fprintf(stderr, "Error: -dependents given, but no dylib path specified\n");
usage();
exit(1);
}
}
-
- if (!shared_cache_path)
- shared_cache_path = default_shared_cache_path();
-
- if (stat(shared_cache_path, &statbuf)) {
- fprintf(stderr, "Error: stat failed for dyld shared cache at %s\n", shared_cache_path);
+
+ struct stat statbuf;
+ if ( ::stat(sharedCachePath, &statbuf) == -1 ) {
+ fprintf(stderr, "Error: stat() failed for dyld shared cache at %s, errno=%d\n", sharedCachePath, errno);
exit(1);
}
- cache_fd = open(shared_cache_path, O_RDONLY);
- if (cache_fd < 0) {
- fprintf(stderr, "Error: failed to open shared cache file at %s\n", shared_cache_path);
+ int cache_fd = ::open(sharedCachePath, O_RDONLY);
+ if ( cache_fd < 0 ) {
+ fprintf(stderr, "Error: open() failed for shared cache file at %s, errno=%d\n", sharedCachePath, errno);
exit(1);
}
- mapped_cache = mmap(NULL, statbuf.st_size, PROT_READ, MAP_PRIVATE, cache_fd, 0);
- if (mapped_cache == MAP_FAILED) {
- fprintf(stderr, "Error: mmap() for shared cache at %s failed, errno=%d\n", shared_cache_path, errno);
+ options.mappedCache = ::mmap(NULL, statbuf.st_size, PROT_READ, MAP_PRIVATE, cache_fd, 0);
+ if (options.mappedCache == MAP_FAILED) {
+ fprintf(stderr, "Error: mmap() for shared cache at %s failed, errno=%d\n", sharedCachePath, errno);
exit(1);
}
- if ( print_slide_info ) {
- const dyldCacheHeader<LittleEndian>* header = (dyldCacheHeader<LittleEndian>*)mapped_cache;
- if ( (strcmp(header->magic(), "dyld_v1 x86_64") != 0)
- && (strcmp(header->magic(), "dyld_v1 armv6") != 0)
- && (strcmp(header->magic(), "dyld_v1 armv7") != 0)
- && (strcmp(header->magic(), "dyld_v1 armv7f") != 0)
- && (strcmp(header->magic(), "dyld_v1 armv7k") != 0) ) {
- fprintf(stderr, "Error: unrecognized dyld shared cache magic or arch does not support sliding\n");
- exit(1);
- }
+ if ( options.mode == modeSlideInfo ) {
+ const dyldCacheHeader<LittleEndian>* header = (dyldCacheHeader<LittleEndian>*)options.mappedCache;
if ( header->slideInfoOffset() == 0 ) {
fprintf(stderr, "Error: dyld shared cache does not contain slide info\n");
exit(1);
}
- const dyldCacheFileMapping<LittleEndian>* mappings = (dyldCacheFileMapping<LittleEndian>*)((char*)mapped_cache + header->mappingOffset());
+ const dyldCacheFileMapping<LittleEndian>* mappings = (dyldCacheFileMapping<LittleEndian>*)((char*)options.mappedCache + header->mappingOffset());
const dyldCacheFileMapping<LittleEndian>* dataMapping = &mappings[1];
uint64_t dataStartAddress = dataMapping->address();
uint64_t dataSize = dataMapping->size();
- const dyldCacheSlideInfo<LittleEndian>* slideInfoHeader = (dyldCacheSlideInfo<LittleEndian>*)((char*)mapped_cache+header->slideInfoOffset());
+ const dyldCacheSlideInfo<LittleEndian>* slideInfoHeader = (dyldCacheSlideInfo<LittleEndian>*)((char*)options.mappedCache+header->slideInfoOffset());
printf("slide info version=%d\n", slideInfoHeader->version());
printf("toc_count=%d, data page count=%lld\n", slideInfoHeader->toc_count(), dataSize/4096);
const dyldCacheSlideInfoEntry* entries = (dyldCacheSlideInfoEntry*)((char*)slideInfoHeader + slideInfoHeader->entries_offset());
printf("%02X", entry->bits[j]);
printf("\n");
}
-
-
+ }
+ else if ( options.mode == modeInfo ) {
+ const dyldCacheHeader<LittleEndian>* header = (dyldCacheHeader<LittleEndian>*)options.mappedCache;
+ printf("uuid: ");
+ if ( header->mappingOffset() >= 0x68 ) {
+ const uint8_t* uuid = header->uuid();
+ printf("%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
+ uuid[0], uuid[1], uuid[2], uuid[3],
+ uuid[4], uuid[5], uuid[6], uuid[7],
+ uuid[8], uuid[9], uuid[10], uuid[11],
+ uuid[12], uuid[13], uuid[14], uuid[15]);
+ }
+ else {
+ printf("n/a\n");
+ }
+ printf("image count: %u\n", header->imagesCount());
+ printf("mappings:\n");
+ 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));
+ else if ( mappings[i]. init_prot() & VM_PROT_WRITE )
+ printf(" __DATA %lluMB\n", mappings[i].size()/(1024*1024));
+ else if ( mappings[i].init_prot() & VM_PROT_READ )
+ printf(" __LINKEDIT %lluMB\n", mappings[i].size()/(1024*1024));
+ }
}
else {
segment_callback_t callback;
- if ( strcmp((char*)mapped_cache, "dyld_v1 i386") == 0 )
- callback = segment_callback<x86>;
- else if ( strcmp((char*)mapped_cache, "dyld_v1 x86_64") == 0 )
- callback = segment_callback<x86_64>;
- else if ( strcmp((char*)mapped_cache, "dyld_v1 armv5") == 0 )
- callback = segment_callback<arm>;
- else if ( strcmp((char*)mapped_cache, "dyld_v1 armv6") == 0 )
- callback = segment_callback<arm>;
- else if ( strcmp((char*)mapped_cache, "dyld_v1 armv7") == 0 )
- callback = segment_callback<arm>;
- else if ( strcmp((char*)mapped_cache, "dyld_v1 armv7f") == 0 )
- callback = segment_callback<arm>;
- else if ( strcmp((char*)mapped_cache, "dyld_v1 armv7k") == 0 )
- callback = segment_callback<arm>;
- else {
+ if ( strcmp((char*)options.mappedCache, "dyld_v1 i386") == 0 ) {
+ switch ( options.mode ) {
+ case modeList:
+ callback = print_list<x86>;
+ break;
+ case modeMap:
+ callback = print_map<x86>;
+ break;
+ case modeDependencies:
+ callback = print_dependencies<x86>;
+ break;
+ case modeLinkEdit:
+ callback = process_linkedit<x86>;
+ break;
+ case modeNone:
+ case modeInfo:
+ case modeSlideInfo:
+ break;
+ }
+ }
+ else if ( strcmp((char*)options.mappedCache, "dyld_v1 x86_64") == 0 ) {
+ switch ( options.mode ) {
+ case modeList:
+ callback = print_list<x86_64>;
+ break;
+ case modeMap:
+ callback = print_map<x86_64>;
+ break;
+ case modeDependencies:
+ callback = print_dependencies<x86_64>;
+ break;
+ case modeLinkEdit:
+ callback = process_linkedit<x86_64>;
+ break;
+ case modeNone:
+ case modeInfo:
+ case modeSlideInfo:
+ break;
+ }
+ }
+ else if ( (strncmp((char*)options.mappedCache, "dyld_v1 armv", 14) == 0)
+ || (strncmp((char*)options.mappedCache, "dyld_v1 armv", 13) == 0) ) {
+ switch ( options.mode ) {
+ case modeList:
+ callback = print_list<arm>;
+ break;
+ case modeMap:
+ callback = print_map<arm>;
+ break;
+ case modeDependencies:
+ callback = print_dependencies<arm>;
+ break;
+ case modeLinkEdit:
+ callback = process_linkedit<arm>;
+ break;
+ case modeNone:
+ case modeInfo:
+ case modeSlideInfo:
+ break;
+ }
+ }
+ else {
fprintf(stderr, "Error: unrecognized dyld shared cache magic.\n");
exit(1);
}
-
- args.mapped_cache = mapped_cache;
-
- #if __BLOCKS__
- // Shim to allow building for the host
- void *argsPtr = &args;
- dyld_shared_cache_iterate_segments_with_slide(mapped_cache,
- ^(const char* dylib, const char* segName, uint64_t offset, uint64_t size, uint64_t mappedddress, uint64_t slide ) {
- (callback)(dylib, segName, offset, size, mappedddress, slide, argsPtr);
+
+ __block Results results;
+ results.dependentTargetFound = false;
+ int iterateResult = dyld_shared_cache_iterate(options.mappedCache, statbuf.st_size,
+ ^(const dyld_shared_cache_dylib_info* dylibInfo, const dyld_shared_cache_segment_info* segInfo ) {
+ (callback)(dylibInfo, segInfo, options, results);
});
- #else
- dyld_shared_cache_iterate_segments_with_slide_nb(mapped_cache, callback, &args);
- #endif
+ if ( iterateResult != 0 ) {
+ fprintf(stderr, "Error: malformed shared cache file\n");
+ exit(1);
+ }
- if (args.op == OP_LIST_LINKEDIT) {
+ if ( options.mode == modeLinkEdit ) {
// dump -linkedit information
- for (std::map<uint32_t, char*>::iterator it = sPageToContent.begin(); it != sPageToContent.end(); ++it) {
- printf("0x%0llX %s\n", sLinkeditBase+it->first, it->second);
+ for (std::map<uint32_t, const char*>::iterator it = results.pageToContent.begin(); it != results.pageToContent.end(); ++it) {
+ printf("0x%08X %s\n", it->first, it->second);
}
}
-
- if (args.target_path && !args.target_found) {
- fprintf(stderr, "Error: could not find '%s' in the shared cache at\n %s\n", args.target_path, shared_cache_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);
exit(1);
}
}
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
+#include <math.h>
#include <fcntl.h>
+#include <dlfcn.h>
#include <signal.h>
#include <errno.h>
#include <sys/uio.h>
#include <servers/bootstrap.h>
#include <mach-o/loader.h>
#include <mach-o/fat.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/Security.h>
+#include <Security/SecCodeSigner.h>
+#include <CommonCrypto/CommonDigest.h>
#include "dyld_cache_format.h"
#include <vector>
#include <set>
#include <map>
-#include <ext/hash_map>
+#include <unordered_map>
#include "Architectures.hpp"
#include "MachOLayout.hpp"
#include "MachORebaser.hpp"
#include "MachOBinder.hpp"
#include "CacheFileAbstraction.hpp"
+#include "dyld_cache_config.h"
#define SELOPT_WRITE
#include "objc-shared-cache.h"
-#define FIRST_DYLIB_TEXT_OFFSET 0x7000
-#define FIRST_DYLIB_DATA_OFFSET 0x1000
+#define FIRST_DYLIB_TEXT_OFFSET 0x8000
#ifndef LC_FUNCTION_STARTS
#define LC_FUNCTION_STARTS 0x26
}
-static uint64_t pageAlign(uint64_t addr) { return ( (addr + 4095) & (-4096) ); }
+class CStringHash {
+public:
+ size_t operator()(const char* __s) const {
+ size_t __h = 0;
+ for ( ; *__s; ++__s)
+ __h = 5 * __h + *__s;
+ return __h;
+ };
+};
+class CStringEquals
+{
+public:
+ bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+};
+
+
class ArchGraph
{
public:
- struct CStringEquals {
- bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
- };
- typedef __gnu_cxx::hash_map<const char*, const char*, __gnu_cxx::hash<const char*>, CStringEquals> StringToString;
+ typedef std::unordered_map<const char*, const char*, CStringHash, CStringEquals> StringToString;
static void addArchPair(ArchPair ap);
static void addRoot(const char* vpath, const std::set<ArchPair>& archs);
std::set<DependencyNode*> fRootsDependentOnThis;
};
- typedef __gnu_cxx::hash_map<const char*, class DependencyNode*, __gnu_cxx::hash<const char*>, CStringEquals> PathToNode;
+ typedef std::unordered_map<const char*, class DependencyNode*, CStringHash, CStringEquals> PathToNode;
ArchGraph(ArchPair ap) : fArchPair(ap) {}
//fprintf(stderr, "adding %s node alias %s for %s\n", archName(fArchPair), node->getLayout()->getID().name, realPath);
pos = fNodes.find(node->getLayout()->getID().name);
if ( pos != fNodes.end() ) {
- // <rdar://problem/8305479> warn if two dylib in cache have same install_name
- char* msg;
- asprintf(&msg, "update_dyld_shared_cache: warning, found two dylibs with same install path: %s\n\t%s\n\t%s\n",
- node->getLayout()->getID().name, pos->second->getPath(), node->getPath());
- fprintf(stderr, "%s", msg);
- warnings.push_back(msg);
+ // get uuids of two dylibs to see if this is accidental copy of a dylib or two differnent dylibs with same -install_name
+ uuid_t uuid1;
+ uuid_t uuid2;
+ node->getLayout()->uuid(uuid1);
+ pos->second->getLayout()->uuid(uuid2);
+ if ( memcmp(&uuid1, &uuid2, 16) == 0 ) {
+ // <rdar://problem/8305479> warn if two dylib in cache have same install_name
+ char* msg;
+ asprintf(&msg, "update_dyld_shared_cache: warning, found two copies of the same dylib with same install path: %s\n\t%s\n\t%s\n",
+ node->getLayout()->getID().name, pos->second->getPath(), node->getPath());
+ fprintf(stderr, "%s", msg);
+ warnings.push_back(msg);
+ }
+ else {
+ // <rdar://problem/12763450> update_dyld_shared_cache should fail if two images have same install name
+ fprintf(stderr, "update_dyld_shared_cache: found two different dylibs with same install path: %s\n\t%s\n\t%s\n",
+ node->getLayout()->getID().name, pos->second->getPath(), node->getPath());
+ exit(1);
+ }
}
else
fNodes[node->getLayout()->getID().name] = node;
return "armv7f";
case CPU_SUBTYPE_ARM_V7K:
return "armv7k";
+ case CPU_SUBTYPE_ARM_V7S:
+ return "armv7s";
default:
return "arm";
}
}
+
+class StringPool
+{
+public:
+ StringPool();
+ const char* getBuffer();
+ uint32_t size();
+ 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;
+
+ char* fBuffer;
+ uint32_t fBufferAllocated;
+ uint32_t fBufferUsed;
+ StringToOffset fUniqueStrings;
+};
+
+
+StringPool::StringPool()
+ : fBufferUsed(0), fBufferAllocated(48*1024*1024)
+{
+ fBuffer = (char*)malloc(fBufferAllocated);
+}
+
+uint32_t StringPool::add(const char* str)
+{
+ uint32_t len = strlen(str);
+ if ( (fBufferUsed + len + 1) > fBufferAllocated ) {
+ // grow buffer
+ throw "string buffer exhausted";
+ }
+ strcpy(&fBuffer[fBufferUsed], str);
+ uint32_t result = fBufferUsed;
+ fUniqueStrings[&fBuffer[fBufferUsed]] = result;
+ fBufferUsed += len+1;
+ return result;
+}
+
+uint32_t StringPool::addUnique(const char* str)
+{
+ StringToOffset::iterator pos = fUniqueStrings.find(str);
+ if ( pos != fUniqueStrings.end() )
+ return pos->second;
+ else {
+ //fprintf(stderr, "StringPool::addUnique() new string: %s\n", str);
+ return this->add(str);
+ }
+}
+
+uint32_t StringPool::size()
+{
+ return fBufferUsed;
+}
+
+const char* StringPool::getBuffer()
+{
+ return fBuffer;
+}
+
+const char* StringPool::stringAtIndex(uint32_t index) const
+{
+ return &fBuffer[index];
+}
+
+
+
+struct LocalSymbolInfo
+{
+ uint32_t dylibOffset;
+ uint32_t nlistStartIndex;
+ uint32_t nlistCount;
+};
+
+
template <typename A>
class SharedCache
{
SharedCache(ArchGraph* graph, const char* rootPath, const char* overlayPath, 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);
+ int archCount, bool keepSignatures, bool dontMapLocalSymbols);
static const char* cacheFileSuffix(bool optimized, const char* archName);
// vm address = address AS WRITTEN into the cache
bool notUpToDate(const char* path, unsigned int aliasCount);
bool notUpToDate(const void* cache, unsigned int aliasCount);
- uint8_t* optimizeLINKEDIT(bool keepSignatures);
+ uint8_t* optimizeLINKEDIT(bool keepSignatures, bool dontMapLocalSymbols);
void optimizeObjC(std::vector<void*>& pointersInData);
static void getSharedCacheBasAddresses(cpu_type_t arch, uint64_t* baseReadOnly, uint64_t* baseWritable);
static cpu_type_t arch();
- static uint64_t sharedRegionReadOnlyStartAddress();
- static uint64_t sharedRegionWritableStartAddress();
- static uint64_t sharedRegionReadOnlySize();
- static uint64_t sharedRegionWritableSize();
+ static uint64_t sharedRegionStartAddress();
+ static uint64_t sharedRegionSize();
+ static uint64_t sharedRegionStartWritableAddress(uint64_t);
+ 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 pageAlign(uint64_t addr);
void assignNewBaseAddresses(bool verify);
struct LayoutInfo {
std::vector<LayoutInfo> fDylibs;
std::vector<LayoutInfo> fDylibAliases;
std::vector<shared_file_mapping_np> fMappings;
+ std::vector<macho_nlist<P> > fUnmappedLocalSymbols;
+ StringPool fUnmappedLocalsStringPool;
+ std::vector<LocalSymbolInfo> fLocalSymbolInfos;
uint32_t fHeaderSize;
uint8_t* fInMemoryCache;
uint64_t fDyldBaseAddress;
uint32_t fOffsetOfDataInCodeInCombinedLinkedit;
uint32_t fSizeOfDataInCodeInCombinedLinkedit;
uint32_t fLinkEditsTotalOptimizedSize;
+ uint32_t fUnmappedLocalSymbolsSize;
};
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 <> uint64_t SharedCache<x86>::sharedRegionReadOnlyStartAddress() { return 0x90000000; }
-template <> uint64_t SharedCache<x86_64>::sharedRegionReadOnlyStartAddress() { return 0x7FFF80000000LL; }
-template <> uint64_t SharedCache<arm>::sharedRegionReadOnlyStartAddress() { return 0x30000000; }
+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<x86>::sharedRegionWritableStartAddress() { return 0xAC000000; }
-template <> uint64_t SharedCache<x86_64>::sharedRegionWritableStartAddress() { return 0x7FFF70000000LL; }
-template <> uint64_t SharedCache<arm>::sharedRegionWritableStartAddress() { return 0x3E000000; }
+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<x86>::sharedRegionReadOnlySize() { return 0x1C000000; }
-template <> uint64_t SharedCache<x86_64>::sharedRegionReadOnlySize() { return 0x40000000; }
-template <> uint64_t SharedCache<arm>::sharedRegionReadOnlySize() { return 0x0E000000; }
+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<x86>::sharedRegionWritableSize() { return 0x04000000; }
-template <> uint64_t SharedCache<x86_64>::sharedRegionWritableSize() { return 0x10000000; }
-template <> uint64_t SharedCache<arm>::sharedRegionWritableSize() { return 0x02000000; }
+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 <> const char* SharedCache<x86>::archName() { return "i386"; }
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 <> 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 <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)
: fArchGraph(graph), fVerify(verify), fExistingIsNotUpToDate(true),
fOffsetOfOldIndirectSymbolsInCombinedLinkedit(0), fSizeOfOldIndirectSymbolsInCombinedLinkedit(0),
fOffsetOfOldStringPoolInCombinedLinkedit(0), fSizeOfOldStringPoolInCombinedLinkedit(0),
fOffsetOfFunctionStartsInCombinedLinkedit(0), fSizeOfFunctionStartsInCombinedLinkedit(0),
- fOffsetOfDataInCodeInCombinedLinkedit(0), fSizeOfDataInCodeInCombinedLinkedit(0)
+ fOffsetOfDataInCodeInCombinedLinkedit(0), fSizeOfDataInCodeInCombinedLinkedit(0),
+ fUnmappedLocalSymbolsSize(0)
{
if ( fArchGraph->getArchPair().arch != arch() )
throwf("SharedCache object is wrong architecture: 0x%08X vs 0x%08X", fArchGraph->getArchPair().arch, arch());
fHeaderSize = sizeof(dyld_cache_header)
+ fMappings.size()*sizeof(shared_file_mapping_np)
+ (fDylibs.size()+aliasCount)*sizeof(dyld_cache_image_info);
+ const uint64_t baseHeaderSize = fHeaderSize;
//fprintf(stderr, "aliasCount=%d, fHeaderSize=0x%08X\n", aliasCount, fHeaderSize);
// build list of aliases and compute where each ones path string will go
for(typename std::vector<struct LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
// if no existing cache, say so
if ( fExistingCacheForVerification == NULL ) {
throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify because cache file does not exist in /var/db/dyld/\n",
- getpid(), archName());
+ getpid(), fArchGraph->archName());
}
const dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)fExistingCacheForVerification;
const dyldCacheImageInfo<E>* cacheEntry = (dyldCacheImageInfo<E>*)(fExistingCacheForVerification + header->imagesOffset());
for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it, ++cacheEntry) {
if ( cacheEntry->address() != it->layout->getSegments()[0].newAddress() ) {
throwf("update_dyld_shared_cache[%u] warning: for arch=%s, could not verify cache because start address of %s is 0x%llX in cache, but should be 0x%llX\n",
- getpid(), archName(), it->layout->getID().name, cacheEntry->address(), it->layout->getSegments()[0].newAddress());
+ getpid(), fArchGraph->archName(), it->layout->getID().name, cacheEntry->address(), it->layout->getSegments()[0].newAddress());
}
}
}
if ( fHeaderSize > FIRST_DYLIB_TEXT_OFFSET )
- throwf("header size miscalculation 0x%08X", fHeaderSize);
+ throwf("header size overflow: allowed=0x%08X, base=0x%08llX, aliases=0x%08llX", FIRST_DYLIB_TEXT_OFFSET, baseHeaderSize, fHeaderSize-baseHeaderSize);
}
template <typename A>
void SharedCache<A>::assignNewBaseAddresses(bool verify)
{
- uint64_t sharedCacheStartAddress = sharedRegionReadOnlyStartAddress();
-#if 0
- if ( arch() == CPU_TYPE_X86_64 ) {
- if ( verify ) {
- if ( fExistingCacheForVerification == NULL ) {
- throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify because cache file does not exist in /var/db/dyld/\n",
- getpid(), archName());
- }
- const dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)fExistingCacheForVerification;
- const dyldCacheFileMapping<E>* mappings = (dyldCacheFileMapping<E>*)(fExistingCacheForVerification + header->mappingOffset());
- sharedCacheStartAddress = mappings[0].address();
- }
- else {
- // <rdar://problem/5274722> dyld shared cache can be more random
- uint64_t readOnlySize = 0;
- for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
- if ( ! it->layout->hasSplitSegInfo() )
- continue;
- std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
- for (int i=0; i < segs.size(); ++i) {
- MachOLayoutAbstraction::Segment& seg = segs[i];
- if ( ! seg.writable() )
- readOnlySize += pageAlign(seg.size());
- }
+ // first layout TEXT for dylibs
+ const uint64_t startExecuteAddress = sharedRegionStartAddress();
+ uint64_t currentExecuteAddress = startExecuteAddress + FIRST_DYLIB_TEXT_OFFSET;
+ for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
+ std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
+ for (int i=0; i < segs.size(); ++i) {
+ MachOLayoutAbstraction::Segment& seg = segs[i];
+ seg.reset();
+ if ( seg.executable() && !seg.writable() ) {
+ // __TEXT segment
+ if ( it->info.address == 0 )
+ it->info.address = currentExecuteAddress;
+ seg.setNewAddress(currentExecuteAddress);
+ currentExecuteAddress += pageAlign(seg.size());
}
- uint64_t maxSlide = sharedRegionReadOnlySize() - (readOnlySize + FIRST_DYLIB_TEXT_OFFSET);
- sharedCacheStartAddress = sharedRegionReadOnlyStartAddress() + pageAlign(arc4random() % maxSlide);
}
}
-#endif
- uint64_t currentExecuteAddress = sharedCacheStartAddress + FIRST_DYLIB_TEXT_OFFSET;
- uint64_t currentWritableAddress = sharedRegionWritableStartAddress() + FIRST_DYLIB_DATA_OFFSET;
- // first layout TEXT and DATA for dylibs
+ // layout DATA for dylibs
+ const uint64_t startWritableAddress = sharedRegionStartWritableAddress(currentExecuteAddress);
+ uint64_t currentWritableAddress = startWritableAddress;
for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
- MachOLayoutAbstraction::Segment* executableSegment = NULL;
for (int i=0; i < segs.size(); ++i) {
MachOLayoutAbstraction::Segment& seg = segs[i];
seg.reset();
if ( seg.writable() ) {
- if ( seg.executable() && it->layout->hasSplitSegInfo() ) {
- // skip __IMPORT segments in this pass
- }
- else {
- // __DATA segment
- if ( it->layout->hasSplitSegInfo() ) {
- if ( executableSegment == NULL )
- throwf("first segment in dylib is not executable for %s", it->layout->getID().name);
- seg.setNewAddress(getWritableSegmentNewAddress(currentWritableAddress, seg.address(), executableSegment->newAddress() - executableSegment->address()));
- }
- else
- seg.setNewAddress(currentWritableAddress);
- currentWritableAddress = pageAlign(seg.newAddress() + seg.size());
- }
- }
- else {
- if ( seg.executable() ) {
- // __TEXT segment
- if ( it->info.address == 0 )
- it->info.address = currentExecuteAddress;
- executableSegment = &seg;
- seg.setNewAddress(currentExecuteAddress);
- currentExecuteAddress += pageAlign(seg.size());
- }
- else {
- // skip read-only segments in this pass
- }
+ if ( seg.executable() )
+ throw "found writable and executable segment";
+ // __DATA segment
+ seg.setNewAddress(currentWritableAddress);
+ currentWritableAddress = pageAlign(seg.newAddress() + seg.size());
}
}
}
- // append all read-only (but not LINKEDIT) segments at end of all TEXT segments
- // append all IMPORT segments at end of all DATA segments rounded to next 2MB
- uint64_t currentReadOnlyAddress = currentExecuteAddress;
- uint64_t startWritableExecutableAddress = (currentWritableAddress + 0x200000 - 1) & (-0x200000);
- uint64_t currentWritableExecutableAddress = startWritableExecutableAddress;
+ // layout all read-only (but not LINKEDIT) segments
+ const uint64_t startReadOnlyAddress = sharedRegionStartReadOnlyAddress(currentWritableAddress, currentExecuteAddress);
+ uint64_t currentReadOnlyAddress = startReadOnlyAddress;
for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
for(int i=0; i < segs.size(); ++i) {
MachOLayoutAbstraction::Segment& seg = segs[i];
- if ( !seg.writable() && !seg.executable() && (strcmp(seg.name(), "__LINKEDIT") != 0) ) {
- // allocate non-executable,read-only segments from end of read only shared region
+ if ( seg.readable() && !seg.writable() && !seg.executable() && (strcmp(seg.name(), "__LINKEDIT") != 0) ) {
+ // __UNICODE segment
seg.setNewAddress(currentReadOnlyAddress);
currentReadOnlyAddress += pageAlign(seg.size());
}
- else if ( seg.writable() && seg.executable() && it->layout->hasSplitSegInfo() ) {
- // allocate IMPORT segments to end of writable shared region
- seg.setNewAddress(currentWritableExecutableAddress);
- currentWritableExecutableAddress += pageAlign(seg.size());
- }
}
}
- // append all LINKEDIT segments at end of all read-only segments
+ // layout all LINKEDIT segments at end of all read-only segments
fLinkEditsStartAddress = currentReadOnlyAddress;
fFirstLinkEditSegment = NULL;
for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
std::vector<MachOLayoutAbstraction::Segment>& segs = ((MachOLayoutAbstraction*)(it->layout))->getSegments();
for(int i=0; i < segs.size(); ++i) {
MachOLayoutAbstraction::Segment& seg = segs[i];
- if ( !seg.writable() && !seg.executable() && (strcmp(seg.name(), "__LINKEDIT") == 0) ) {
+ if ( seg.readable() && !seg.writable() && !seg.executable() && (strcmp(seg.name(), "__LINKEDIT") == 0) ) {
if ( fFirstLinkEditSegment == NULL )
fFirstLinkEditSegment = &seg;
- // allocate non-executable,read-only segments from end of read only shared region
seg.setNewAddress(currentReadOnlyAddress);
currentReadOnlyAddress += pageAlign(seg.size());
}
}
}
- fLinkEditsTotalUnoptimizedSize = (currentReadOnlyAddress - fLinkEditsStartAddress + 4095) & (-4096);
-
- // <rdar://problem/9361288> i386 dyld shared cache overflows after adding libclh.dylib
- if ( (currentReadOnlyAddress - sharedRegionReadOnlyStartAddress()) > sharedRegionReadOnlySize() )
- throwf("read-only slice of cache too big: %lluMB (max %lluMB)",
- (currentReadOnlyAddress - sharedRegionReadOnlyStartAddress())/(1024*1024),
- sharedRegionReadOnlySize()/(1024*1024));
-
+ fLinkEditsTotalUnoptimizedSize = pageAlign(currentReadOnlyAddress - fLinkEditsStartAddress);
// populate large mappings
uint64_t cacheFileOffset = 0;
- if ( currentExecuteAddress > sharedCacheStartAddress + FIRST_DYLIB_TEXT_OFFSET ) {
+ if ( currentExecuteAddress > startExecuteAddress ) {
shared_file_mapping_np executeMapping;
- executeMapping.sfm_address = sharedCacheStartAddress;
- executeMapping.sfm_size = currentExecuteAddress - sharedCacheStartAddress;
+ executeMapping.sfm_address = startExecuteAddress;
+ executeMapping.sfm_size = currentExecuteAddress - startExecuteAddress;
executeMapping.sfm_file_offset = cacheFileOffset;
executeMapping.sfm_max_prot = VM_PROT_READ | VM_PROT_EXECUTE;
executeMapping.sfm_init_prot = VM_PROT_READ | VM_PROT_EXECUTE;
cacheFileOffset += executeMapping.sfm_size;
shared_file_mapping_np writableMapping;
- writableMapping.sfm_address = sharedRegionWritableStartAddress();
- writableMapping.sfm_size = currentWritableAddress - sharedRegionWritableStartAddress();
+ writableMapping.sfm_address = startWritableAddress;
+ writableMapping.sfm_size = currentWritableAddress - startWritableAddress;
writableMapping.sfm_file_offset = cacheFileOffset;
writableMapping.sfm_max_prot = VM_PROT_READ | VM_PROT_WRITE;
writableMapping.sfm_init_prot = VM_PROT_READ | VM_PROT_WRITE;
fMappings.push_back(writableMapping);
cacheFileOffset += writableMapping.sfm_size;
-
- if ( currentWritableExecutableAddress > startWritableExecutableAddress ) {
- shared_file_mapping_np writableExecutableMapping;
- writableExecutableMapping.sfm_address = startWritableExecutableAddress;
- writableExecutableMapping.sfm_size = currentWritableExecutableAddress - startWritableExecutableAddress;
- writableExecutableMapping.sfm_file_offset= cacheFileOffset;
- writableExecutableMapping.sfm_max_prot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
- writableExecutableMapping.sfm_init_prot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
- fMappings.push_back(writableExecutableMapping);
- cacheFileOffset += writableExecutableMapping.sfm_size;
- }
-
+
// make read-only (contains LINKEDIT segments) last, so it can be cut back when optimized
shared_file_mapping_np readOnlyMapping;
- readOnlyMapping.sfm_address = currentExecuteAddress;
- readOnlyMapping.sfm_size = currentReadOnlyAddress - currentExecuteAddress;
+ readOnlyMapping.sfm_address = startReadOnlyAddress;
+ readOnlyMapping.sfm_size = currentReadOnlyAddress - startReadOnlyAddress;
readOnlyMapping.sfm_file_offset = cacheFileOffset;
readOnlyMapping.sfm_max_prot = VM_PROT_READ;
readOnlyMapping.sfm_init_prot = VM_PROT_READ;
else {
// empty cache
shared_file_mapping_np cacheHeaderMapping;
- cacheHeaderMapping.sfm_address = sharedRegionWritableStartAddress();
+ cacheHeaderMapping.sfm_address = startExecuteAddress;
cacheHeaderMapping.sfm_size = FIRST_DYLIB_TEXT_OFFSET;
cacheHeaderMapping.sfm_file_offset = cacheFileOffset;
cacheHeaderMapping.sfm_max_prot = VM_PROT_READ;
struct stat stat_buf;
::fstat(fd, &stat_buf);
uint32_t cacheFileSize = stat_buf.st_size;
- uint32_t cacheAllocatedSize = (cacheFileSize + 4095) & (-4096);
+ uint32_t cacheAllocatedSize = pageAlign(cacheFileSize);
uint8_t* mappingAddr = NULL;
if ( vm_allocate(mach_task_self(), (vm_address_t*)(&mappingAddr), cacheAllocatedSize, VM_FLAGS_ANYWHERE) != KERN_SUCCESS )
throwf("can't vm_allocate cache of size %u", cacheFileSize);
return result;
}
-class CStringEquals
-{
-public:
- bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
-};
-
-class StringPool
-{
-public:
- StringPool();
- const char* getBuffer();
- uint32_t size();
- uint32_t add(const char* str);
- uint32_t addUnique(const char* str);
- const char* stringAtIndex(uint32_t) const;
-private:
- typedef __gnu_cxx::hash_map<const char*, uint32_t, __gnu_cxx::hash<const char*>, CStringEquals> StringToOffset;
-
- char* fBuffer;
- uint32_t fBufferAllocated;
- uint32_t fBufferUsed;
- StringToOffset fUniqueStrings;
-};
-
-
-StringPool::StringPool()
- : fBufferUsed(0), fBufferAllocated(32*1024*1024)
-{
- fBuffer = (char*)malloc(fBufferAllocated);
-}
-
-uint32_t StringPool::add(const char* str)
-{
- uint32_t len = strlen(str);
- if ( (fBufferUsed + len + 1) > fBufferAllocated ) {
- // grow buffer
- throw "string buffer exhausted";
- }
- strcpy(&fBuffer[fBufferUsed], str);
- uint32_t result = fBufferUsed;
- fUniqueStrings[&fBuffer[fBufferUsed]] = result;
- fBufferUsed += len+1;
- return result;
-}
-
-uint32_t StringPool::addUnique(const char* str)
-{
- StringToOffset::iterator pos = fUniqueStrings.find(str);
- if ( pos != fUniqueStrings.end() )
- return pos->second;
- else {
- //fprintf(stderr, "StringPool::addUnique() new string: %s\n", str);
- return this->add(str);
- }
-}
-
-uint32_t StringPool::size()
-{
- return fBufferUsed;
-}
-
-const char* StringPool::getBuffer()
-{
- return fBuffer;
-}
-
-const char* StringPool::stringAtIndex(uint32_t index) const
-{
- return &fBuffer[index];
-}
template <typename A>
void copyWeakBindInfo(uint32_t&);
void copyLazyBindInfo(uint32_t&);
void copyExportInfo(uint32_t&);
- void copyLocalSymbols(uint32_t symbolTableOffset, uint32_t&);
+ void copyLocalSymbols(uint32_t symbolTableOffset, uint32_t&, bool dontMapLocalSymbols,
+ uint8_t* cacheStart, StringPool& unmappedLocalsStringPool,
+ std::vector<macho_nlist<typename A::P> >& unmappedSymbols,
+ std::vector<LocalSymbolInfo>& info);
void copyExportedSymbols(uint32_t symbolTableOffset, uint32_t&);
void copyImportedSymbols(uint32_t symbolTableOffset, uint32_t&);
void copyExternalRelocations(uint32_t& offset);
uint32_t fIndirectSymbolTableOffsetInfoNewLinkEdit;
uint32_t fFunctionStartsOffsetInNewLinkEdit;
uint32_t fDataInCodeOffsetInNewLinkEdit;
+ uint32_t fUnmappedLocalSymbolsStartIndexInNewLinkEdit;
+ uint32_t fUnmappedLocalSymbolsCountInNewLinkEdit;
};
fExportedSymbolsStartIndexInNewLinkEdit(0), fExportedSymbolsCountInNewLinkEdit(0),
fImportSymbolsStartIndexInNewLinkEdit(0), fImportedSymbolsCountInNewLinkEdit(0),
fExternalRelocationsOffsetIntoNewLinkEdit(0), fIndirectSymbolTableOffsetInfoNewLinkEdit(0),
- fFunctionStartsOffsetInNewLinkEdit(0), fDataInCodeOffsetInNewLinkEdit(0)
+ fFunctionStartsOffsetInNewLinkEdit(0), fDataInCodeOffsetInNewLinkEdit(0),
+ fUnmappedLocalSymbolsStartIndexInNewLinkEdit(0), fUnmappedLocalSymbolsCountInNewLinkEdit(0)
{
fHeader = (const macho_header<P>*)fLayout.getSegments()[0].mappedAddress();
}
-
template <typename A>
-void LinkEditOptimizer<A>::copyLocalSymbols(uint32_t symbolTableOffset, uint32_t& symbolIndex)
+void LinkEditOptimizer<A>::copyLocalSymbols(uint32_t symbolTableOffset, uint32_t& symbolIndex, bool dontMapLocalSymbols, uint8_t* cacheStart,
+ StringPool& unmappedLocalsStringPool, std::vector<macho_nlist<P> >& unmappedSymbols,
+ std::vector<LocalSymbolInfo>& dylibInfos)
{
fLocalSymbolsStartIndexInNewLinkEdit = symbolIndex;
+ LocalSymbolInfo localInfo;
+ localInfo.dylibOffset = ((uint8_t*)fHeader) - cacheStart;
+ localInfo.nlistStartIndex = unmappedSymbols.size();
+ localInfo.nlistCount = 0;
fSymbolTableStartOffsetInNewLinkEdit = symbolTableOffset + symbolIndex*sizeof(macho_nlist<P>);
macho_nlist<P>* const newSymbolTableStart = (macho_nlist<P>*)(fNewLinkEditStart+symbolTableOffset);
const macho_nlist<P>* const firstLocal = &fSymbolTable[fDynamicSymbolTable->ilocalsym()];
const macho_nlist<P>* const lastLocal = &fSymbolTable[fDynamicSymbolTable->ilocalsym()+fDynamicSymbolTable->nlocalsym()];
uint32_t oldIndex = fDynamicSymbolTable->ilocalsym();
for (const macho_nlist<P>* entry = firstLocal; entry < lastLocal; ++entry, ++oldIndex) {
- if ( (entry->n_type() & N_TYPE) == N_SECT ) {
+ // <rdar://problem/12237639> don't copy stab symbols
+ if ( (entry->n_sect() != NO_SECT) && ((entry->n_type() & N_STAB) == 0) ) {
+ const char* name = &fStrings[entry->n_strx()];
macho_nlist<P>* newSymbolEntry = &newSymbolTableStart[symbolIndex];
*newSymbolEntry = *entry;
- newSymbolEntry->set_n_strx(fNewStringPool.addUnique(&fStrings[entry->n_strx()]));
- ++symbolIndex;
+ if ( dontMapLocalSymbols ) {
+ // if local in __text, add <redacted> symbol name to shared cache so backtraces don't have bogus names
+ if ( entry->n_sect() == 1 ) {
+ newSymbolEntry->set_n_strx(fNewStringPool.addUnique("<redacted>"));
+ ++symbolIndex;
+ }
+ // copy local symbol to unmmapped locals area
+ unmappedSymbols.push_back(*entry);
+ unmappedSymbols.back().set_n_strx(unmappedLocalsStringPool.addUnique(name));
+ }
+ else {
+ newSymbolEntry->set_n_strx(fNewStringPool.addUnique(name));
+ ++symbolIndex;
+ }
}
}
fLocalSymbolsCountInNewLinkEdit = symbolIndex - fLocalSymbolsStartIndexInNewLinkEdit;
+ localInfo.nlistCount = unmappedSymbols.size() - localInfo.nlistStartIndex;
+ dylibInfos.push_back(localInfo);
//fprintf(stderr, "%u locals starting at %u for %s\n", fLocalSymbolsCountInNewLinkEdit, fLocalSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
}
template <typename A>
-uint8_t* SharedCache<A>::optimizeLINKEDIT(bool keepSignatures)
+uint8_t* SharedCache<A>::optimizeLINKEDIT(bool keepSignatures, bool dontMapLocalSymbols)
{
// allocate space for optimized LINKEDIT area
uint8_t* newLinkEdit = new uint8_t[fLinkEditsTotalUnoptimizedSize];
fOffsetOfOldSymbolTableInfoInCombinedLinkedit = offset;
uint32_t symbolTableOffset = offset;
uint32_t symbolTableIndex = 0;
+ if ( dontMapLocalSymbols )
+ fUnmappedLocalSymbols.reserve(16384);
for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
- (*it)->copyLocalSymbols(symbolTableOffset, symbolTableIndex);
+ (*it)->copyLocalSymbols(symbolTableOffset, symbolTableIndex, dontMapLocalSymbols, fInMemoryCache,
+ fUnmappedLocalsStringPool, fUnmappedLocalSymbols, fLocalSymbolInfos);
(*it)->copyExportedSymbols(symbolTableOffset, symbolTableIndex);
(*it)->copyImportedSymbols(symbolTableOffset, symbolTableIndex);
}
fSizeOfOldStringPoolInCombinedLinkedit = stringPool.size();
// total new size round up to page size
- fLinkEditsTotalOptimizedSize = (fOffsetOfOldStringPoolInCombinedLinkedit + fSizeOfOldStringPoolInCombinedLinkedit + 4095) & (-4096);
+ fLinkEditsTotalOptimizedSize = pageAlign(fOffsetOfOldStringPoolInCombinedLinkedit + fSizeOfOldStringPoolInCombinedLinkedit);
// choose new linkedit file offset
uint32_t linkEditsFileOffset = cacheFileOffsetForVMAddress(fLinkEditsStartAddress);
-// uint32_t linkEditsFileOffset = fLinkEditsStartAddress - sharedRegionReadOnlyStartAddress();
+// uint32_t linkEditsFileOffset = fLinkEditsStartAddress - sharedRegionStartAddress();
// 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) {
}
+// <rdar://problem/10730767> update_dyld_shared_cache should use sync_volume_np() instead of sync()
+static void sync_volume(const char* volumePath)
+{
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
+ int error = sync_volume_np(volumePath, SYNC_VOLUME_FULLSYNC|SYNC_VOLUME_FULLSYNC);
+#else
+ int full_sync = 3; // SYNC_VOLUME_FULLSYNC | SYNC_VOLUME_FULLSYNC
+ int error = 0;
+ if ( fsctl(volumePath, 0x80004101 /*FSCTL_SYNC_VOLUME*/, &full_sync, 0) == -1)
+ error = errno;
+#endif
+ if ( error )
+ ::sync();
+}
+
+
+// <rdar://problem/12552226> update shared cache should sign the shared cache
+static bool adhoc_codesign_share_cache(const char* path)
+{
+ CFURLRef target = ::CFURLCreateFromFileSystemRepresentation(NULL, (const UInt8 *)path, strlen(path), FALSE);
+ if ( target == NULL )
+ return false;
+
+ SecStaticCodeRef code;
+ OSStatus status = ::SecStaticCodeCreateWithPath(target, kSecCSDefaultFlags, &code);
+ CFRelease(target);
+ if ( status ) {
+ ::fprintf(stderr, "codesign: failed to create url to signed object\n");
+ return false;
+ }
+
+ const void * keys[1] = { (void *)kSecCodeSignerIdentity } ;
+ const void * values[1] = { (void *)kCFNull };
+ CFDictionaryRef params = ::CFDictionaryCreate(NULL, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ if ( params == NULL ) {
+ CFRelease(code);
+ return false;
+ }
+
+ SecCodeSignerRef signer;
+ status = ::SecCodeSignerCreate(params, kSecCSDefaultFlags, &signer);
+ CFRelease(params);
+ if ( status ) {
+ CFRelease(code);
+ ::fprintf(stderr, "codesign: failed to create signer object\n");
+ return false;
+ }
+
+ status = ::SecCodeSignerAddSignatureWithErrors(signer, code, kSecCSDefaultFlags, NULL);
+ CFRelease(code);
+ CFRelease(signer);
+ if ( status ) {
+ ::fprintf(stderr, "codesign: failed to sign object: %s\n", path);
+ return false;
+ }
+
+ if ( verbose )
+ ::fprintf(stderr, "codesigning complete of %s\n", path);
+
+ return true;
+}
+
+
template <> bool SharedCache<x86_64>::addCacheSlideInfo(){ return true; }
template <> bool SharedCache<arm>::addCacheSlideInfo() { return true; }
template <typename A>
bool SharedCache<A>::update(bool force, bool optimize, bool deleteExistingFirst, int archIndex,
- int archCount, bool keepSignatures)
+ int archCount, bool keepSignatures, bool dontMapLocalSymbols)
{
bool didUpdate = false;
header->set_codeSignatureSize(0);
header->set_slideInfoOffset(0);
header->set_slideInfoSize(0);
+ header->set_localSymbolsOffset(0);
+ header->set_localSymbolsSize(0);
// fill in mappings
dyldCacheFileMapping<E>* mapping = (dyldCacheFileMapping<E>*)&inMemoryCache[sizeof(dyldCacheHeader<E>)];
std::vector<void*> pointersInData;
pointersInData.reserve(1024);
- // add pointer in start of __DATA to start of __TEXT to remain compatible with previous dylds
- pint_t* dataStartPtr = (pint_t*)(&inMemoryCache[fMappings[1].sfm_file_offset]);
- P::setP(*dataStartPtr, fMappings[0].sfm_address);
-
// rebase each dylib in shared cache
for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
try {
// merge/optimize all LINKEDIT segments
if ( optimize ) {
//fprintf(stderr, "update_dyld_shared_cache: original cache file size %uMB\n", cacheFileSize/(1024*1024));
- cacheFileSize = (this->optimizeLINKEDIT(keepSignatures) - inMemoryCache);
+ cacheFileSize = (this->optimizeLINKEDIT(keepSignatures, dontMapLocalSymbols) - inMemoryCache);
//fprintf(stderr, "update_dyld_shared_cache: optimized cache file size %uMB\n", cacheFileSize/(1024*1024));
// update header to reduce mapping size
dyldCacheHeader<E>* cacheHeader = (dyldCacheHeader<E>*)inMemoryCache;
}
slideInfo->set_entries_count(entry_count);
- int slideInfoPageSize = (slideInfo->entries_offset() + entry_count*entry_size + 4095) & (-4096);
+ int slideInfoPageSize = pageAlign(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;
+ uint32_t localSymbolsOffset = pageAlign(cacheFileSize);
+ dyldCacheLocalSymbolsInfo<E>* infoHeader = (dyldCacheLocalSymbolsInfo<E>*)(&inMemoryCache[localSymbolsOffset]);
+ const uint32_t entriesOffset = sizeof(dyldCacheLocalSymbolsInfo<E>);
+ const uint32_t entriesCount = fLocalSymbolInfos.size();
+ const uint32_t nlistOffset = entriesOffset + entriesCount * sizeof(dyldCacheLocalSymbolEntry<E>);
+ const uint32_t nlistCount = fUnmappedLocalSymbols.size();
+ const uint32_t stringsOffset = nlistOffset + nlistCount * sizeof(macho_nlist<P>);
+ const uint32_t stringsSize = fUnmappedLocalsStringPool.size();
+ if ( stringsOffset+stringsSize > spaceAtEnd )
+ throwf("update_dyld_shared_cache[%u] for arch=%s, out of space for local symbols. Have 0x%X, Need 0x%X\n",
+ getpid(), fArchGraph->archName(), spaceAtEnd, stringsOffset+stringsSize);
+ // fill in local symbols info
+ infoHeader->set_nlistOffset(nlistOffset);
+ infoHeader->set_nlistCount(nlistCount);
+ infoHeader->set_stringsOffset(stringsOffset);
+ infoHeader->set_stringsSize(stringsSize);
+ infoHeader->set_entriesOffset(entriesOffset);
+ infoHeader->set_entriesCount(entriesCount);
+ // copy info for each dylib
+ dyldCacheLocalSymbolEntry<E>* entries = (dyldCacheLocalSymbolEntry<E>*)(&inMemoryCache[localSymbolsOffset+entriesOffset]);
+ for (int i=0; i < entriesCount; ++i) {
+ entries[i].set_dylibOffset(fLocalSymbolInfos[i].dylibOffset);
+ entries[i].set_nlistStartIndex(fLocalSymbolInfos[i].nlistStartIndex);
+ entries[i].set_nlistCount(fLocalSymbolInfos[i].nlistCount);
+ }
+ // copy nlists
+ memcpy(&inMemoryCache[localSymbolsOffset+nlistOffset], &fUnmappedLocalSymbols[0], nlistCount*sizeof(macho_nlist<P>));
+ // copy string pool
+ memcpy(&inMemoryCache[localSymbolsOffset+stringsOffset], fUnmappedLocalsStringPool.getBuffer(), stringsSize);
+
+ // update state
+ fUnmappedLocalSymbolsSize = pageAlign(stringsOffset + stringsSize);
+ cacheFileSize = localSymbolsOffset + fUnmappedLocalSymbolsSize;
+
+ // update header to show location of slidePointers
+ dyldCacheHeader<E>* cacheHeader = (dyldCacheHeader<E>*)inMemoryCache;
+ cacheHeader->set_localSymbolsOffset(localSymbolsOffset);
+ cacheHeader->set_localSymbolsSize(stringsOffset+stringsSize);
+ cacheHeader->set_codeSignatureOffset(cacheFileSize);
+ }
+
+ // compute UUID of whole cache
+ uint8_t digest[16];
+ CC_MD5(inMemoryCache, cacheFileSize, digest);
+ // <rdar://problem/6723729> uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats
+ digest[6] = ( digest[6] & 0x0F ) | ( 3 << 4 );
+ digest[8] = ( digest[8] & 0x3F ) | 0x80;
+ ((dyldCacheHeader<E>*)inMemoryCache)->set_uuid(digest);
if ( fVerify ) {
// if no existing cache, say so
if ( result != 0 )
fprintf(stderr, "update_dyld_shared_cache: warning, close() failed with errno=%d for %s\n", errno, tempCachePath);
+ if ( !iPhoneOS )
+ adhoc_codesign_share_cache(tempCachePath);
+
// <rdar://problem/7901042> Make life easier for the kernel at shutdown.
// If we just move the new cache file over the old, the old file
// may need to exist in the open-unlink state. But because it
// flush everything to disk to assure rename() gets recorded
- ::sync();
+ sync_volume(fCacheFilePath);
didUpdate = true;
// restore default signal handlers
else if ( it->sfm_init_prot == (VM_PROT_EXECUTE|VM_PROT_WRITE|VM_PROT_READ) )
prot = "WX";
if ( it->sfm_size > 1024*1024 )
- fprintf(fmap, "mapping %s %4lluMB 0x%0llX -> 0x%0llX\n", prot, it->sfm_size/(1024*1024),
+ fprintf(fmap, "mapping %s %4lluMB 0x%0llX -> 0x%0llX\n", prot, it->sfm_size/(1024*1024),
it->sfm_address, it->sfm_address+it->sfm_size);
else
- fprintf(fmap, "mapping %s %4lluKB 0x%0llX -> 0x%0llX\n", prot, it->sfm_size/1024,
+ fprintf(fmap, "mapping %s %4lluKB 0x%0llX -> 0x%0llX\n", prot, it->sfm_size/1024,
it->sfm_address, it->sfm_address+it->sfm_size);
}
- fprintf(fmap, "linkedit %4uKB 0x%0llX -> 0x%0llX weak binding info\n",
+ fprintf(fmap, " linkedit %4uKB 0x%0llX -> 0x%0llX weak binding info\n",
(fOffsetOfExportInfoInCombinedLinkedit-fOffsetOfWeakBindInfoInCombinedLinkedit)/1024,
fLinkEditsStartAddress+fOffsetOfWeakBindInfoInCombinedLinkedit,
fLinkEditsStartAddress+fOffsetOfExportInfoInCombinedLinkedit);
- fprintf(fmap, "linkedit %4uKB 0x%0llX -> 0x%0llX export info\n",
+ fprintf(fmap, " linkedit %4uKB 0x%0llX -> 0x%0llX export info\n",
(fOffsetOfBindInfoInCombinedLinkedit-fOffsetOfExportInfoInCombinedLinkedit)/1024,
fLinkEditsStartAddress+fOffsetOfExportInfoInCombinedLinkedit,
fLinkEditsStartAddress+fOffsetOfBindInfoInCombinedLinkedit);
- fprintf(fmap, "linkedit %4uKB 0x%0llX -> 0x%0llX binding info\n",
+ fprintf(fmap, " linkedit %4uKB 0x%0llX -> 0x%0llX binding info\n",
(fOffsetOfLazyBindInfoInCombinedLinkedit-fOffsetOfBindInfoInCombinedLinkedit)/1024,
fLinkEditsStartAddress+fOffsetOfBindInfoInCombinedLinkedit,
fLinkEditsStartAddress+fOffsetOfLazyBindInfoInCombinedLinkedit);
- fprintf(fmap, "linkedit %4uKB 0x%0llX -> 0x%0llX lazy binding info\n",
+ fprintf(fmap, " linkedit %4uKB 0x%0llX -> 0x%0llX lazy binding info\n",
(fOffsetOfOldSymbolTableInfoInCombinedLinkedit-fOffsetOfLazyBindInfoInCombinedLinkedit)/1024,
fLinkEditsStartAddress+fOffsetOfLazyBindInfoInCombinedLinkedit,
fLinkEditsStartAddress+fOffsetOfOldSymbolTableInfoInCombinedLinkedit);
- fprintf(fmap, "linkedit %4uMB 0x%0llX -> 0x%0llX non-dyld symbol table size\n",
+ fprintf(fmap, " linkedit %4uMB 0x%0llX -> 0x%0llX non-dyld symbol table size\n",
(fSizeOfOldSymbolTableInfoInCombinedLinkedit)/(1024*1024),
fLinkEditsStartAddress+fOffsetOfOldSymbolTableInfoInCombinedLinkedit,
fLinkEditsStartAddress+fOffsetOfOldSymbolTableInfoInCombinedLinkedit+fSizeOfOldSymbolTableInfoInCombinedLinkedit);
if ( fSizeOfFunctionStartsInCombinedLinkedit != 0 )
- fprintf(fmap, "linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld functions starts size\n",
+ fprintf(fmap, " linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld functions starts size\n",
fSizeOfFunctionStartsInCombinedLinkedit/1024,
fLinkEditsStartAddress+fOffsetOfFunctionStartsInCombinedLinkedit,
fLinkEditsStartAddress+fOffsetOfFunctionStartsInCombinedLinkedit+fSizeOfFunctionStartsInCombinedLinkedit);
if ( fSizeOfDataInCodeInCombinedLinkedit != 0 )
- fprintf(fmap, "linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld data-in-code info size\n",
+ fprintf(fmap, " linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld data-in-code info size\n",
fSizeOfDataInCodeInCombinedLinkedit/1024,
fLinkEditsStartAddress+fOffsetOfDataInCodeInCombinedLinkedit,
fLinkEditsStartAddress+fOffsetOfDataInCodeInCombinedLinkedit+fSizeOfDataInCodeInCombinedLinkedit);
if ( fSizeOfOldExternalRelocationsInCombinedLinkedit != 0 )
- fprintf(fmap, "linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld external relocs size\n",
+ fprintf(fmap, " linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld external relocs size\n",
fSizeOfOldExternalRelocationsInCombinedLinkedit/1024,
fLinkEditsStartAddress+fOffsetOfOldExternalRelocationsInCombinedLinkedit,
fLinkEditsStartAddress+fOffsetOfOldExternalRelocationsInCombinedLinkedit+fSizeOfOldExternalRelocationsInCombinedLinkedit);
- fprintf(fmap, "linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld indirect symbol table size\n",
+ fprintf(fmap, " linkedit %4uKB 0x%0llX -> 0x%0llX non-dyld indirect symbol table size\n",
fSizeOfOldIndirectSymbolsInCombinedLinkedit/1024,
fLinkEditsStartAddress+fOffsetOfOldIndirectSymbolsInCombinedLinkedit,
fLinkEditsStartAddress+fOffsetOfOldIndirectSymbolsInCombinedLinkedit+fSizeOfOldIndirectSymbolsInCombinedLinkedit);
- fprintf(fmap, "linkedit %4uMB 0x%0llX -> 0x%0llX non-dyld string pool\n",
+ fprintf(fmap, " linkedit %4uMB 0x%0llX -> 0x%0llX non-dyld string pool\n",
(fSizeOfOldStringPoolInCombinedLinkedit)/(1024*1024),
fLinkEditsStartAddress+fOffsetOfOldStringPoolInCombinedLinkedit,
fLinkEditsStartAddress+fOffsetOfOldStringPoolInCombinedLinkedit+fSizeOfOldStringPoolInCombinedLinkedit);
+ fprintf(fmap, "unmapped -- %4uMB local symbol info\n", fUnmappedLocalSymbolsSize/(1024*1024));
+
+ uint64_t endMappingAddr = fMappings[2].sfm_address + fMappings[2].sfm_size;
+ fprintf(fmap, "total map %4lluMB\n", (endMappingAddr - sharedRegionStartAddress())/(1024*1024));
+ if ( sharedRegionStartWritableAddress(0) == 0x7FFF70000000LL ) {
+ // x86_64 has different slide constraints
+ uint64_t freeSpace = 256*1024*1024 - fMappings[1].sfm_size;
+ fprintf(fmap, "r/w space %4lluMB -> %d bits of entropy for ASLR\n\n", freeSpace/(1024*1024), (int)log2(freeSpace/4096));
+ }
+ else {
+ uint64_t freeSpace = sharedRegionStartAddress() + sharedRegionSize() - endMappingAddr;
+ fprintf(fmap, "free space %4lluMB -> %d bits of entropy for ASLR\n\n", freeSpace/(1024*1024), (int)log2(freeSpace/4096));
+ }
+
for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
fprintf(fmap, "%s\n", it->layout->getID().name);
for (std::vector<const char*>::const_iterator ait = it->aliases.begin(); ait != it->aliases.end(); ++ait)
// <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 ) {
- 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");
+ // 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);
static bool updateSharedeCacheFile(const char* rootPath, const char* overlayPath, const char* cacheDir, bool explicitCacheDir, const std::set<ArchPair>& onlyArchs,
- bool force, bool alphaSort, bool optimize, bool deleteExistingFirst, bool verify, bool keepSignatures)
+ bool force, bool alphaSort, bool optimize, bool deleteExistingFirst, bool verify, bool keepSignatures, bool dontMapLocalSymbols)
{
bool didUpdate = false;
// get dyld load address info
case CPU_TYPE_I386:
{
SharedCache<x86> cache(ArchGraph::graphForArchPair(*a), rootPath, overlayPath, cacheDir, explicitCacheDir, alphaSort, verify, optimize, dyldBaseAddress);
- didUpdate |= cache.update(force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
+ 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);
- didUpdate |= cache.update(force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
+ 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);
- didUpdate |= cache.update(force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
+ didUpdate |= cache.update(force, optimize, deleteExistingFirst, index, archCount, keepSignatures, dontMapLocalSymbols);
}
break;
}
bool verify = false;
bool keepSignatures = false;
bool explicitCacheDir = false;
+ bool dontMapLocalSymbols = false;
const char* cacheDir = NULL;
try {
else if ( strcmp(arg, "-no_opt") == 0 ) {
optimize = false;
}
+ else if ( strcmp(arg, "-dont_map_local_symbols") == 0 ) {
+ dontMapLocalSymbols = true;
+ }
else if ( strcmp(arg, "-iPhone") == 0 ) {
iPhoneOS = true;
+ alphaSort = true;
}
else if ( strcmp(arg, "-dylib_list") == 0 ) {
dylibListFile = argv[++i];
onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7F));
else if ( strcmp(arch, "armv7k") == 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
throwf("unknown architecture %s", arch);
}
setSharedDylibs(rootPath, overlayPath, dylibListFile, onlyArchs);
else
scanForSharedDylibs(rootPath, overlayPath, "/var/db/dyld/shared_region_roots/", onlyArchs);
- updateSharedeCacheFile(rootPath, overlayPath, cacheDir, explicitCacheDir, onlyArchs, force, alphaSort, optimize,
- false, verify, keepSignatures);
+ bool didUpdate = updateSharedeCacheFile(rootPath, overlayPath, cacheDir, explicitCacheDir, onlyArchs, force, alphaSort, optimize,
+ false, verify, keepSignatures, dontMapLocalSymbols);
+
+ if ( didUpdate && !iPhoneOS ) {
+ void* handle = dlopen("/usr/lib/libspindump.dylib", RTLD_LAZY);
+ if ( handle != NULL ) {
+ 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;
+ else if ( rootPath[0] != '\0' )
+ nuggetRootPath = rootPath;
+ (*proc)(nuggetRootPath);
+ }
+ dlclose(handle);
+ }
}
catch (const char* msg) {
fprintf(stderr, "update_dyld_shared_cache failed: %s\n", msg);
#define __STDC_LIMIT_MACROS
#include <stdint.h>
+#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <mach/mach.h>
ImageLoader::ImageLoader(const char* path, unsigned int libCount)
: fPath(path), fRealPath(NULL), fDevice(0), fInode(0), fLastModified(0),
- fPathHash(0), fDlopenReferenceCount(0), fStaticReferenceCount(0),
- fDynamicReferenceCount(0), fDynamicReferences(NULL), fInitializerRecursiveLock(NULL),
+ fPathHash(0), fDlopenReferenceCount(0), fInitializerRecursiveLock(NULL),
fDepth(0), fLoadOrder(fgLoadOrdinal++), fState(0), fLibraryCount(libCount),
fAllLibraryChecksumsAndLoadAddressesMatch(false), fLeaveMapped(false), fNeverUnload(false),
fHideSymbols(false), fMatchByInstallName(false),
fInterposed(false), fRegisteredDOF(false), fAllLazyPointersBound(false),
fBeingRemoved(false), fAddFuncNotified(false),
fPathOwnedByImage(false), fIsReferencedDownward(false),
- fIsReferencedUpward(false), fWeakSymbolsBound(false)
+ fWeakSymbolsBound(false)
{
if ( fPath != NULL )
fPathHash = hash(fPath);
+ if ( libCount > 512 )
+ dyld::throwf("too many dependent dylibs in %s", path);
}
void ImageLoader::deleteImage(ImageLoader* image)
{
- // this cannot be done in destructor because libImage() is implemented
- // in a subclass
- DependentLibraryInfo libraryInfos[image->libraryCount()];
- image->doGetDependentLibraries(libraryInfos);
- for(unsigned int i=0; i < image->libraryCount(); ++i) {
- ImageLoader* lib = image->libImage(i);
- if ( (lib != NULL) && ! libraryInfos[i].upward )
- lib->fStaticReferenceCount--;
- }
delete image;
}
delete [] fRealPath;
if ( fPathOwnedByImage && (fPath != NULL) )
delete [] fPath;
- if ( fDynamicReferences != NULL ) {
- for (std::vector<const ImageLoader*>::iterator it = fDynamicReferences->begin(); it != fDynamicReferences->end(); ++it ) {
- const_cast<ImageLoader*>(*it)->fDynamicReferenceCount--;
- }
- delete fDynamicReferences;
- }
}
void ImageLoader::setFileInfo(dev_t device, ino_t inode, time_t modDate)
context.notifySingle(dyld_image_state_mapped, this); // note: can throw exception
}
-void ImageLoader::addDynamicReference(const ImageLoader* target)
-{
- bool alreadyInVector = false;
- if ( fDynamicReferences == NULL ) {
- fDynamicReferences = new std::vector<const ImageLoader*>();
- }
- else {
- for (std::vector<const ImageLoader*>::iterator it = fDynamicReferences->begin(); it != fDynamicReferences->end(); ++it ) {
- if ( *it == target ) {
- alreadyInVector = true;
- break;
- }
- }
- }
- if ( ! alreadyInVector ) {
- fDynamicReferences->push_back(target);
- const_cast<ImageLoader*>(target)->fDynamicReferenceCount++;
- }
- //dyld::log("dyld: addDynamicReference() from %s to %s, fDynamicReferences->size()=%lu\n", this->getPath(), target->getPath(), fDynamicReferences->size());
-}
-
int ImageLoader::compare(const ImageLoader* right) const
{
if ( this->fDepth == right->fDepth ) {
}
+
+bool ImageLoader::dependsOn(ImageLoader* image) {
+ for(unsigned int i=0; i < libraryCount(); ++i) {
+ if ( libImage(i) == image )
+ return true;
+ }
+ return false;
+}
+
+
static bool notInImgageList(const ImageLoader* image, const ImageLoader** dsiStart, const ImageLoader** dsiCur)
{
for (const ImageLoader** p = dsiStart; p < dsiCur; ++p)
this->recursiveApplyInterposing(context);
}
-void ImageLoader::link(const LinkContext& context, bool forceLazysBound, bool preflightOnly, const RPathChain& loaderRPaths)
+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(), fStaticReferenceCount, fNeverUnload);
+ //dyld::log("ImageLoader::link(%s) refCount=%d, neverUnload=%d\n", this->getPath(), fDlopenReferenceCount, fNeverUnload);
// clear error strings
(*context.setErrorStrings)(dyld_error_kind_none, NULL, NULL, NULL);
context.notifyBatch(dyld_image_state_rebased);
uint64_t t3 = mach_absolute_time();
- this->recursiveBind(context, forceLazysBound);
+ this->recursiveBind(context, forceLazysBound, neverUnload);
uint64_t t4 = mach_absolute_time();
- this->weakBind(context);
+ if ( !context.linkingMainExecutable )
+ this->weakBind(context);
uint64_t t5 = mach_absolute_time();
context.notifyBatch(dyld_image_state_bound);
void ImageLoader::printReferenceCounts()
{
- dyld::log(" dlopen=%d, static=%d, dynamic=%d for %s\n",
- fDlopenReferenceCount, fStaticReferenceCount, fDynamicReferenceCount, getPath() );
+ dyld::log(" dlopen=%d for %s\n", fDlopenReferenceCount, getPath() );
}
}
+void ImageLoader::markedUsedRecursive(const std::vector<DynamicReference>& dynamicReferences)
+{
+ // already visited here
+ if ( fMarkedInUse )
+ return;
+ fMarkedInUse = true;
+
+ // clear mark on all statically dependent dylibs
+ for(unsigned int i=0; i < libraryCount(); ++i) {
+ ImageLoader* dependentImage = libImage(i);
+ if ( dependentImage != NULL ) {
+ dependentImage->markedUsedRecursive(dynamicReferences);
+ }
+ }
+
+ // clear mark on all dynamically dependent dylibs
+ for (std::vector<ImageLoader::DynamicReference>::const_iterator it=dynamicReferences.begin(); it != dynamicReferences.end(); ++it) {
+ if ( it->from == this )
+ it->to->markedUsedRecursive(dynamicReferences);
+ }
+
+}
+
unsigned int ImageLoader::recursiveUpdateDepth(unsigned int maxDepth)
{
// the purpose of this phase is to make the images sortable such that
if ( fNeverUnload )
dependentLib->setNeverUnload();
if ( requiredLibInfo.upward ) {
- dependentLib->fIsReferencedUpward = true;
}
else {
- dependentLib->fStaticReferenceCount += 1;
dependentLib->fIsReferencedDownward = true;
}
LibraryInfo actualInfo = dependentLib->doGetLibraryInfo();
-void ImageLoader::recursiveBind(const LinkContext& context, bool forceLazysBound)
+void ImageLoader::recursiveBind(const LinkContext& context, bool forceLazysBound, bool neverUnload)
{
// Normally just non-lazy pointers are bound immediately.
// The exceptions are:
for(unsigned int i=0; i < libraryCount(); ++i) {
ImageLoader* dependentImage = libImage(i);
if ( dependentImage != NULL )
- dependentImage->recursiveBind(context, forceLazysBound);
+ dependentImage->recursiveBind(context, forceLazysBound, neverUnload);
}
// bind this image
this->doBind(context, forceLazysBound);
// mark if lazys are also bound
if ( forceLazysBound || this->usablePrebinding(context) )
fAllLazyPointersBound = true;
+ // mark as never-unload if requested
+ if ( neverUnload )
+ this->setNeverUnload();
context.notifySingle(dyld_image_state_bound, this);
}
{
if ( context.verboseWeakBind )
dyld::log("dyld: weak bind start:\n");
+ uint64_t t1 = mach_absolute_time();
// get set of ImageLoaders that participate in coalecsing
ImageLoader* imagesNeedingCoalescing[fgImagesRequiringCoalescing];
int count = context.getCoalescedImages(imagesNeedingCoalescing);
imagesNeedingCoalescing[i]->fWeakSymbolsBound = true;
}
}
+ uint64_t t2 = mach_absolute_time();
+ fgTotalWeakBindTime += t2 - t1;
+
if ( context.verboseWeakBind )
dyld::log("dyld: weak bind end\n");
}
}
}
+void ImageLoader::setNeverUnloadRecursive() {
+ if ( ! fNeverUnload ) {
+ // break cycles
+ fNeverUnload = true;
+
+ // gather lower level libraries first
+ for(unsigned int i=0; i < libraryCount(); ++i) {
+ ImageLoader* dependentImage = libImage(i);
+ if ( dependentImage != NULL )
+ dependentImage->setNeverUnloadRecursive();
+ }
+ }
+}
void ImageLoader::recursiveSpinLock(recursive_lock& rlock)
{
// 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) {
}
+VECTOR_NEVER_DESTRUCTED_IMPL(ImageLoader::InterposeTuple);
+VECTOR_NEVER_DESTRUCTED_IMPL(ImagePair);
+
#include <sys/types.h>
#include <unistd.h>
+#include <stdlib.h>
#include <mach/mach_time.h> // struct mach_timebase_info
#include <mach/mach_init.h> // struct mach_thread_self
#include <mach/shared_region.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <stdint.h>
+#include <stdlib.h>
+#include <TargetConditionals.h>
#include <vector>
#include <new>
-#if (__i386__ || __x86_64__)
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
#include <CrashReporterClient.h>
#else
// work around until iOS has CrashReporterClient.h
};
#endif
-#define SPLIT_SEG_SHARED_REGION_SUPPORT __arm__
-#define SPLIT_SEG_DYLIB_SUPPORT (__i386__ || __arm__)
-#define PREBOUND_IMAGE_SUPPORT (__i386__ || __arm__)
-#define TEXT_RELOC_SUPPORT (__i386__ || __arm__)
-#define DYLD_SHARED_CACHE_SUPPORT (__i386__ || __x86_64__ || __arm__)
-#define SUPPORT_OLD_CRT_INITIALIZATION (__i386__)
-#define SUPPORT_LC_DYLD_ENVIRONMENT (__i386__ || __x86_64__)
-#define SUPPORT_VERSIONED_PATHS (__i386__ || __x86_64__)
-#if __IPHONE_OS_VERSION_MIN_REQUIRED
- #define CORESYMBOLICATION_SUPPORT 1
+#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 TEXT_RELOC_SUPPORT __i386__
+ #define DYLD_SHARED_CACHE_SUPPORT __arm__
+ #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 INITIAL_IMAGE_COUNT 256
#else
- #define CORESYMBOLICATION_SUPPORT (__i386__ || __x86_64__)
-#endif
-#if __arm__
- #define INITIAL_IMAGE_COUNT 256
-#else
- #define INITIAL_IMAGE_COUNT 200
+ #define SPLIT_SEG_SHARED_REGION_SUPPORT 0
+ #define SPLIT_SEG_DYLIB_SUPPORT __i386__
+ #define PREBOUND_IMAGE_SUPPORT __i386__
+ #define TEXT_RELOC_SUPPORT __i386__
+ #define DYLD_SHARED_CACHE_SUPPORT 1
+ #define SUPPORT_OLD_CRT_INITIALIZATION __i386__
+ #define SUPPORT_LC_DYLD_ENVIRONMENT (__i386__ || __x86_64__)
+ #define SUPPORT_VERSIONED_PATHS 1
+ #define SUPPORT_CLASSIC_MACHO 1
+ #define CORESYMBOLICATION_SUPPORT 1
+ #define INITIAL_IMAGE_COUNT 200
#endif
-#define CODESIGNING_SUPPORT __arm__
+
+
+// <rdar://problem/13590567> optimize away dyld's initializers
+#define VECTOR_NEVER_DESTRUCTED(type) \
+ namespace std { \
+ template <> \
+ __vector_base<type, std::allocator<type> >::~__vector_base() { } \
+ }
+#define VECTOR_NEVER_DESTRUCTED_EXTERN(type) \
+ namespace std { \
+ template <> \
+ __vector_base<type, std::allocator<type> >::~__vector_base(); \
+ }
+#define VECTOR_NEVER_DESTRUCTED_IMPL(type) \
+ namespace std { \
+ template <> \
+ __vector_base<type, std::allocator<type> >::~__vector_base() { } \
+ }
// utilities
namespace dyld {
#if LOG_BINDINGS
extern void logBindings(const char* format, ...) __attribute__((format(printf, 1, 2)));
#endif
-};
+}
+extern "C" int vm_alloc(vm_address_t* addr, vm_size_t size, uint32_t flags);
+extern "C" void* xmmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset);
#if __LP64__
const char* imageShortName;
};
+ struct DynamicReference {
+ ImageLoader* from;
+ ImageLoader* to;
+ };
+
struct LinkContext {
ImageLoader* (*loadLibrary)(const char* libraryName, bool search, const char* origin, const RPathChain* rpaths);
void (*terminationRecorder)(ImageLoader* image);
bool (*inSharedCache)(const char* path);
void (*setErrorStrings)(unsigned errorCode, const char* errorClientOfDylibPath,
const char* errorTargetDylibPath, const char* errorSymbol);
+ ImageLoader* (*findImageContainingAddress)(const void* addr);
+ void (*addDynamicReference)(ImageLoader* from, ImageLoader* to);
+
#if SUPPORT_OLD_CRT_INITIALIZATION
void (*setRunInitialzersOldWay)();
#endif
const char** rootPaths;
PrebindMode prebindUsage;
SharedRegionMode sharedRegionMode;
- bool dyldLoadedAtSameAddressNeededBySharedCache;
+ bool dyldLoadedAtSameAddressNeededBySharedCache;
+ bool codeSigningEnforced;
+ bool mainExecutableCodeSigned;
bool preFetchDisabled;
bool prebinding;
bool bindFlat;
bool verboseWarnings;
bool verboseRPaths;
bool verboseInterposing;
+ bool verboseCodeSignatures;
};
struct CoalIterator
// link() takes a newly instantiated ImageLoader and does all
// fixups needed to make it usable by the process
- void link(const LinkContext& context, bool forceLazysBound, bool preflight, const RPathChain& loaderRPaths);
+ void link(const LinkContext& context, bool forceLazysBound, bool preflight, bool neverUnload, const RPathChain& loaderRPaths);
// runInitializers() is normally called in link() but the main executable must
// run crt code before initializers
virtual uintptr_t segActualEndAddress(unsigned int) const = 0;
+ virtual uint32_t sdkVersion() const = 0;
+
// if the image contains interposing functions, register them
virtual void registerInterposing() = 0;
// when resolving symbols look in subImage if symbol can't be found
void reExport(ImageLoader* subImage);
+ void weakBind(const LinkContext& context);
+
void applyInterposing(const LinkContext& context);
dyld_image_states getState() { return (dyld_image_states)fState; }
void printReferenceCounts();
- uint32_t referenceCount() const { return fDlopenReferenceCount + fStaticReferenceCount + fDynamicReferenceCount; }
+ uint32_t dlopenCount() const { return fDlopenReferenceCount; }
+
+ void setCanUnload() { fNeverUnload = false; fLeaveMapped = false; }
bool neverUnload() const { return fNeverUnload; }
void setNeverUnload() { fNeverUnload = true; fLeaveMapped = true; }
+ void setNeverUnloadRecursive();
bool isReferencedDownward() { return fIsReferencedDownward; }
- bool isReferencedUpward() { return fIsReferencedUpward; }
// triggered by DYLD_PRINT_STATISTICS to write info on work done and how fast
static void printStatistics(unsigned int imageCount, const InitializerTimingList& timingInfo);
// used instead of directly deleting image
static void deleteImage(ImageLoader*);
- void setPath(const char* path);
+ bool dependsOn(ImageLoader* image);
+
+ void setPath(const char* path);
void setPaths(const char* path, const char* realPath);
void setPathUnowned(const char* path);
void setBeingRemoved() { fBeingRemoved = true; }
bool isBeingRemoved() const { return fBeingRemoved; }
+ void markNotUsed() { fMarkedInUse = false; }
+ void markedUsedRecursive(const std::vector<DynamicReference>&);
+ bool isMarkedInUse() const { return fMarkedInUse; }
+
void setAddFuncNotified() { fAddFuncNotified = true; }
bool addFuncNotified() const { return fAddFuncNotified; }
+ struct InterposeTuple {
+ uintptr_t replacement;
+ ImageLoader* replacementImage; // don't apply replacement to this image
+ uintptr_t replacee;
+ };
+
protected:
// abstract base class so all constructors protected
ImageLoader(const char* path, unsigned int libCount);
ImageLoader(const ImageLoader&);
void operator=(const ImageLoader&);
- void operator delete(void* image) throw() { free(image); }
+ void operator delete(void* image) throw() { ::free(image); }
struct LibraryInfo {
};
- struct InterposeTuple {
- uintptr_t replacement;
- ImageLoader* replacementImage; // don't apply replacement to this image
- uintptr_t replacee;
- };
-
typedef void (*Initializer)(int argc, const char* argv[], const char* envp[], const char* apple[], const ProgramVars* vars);
typedef void (*Terminator)(void);
virtual bool libIsUpward(unsigned int) const = 0;
virtual void setLibImage(unsigned int, ImageLoader*, bool, bool) = 0;
-
// To link() an image, its dependent libraries are loaded, it is rebased, bound, and initialized.
// These methods do the above, exactly once, and it the right order
void recursiveLoadLibraries(const LinkContext& context, bool preflightOnly, const RPathChain& loaderRPaths);
unsigned int recursiveUpdateDepth(unsigned int maxDepth);
void recursiveValidate(const LinkContext& context);
void recursiveRebase(const LinkContext& context);
- void recursiveBind(const LinkContext& context, bool forceLazysBound);
- void weakBind(const LinkContext& context);
+ 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&);
// set fState to dyld_image_state_memory_mapped
void setMapped(const LinkContext& context);
-
- // mark that target should not be unloaded unless this is also unloaded
- void addDynamicReference(const ImageLoader* target);
-
+
void setFileInfo(dev_t device, ino_t inode, time_t modDate);
static uintptr_t fgNextPIEDylibAddress;
static uint64_t fgTotalDOF;
static uint64_t fgTotalInitTime;
static std::vector<InterposeTuple> fgInterposingTuples;
+
const char* fPath;
const char* fRealPath;
dev_t fDevice;
time_t fLastModified;
uint32_t fPathHash;
uint32_t fDlopenReferenceCount; // count of how many dlopens have been done on this image
- uint32_t fStaticReferenceCount; // count of images that have a fLibraries entry pointing to this image
- uint32_t fDynamicReferenceCount; // count of images that have a fDynamicReferences entry pointer to this image
- std::vector<const ImageLoader*>* fDynamicReferences; // list of all images this image used because of a flat/coalesced lookup
private:
struct recursive_lock {
fInterposed : 1,
fRegisteredDOF : 1,
fAllLazyPointersBound : 1,
+ fMarkedInUse : 1,
fBeingRemoved : 1,
fAddFuncNotified : 1,
fPathOwnedByImage : 1,
fIsReferencedDownward : 1,
- fIsReferencedUpward : 1,
fWeakSymbolsBound : 1;
static uint16_t fgLoadOrdinal;
};
+VECTOR_NEVER_DESTRUCTED_EXTERN(ImageLoader::InterposeTuple);
#endif
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <sys/sysctl.h>
+#include <sys/syscall.h>
#include <libkern/OSAtomic.h>
#include <libkern/OSCacheControl.h>
#include <stdint.h>
+#include <System/sys/codesign.h>
#include "ImageLoaderMachO.h"
#include "ImageLoaderMachOCompressed.h"
+#if SUPPORT_CLASSIC_MACHO
#include "ImageLoaderMachOClassic.h"
+#endif
#include "mach-o/dyld_images.h"
// <rdar://problem/8718137> use stack guard random value to add padding between dylibs
#if __LP64__
#define LC_SEGMENT_COMMAND LC_SEGMENT_64
#define LC_ROUTINES_COMMAND LC_ROUTINES_64
+ #define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT
struct macho_segment_command : public segment_command_64 {};
struct macho_section : public section_64 {};
struct macho_routines_command : public routines_command_64 {};
#else
#define LC_SEGMENT_COMMAND LC_SEGMENT
#define LC_ROUTINES_COMMAND LC_ROUTINES
+ #define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT_64
struct macho_segment_command : public segment_command {};
struct macho_section : public section {};
struct macho_routines_command : public routines_command {};
// determine if this mach-o file has classic or compressed LINKEDIT and number of segments it has
void ImageLoaderMachO::sniffLoadCommands(const macho_header* mh, const char* path, bool* compressed,
- unsigned int* segCount, unsigned int* libCount,
+ unsigned int* segCount, unsigned int* libCount, const LinkContext& context,
const linkedit_data_command** codeSigCmd)
{
*compressed = false;
*libCount = 0;
*codeSigCmd = NULL;
struct macho_segment_command* segCmd;
-#if CODESIGNING_SUPPORT
bool foundLoadCommandSegment = false;
-#endif
+ uint32_t loadCommandSegmentIndex = 0xFFFFFFFF;
+ uintptr_t loadCommandSegmentVMStart = 0;
+ uintptr_t loadCommandSegmentVMEnd = 0;
+
const uint32_t cmd_count = mh->ncmds;
const struct load_command* const startCmds = (struct load_command*)(((uint8_t*)mh) + sizeof(macho_header));
const struct load_command* const endCmds = (struct load_command*)(((uint8_t*)mh) + sizeof(macho_header) + mh->sizeofcmds);
// ignore zero-sized segments
if ( segCmd->vmsize != 0 )
*segCount += 1;
-#if CODESIGNING_SUPPORT
// <rdar://problem/7942521> all load commands must be in an executable segment
- if ( (segCmd->fileoff < mh->sizeofcmds) && (segCmd->filesize != 0) ) {
+ if ( context.codeSigningEnforced && (segCmd->fileoff < mh->sizeofcmds) && (segCmd->filesize != 0) ) {
if ( (segCmd->fileoff != 0) || (segCmd->filesize < (mh->sizeofcmds+sizeof(macho_header))) )
dyld::throwf("malformed mach-o image: segment %s does not span all load commands", segCmd->segname);
if ( segCmd->initprot != (VM_PROT_READ | VM_PROT_EXECUTE) )
dyld::throwf("malformed mach-o image: load commands found in segment %s with wrong permissions", segCmd->segname);
+ if ( foundLoadCommandSegment )
+ throw "load commands in multiple segments";
foundLoadCommandSegment = true;
+ loadCommandSegmentIndex = i;
+ loadCommandSegmentVMStart = segCmd->vmaddr;
+ loadCommandSegmentVMEnd = segCmd->vmaddr + segCmd->vmsize;
}
-#endif
+ break;
+ case LC_SEGMENT_COMMAND_WRONG:
+ dyld::throwf("malformed mach-o image: wrong LC_SEGMENT[_64] for architecture");
break;
case LC_LOAD_DYLIB:
case LC_LOAD_WEAK_DYLIB:
}
}
-#if CODESIGNING_SUPPORT
- if ( ! foundLoadCommandSegment )
+ if ( context.codeSigningEnforced && !foundLoadCommandSegment )
throw "load commands not in a segment";
-#endif
-
+ // <rdar://problem/13145644> verify another segment does not over-map load commands
+ cmd = startCmds;
+ if ( context.codeSigningEnforced ) {
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ switch (cmd->cmd) {
+ case LC_SEGMENT_COMMAND:
+ if ( i != loadCommandSegmentIndex ) {
+ segCmd = (struct macho_segment_command*)cmd;
+ uintptr_t start = segCmd->vmaddr;
+ uintptr_t end = segCmd->vmaddr + segCmd->vmsize;
+ if ( ((start <= loadCommandSegmentVMStart) && (end > loadCommandSegmentVMStart))
+ || ((start >= loadCommandSegmentVMStart) && (start < loadCommandSegmentVMEnd)) )
+ dyld::throwf("malformed mach-o image: segment %s overlaps load commands", segCmd->segname);
+ }
+ break;
+ }
+ cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+ }
+ }
+
// fSegmentsArrayCount is only 8-bits
if ( *segCount > 255 )
dyld::throwf("malformed mach-o image: more than 255 segments in %s", path);
unsigned int segCount;
unsigned int libCount;
const linkedit_data_command* codeSigCmd;
- sniffLoadCommands(mh, path, &compressed, &segCount, &libCount, &codeSigCmd);
+ sniffLoadCommands(mh, path, &compressed, &segCount, &libCount, context, &codeSigCmd);
// instantiate concrete class based on content of load commands
if ( compressed )
return ImageLoaderMachOCompressed::instantiateMainExecutable(mh, slide, path, segCount, libCount, context);
else
+#if SUPPORT_CLASSIC_MACHO
return ImageLoaderMachOClassic::instantiateMainExecutable(mh, slide, path, segCount, libCount, context);
+#else
+ throw "missing LC_DYLD_INFO load command";
+#endif
}
unsigned int segCount;
unsigned int libCount;
const linkedit_data_command* codeSigCmd;
- sniffLoadCommands((const macho_header*)fileData, path, &compressed, &segCount, &libCount, &codeSigCmd);
+ sniffLoadCommands((const macho_header*)fileData, path, &compressed, &segCount, &libCount, context, &codeSigCmd);
// instantiate concrete class based on content of load commands
if ( compressed )
return ImageLoaderMachOCompressed::instantiateFromFile(path, fd, fileData, offsetInFat, lenInFat, info, segCount, libCount, codeSigCmd, context);
else
+#if SUPPORT_CLASSIC_MACHO
return ImageLoaderMachOClassic::instantiateFromFile(path, fd, fileData, offsetInFat, lenInFat, info, segCount, libCount, codeSigCmd, context);
+#else
+ throw "missing LC_DYLD_INFO load command";
+#endif
}
// create image by using cached mach-o file
unsigned int segCount;
unsigned int libCount;
const linkedit_data_command* codeSigCmd;
- sniffLoadCommands(mh, path, &compressed, &segCount, &libCount, &codeSigCmd);
+ sniffLoadCommands(mh, path, &compressed, &segCount, &libCount, context, &codeSigCmd);
// instantiate concrete class based on content of load commands
if ( compressed )
return ImageLoaderMachOCompressed::instantiateFromCache(mh, path, slide, info, segCount, libCount, context);
else
+#if SUPPORT_CLASSIC_MACHO
return ImageLoaderMachOClassic::instantiateFromCache(mh, path, slide, info, segCount, libCount, context);
+#else
+ throw "missing LC_DYLD_INFO load command";
+#endif
}
// create image by copying an in-memory mach-o file
unsigned int segCount;
unsigned int libCount;
const linkedit_data_command* sigcmd;
- sniffLoadCommands(mh, moduleName, &compressed, &segCount, &libCount, &sigcmd);
+ sniffLoadCommands(mh, moduleName, &compressed, &segCount, &libCount, context, &sigcmd);
// instantiate concrete class based on content of load commands
if ( compressed )
return ImageLoaderMachOCompressed::instantiateFromMemory(moduleName, mh, len, segCount, libCount, context);
else
+#if SUPPORT_CLASSIC_MACHO
return ImageLoaderMachOClassic::instantiateFromMemory(moduleName, mh, len, segCount, libCount, context);
+#else
+ throw "missing LC_DYLD_INFO load command";
+#endif
}
+int ImageLoaderMachO::crashIfInvalidCodeSignature()
+{
+ // Now that segments are mapped in, try reading from first executable segment.
+ // If code signing is enabled the kernel will validate the code signature
+ // when paging in, and kill the process if invalid.
+ for(unsigned int i=0; i < fSegmentsCount; ++i) {
+ if ( (segFileOffset(i) == 0) && (segFileSize(i) != 0) ) {
+ // return read value to ensure compiler does not optimize away load
+ int* p = (int*)segActualLoadAddress(i);
+ return *p;
+ }
+ }
+ return 0;
+}
+
void ImageLoaderMachO::parseLoadCmds()
{
fSlide = slide;
}
-#if CODESIGNING_SUPPORT
-void ImageLoaderMachO::loadCodeSignature(const struct linkedit_data_command* codeSigCmd, int fd, uint64_t offsetInFatFile)
+void ImageLoaderMachO::loadCodeSignature(const struct linkedit_data_command* codeSigCmd, int fd, uint64_t offsetInFatFile, const LinkContext& context)
{
- fsignatures_t siginfo;
- siginfo.fs_file_start=offsetInFatFile; // start of mach-o slice in fat file
- siginfo.fs_blob_start=(void*)(codeSigCmd->dataoff); // start of CD in mach-o file
- siginfo.fs_blob_size=codeSigCmd->datasize; // size of CD
- int result = fcntl(fd, F_ADDFILESIGS, &siginfo);
- if ( result == -1 )
- dyld::log("dyld: F_ADDFILESIGS failed for %s with errno=%d\n", this->getPath(), errno);
- //dyld::log("dyld: registered code signature for %s\n", this->getPath());
-}
+ // if dylib being loaded has no code signature load command
+ if ( codeSigCmd == NULL ) {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+ bool codeSigningEnforced = context.codeSigningEnforced;
+ if ( context.mainExecutableCodeSigned && !codeSigningEnforced ) {
+ static bool codeSignEnforcementDynamicallyEnabled = false;
+ if ( !codeSignEnforcementDynamicallyEnabled ) {
+ uint32_t flags;
+ if ( csops(0, CS_OPS_STATUS, &flags, sizeof(flags)) != -1 ) {
+ if ( flags & CS_ENFORCEMENT ) {
+ codeSignEnforcementDynamicallyEnabled = true;
+ }
+ }
+ }
+ codeSigningEnforced = codeSignEnforcementDynamicallyEnabled;
+ }
+ // if we require dylibs to be code signed
+ if ( codeSigningEnforced ) {
+ // if there is a non-load command based code signature, use it
+ off_t offset = (off_t)offsetInFatFile;
+ if ( fcntl(fd, F_FINDSIGS, &offset, sizeof(offset)) != -1 )
+ return;
+ // otherwise gracefully return from dlopen()
+ dyld::throwf("required code signature missing for '%s'\n", this->getPath());
+ }
#endif
+ }
+ else {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+ // <rdar://problem/13622786> ignore code signatures in binaries built with pre-10.9 tools
+ if ( this->sdkVersion() < DYLD_MACOSX_VERSION_10_9 ) {
+ return;
+ }
+#endif
+ fsignatures_t siginfo;
+ siginfo.fs_file_start=offsetInFatFile; // start of mach-o slice in fat file
+ siginfo.fs_blob_start=(void*)(long)(codeSigCmd->dataoff); // start of CD in mach-o file
+ siginfo.fs_blob_size=codeSigCmd->datasize; // size of CD
+ int result = fcntl(fd, F_ADDFILESIGS, &siginfo);
+ if ( result == -1 ) {
+ if ( (errno == EPERM) || (errno == EBADEXEC) )
+ dyld::throwf("code signature invalid for '%s'\n", this->getPath());
+ if ( context.verboseCodeSignatures )
+ dyld::log("dyld: Failed registering code signature for %s, errno=%d\n", this->getPath(), errno);
+ else
+ dyld::log("dyld: Registered code signature for %s\n", this->getPath());
+ }
+ }
+}
const char* ImageLoaderMachO::getInstallPath() const
}
}
+uint32_t ImageLoaderMachO::sdkVersion() const
+{
+ 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;
+ 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->sdk;
+ }
+ cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+ }
+ return 0;
+}
+
void* ImageLoaderMachO::getThreadPC() const
{
const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
bool found = false;
for(const char** rp = context.rootPaths; *rp != NULL; ++rp) {
char newPath[PATH_MAX];
- strcpy(newPath, *rp);
- strcat(newPath, path);
+ strlcpy(newPath, *rp, PATH_MAX);
+ strlcat(newPath, path, PATH_MAX);
struct stat stat_buf;
if ( stat(newPath, &stat_buf) != -1 ) {
//dyld::log("combined DYLD_ROOT_PATH and LC_RPATH: %s\n", newPath);
segMakeWritable(textSegmentIndex, context);
}
else {
- // iPhoneOS requires range to be invalidated before it is made executable
+ #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);
}
}
uintptr_t ImageLoaderMachO::getSymbolAddress(const Symbol* sym, const ImageLoader* requestor,
const LinkContext& context, bool runResolver) const
{
- uintptr_t result = exportedSymbolAddress(context, sym, runResolver);
+ 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'
dyld::throwf("initializer function %p not in mapped image for %s\n", func, this->getPath());
}
if ( context.verboseInit )
- dyld::log("dyld: calling -init function 0x%p in %s\n", func, this->getPath());
+ dyld::log("dyld: calling -init function %p in %s\n", func, this->getPath());
func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
break;
}
// add small (0-3 pages) random padding between dylibs
addr = fgNextPIEDylibAddress + (__stack_chk_guard/fgNextPIEDylibAddress & (sizeof(long)-1))*4096;
//dyld::log("padding 0x%08llX, guard=0x%08llX\n", (long long)(addr - fgNextPIEDylibAddress), (long long)(__stack_chk_guard));
- kern_return_t r = vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_FIXED);
+ kern_return_t r = vm_alloc(&addr, size, VM_FLAGS_FIXED | VM_MAKE_TAG(VM_MEMORY_DYLIB));
if ( r == KERN_SUCCESS ) {
fgNextPIEDylibAddress = addr + size;
return addr;
}
fgNextPIEDylibAddress = 0;
}
- kern_return_t r = vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE);
+ kern_return_t r = vm_alloc(&addr, size, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_DYLIB));
if ( r != KERN_SUCCESS )
throw "out of address space";
{
vm_address_t addr = start;
vm_size_t size = length;
- kern_return_t r = vm_allocate(mach_task_self(), &addr, size, false /*only this range*/);
+ kern_return_t r = vm_alloc(&addr, size, VM_FLAGS_FIXED | VM_MAKE_TAG(VM_MEMORY_DYLIB));
if ( r != KERN_SUCCESS )
return false;
return true;
dyld::throwf("truncated mach-o error: segment %s extends to %llu which is past end of file %llu",
segName(i), (uint64_t)(fileOffset+size), fileLen);
}
- void* loadAddress = mmap((void*)requestedLoadAddress, size, protection, MAP_FIXED | MAP_PRIVATE, fd, fileOffset);
+ void* loadAddress = xmmap((void*)requestedLoadAddress, size, protection, MAP_FIXED | MAP_PRIVATE, fd, fileOffset);
if ( loadAddress == ((void*)(-1)) ) {
dyld::throwf("mmap() error %d at address=0x%08lX, size=0x%08lX segment=%s in Segment::map() mapping %s",
errno, requestedLoadAddress, (uintptr_t)size, segName(i), getPath());
virtual uintptr_t segPreferredLoadAddress(unsigned int) const;
virtual uintptr_t segActualEndAddress(unsigned int) const;
virtual void registerInterposing();
+ virtual uint32_t sdkVersion() const;
static void printStatistics(unsigned int imageCount, const InitializerTimingList&);
virtual void rebase(const LinkContext& context) = 0;
virtual const ImageLoader::Symbol* findExportedSymbol(const char* name, const ImageLoader** foundIn) const = 0;
virtual bool containsSymbol(const void* addr) const = 0;
- virtual uintptr_t exportedSymbolAddress(const LinkContext& context, const Symbol* symbol, bool runResolver) const = 0;
+ virtual uintptr_t exportedSymbolAddress(const LinkContext& context, const Symbol* symbol, const ImageLoader* requestor, bool runResolver) const = 0;
virtual bool exportedSymbolIsWeakDefintion(const Symbol* symbol) const = 0;
virtual const char* exportedSymbolName(const Symbol* symbol) const = 0;
virtual unsigned int exportedSymbolCount() const = 0;
void destroy();
static void sniffLoadCommands(const macho_header* mh, const char* path, bool* compressed,
- unsigned int* segCount, unsigned int* libCount,
+ unsigned int* segCount, unsigned int* libCount, const LinkContext& context,
const linkedit_data_command** codeSigCmd);
static bool needsAddedLibSystemDepency(unsigned int libCount, const macho_header* mh);
-#if CODESIGNING_SUPPORT
- void loadCodeSignature(const struct linkedit_data_command* codeSigCmd, int fd, uint64_t offsetInFatFile);
-#endif
+ void loadCodeSignature(const struct linkedit_data_command* codeSigCmd, int fd, uint64_t offsetInFatFile, const LinkContext& context);
const struct macho_segment_command* segLoadCommand(unsigned int segIndex) const;
void parseLoadCmds();
+ int crashIfInvalidCodeSignature();
bool segHasRebaseFixUps(unsigned int) const;
bool segHasBindFixUps(unsigned int) const;
void segProtect(unsigned int segIndex, const ImageLoader::LinkContext& context);
// record info about file
image->setFileInfo(info.st_dev, info.st_ino, info.st_mtime);
- #if CODESIGNING_SUPPORT
// if this image is code signed, let kernel validate signature before mapping any pages from image
- if ( codeSigCmd != NULL )
- image->loadCodeSignature(codeSigCmd, fd, offsetInFat);
- #endif
+ image->loadCodeSignature(codeSigCmd, fd, offsetInFat, context);
// mmap segments
image->mapSegmentsClassic(fd, offsetInFat, lenInFat, info.st_size, context);
}
-uintptr_t ImageLoaderMachOClassic::exportedSymbolAddress(const LinkContext& context, const Symbol* symbol, bool runResolver) const
+uintptr_t ImageLoaderMachOClassic::exportedSymbolAddress(const LinkContext& context, const Symbol* symbol, const ImageLoader* requestor, bool runResolver) const
{
const struct macho_nlist* sym = (macho_nlist*)symbol;
uintptr_t result = sym->n_value + fSlide;
}
const Symbol* sym;
if ( context.flatExportFinder(symbolName, &sym, foundIn) ) {
- if ( (*foundIn != this) && !(*foundIn)->neverUnload() )
- this->addDynamicReference(*foundIn);
+ if ( *foundIn != this )
+ context.addDynamicReference(this, const_cast<ImageLoader*>(*foundIn));
return (*foundIn)->getExportedSymbolAddress(sym, context, this);
}
// if a bundle is loaded privately the above will not find its exports
if ( !context.prebinding && !dontCoalesce && (symbolIsWeakReference(undefinedSymbol) || symbolIsWeakDefinition(undefinedSymbol)) ) {
const Symbol* sym;
if ( context.coalescedExportFinder(symbolName, &sym, foundIn) ) {
- if ( (*foundIn != this) && !(*foundIn)->neverUnload() )
- this->addDynamicReference(*foundIn);
+ if ( *foundIn != this )
+ context.addDynamicReference(this, const_cast<ImageLoader*>(*foundIn));
return (*foundIn)->getExportedSymbolAddress(sym, context, this);
}
//throwSymbolNotFound(context, symbolName, this->getPath(), "coalesced namespace");
}
cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
}
- if ( boundSomething && (targetImage != this) && !targetImage->neverUnload() )
- this->addDynamicReference(targetImage);
+ if ( boundSomething && (targetImage != this) ) {
+ context.addDynamicReference(this, targetImage);
+ }
// mark that this symbol has already been bound, so we don't try to bind again
it.type = 1;
virtual void rebase(const LinkContext& context);
virtual const ImageLoader::Symbol* findExportedSymbol(const char* name, const ImageLoader** foundIn) const;
virtual bool containsSymbol(const void* addr) const;
- virtual uintptr_t exportedSymbolAddress(const LinkContext& context, const Symbol* symbol, bool runResolver) const;
+ virtual uintptr_t exportedSymbolAddress(const LinkContext& context, const Symbol* symbol, const ImageLoader* requestor, bool runResolver) const;
virtual bool exportedSymbolIsWeakDefintion(const Symbol* symbol) const;
virtual const char* exportedSymbolName(const Symbol* symbol) const;
virtual unsigned int exportedSymbolCount() const;
#include "ImageLoaderMachOCompressed.h"
#include "mach-o/dyld_images.h"
+#ifndef EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
+ #define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02
+#endif
// relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables
#if __LP64__
if ( slide != 0 )
fgNextPIEDylibAddress = (uintptr_t)image->getEnd();
- image->setNeverUnload();
image->instantiateFinish(context);
image->setMapped(context);
// record info about file
image->setFileInfo(info.st_dev, info.st_ino, info.st_mtime);
- #if CODESIGNING_SUPPORT
// if this image is code signed, let kernel validate signature before mapping any pages from image
- if ( codeSigCmd != NULL )
- image->loadCodeSignature(codeSigCmd, fd, offsetInFat);
- #endif
+ image->loadCodeSignature(codeSigCmd, fd, offsetInFat, context);
// mmap segments
image->mapSegments(fd, offsetInFat, lenInFat, info.st_size, context);
+ // probe to see if code signed correctly
+ image->crashIfInvalidCodeSignature();
+
// finish construction
image->instantiateFinish(context);
}
-uintptr_t ImageLoaderMachOCompressed::exportedSymbolAddress(const LinkContext& context, const Symbol* symbol, bool runResolver) const
+uintptr_t ImageLoaderMachOCompressed::exportedSymbolAddress(const LinkContext& context, const Symbol* symbol, const ImageLoader* requestor, bool runResolver) const
{
const uint8_t* exportNode = (uint8_t*)symbol;
const uint8_t* exportTrieStart = fLinkEditBase + fDyldInfo->export_off;
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);
- if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == 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 ) {
- if ( context.verboseInterposing ) {
- dyld::log("dyld interposing: lazy replace 0x%lX with 0x%lX from %s\n",
- it->replacee, it->replacement, this->getPath());
+ 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;
}
- return it->replacement;
}
+ typedef uintptr_t (*ResolverProc)(void);
+ ResolverProc resolver = (ResolverProc)(read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)fMachOData);
+ uintptr_t result = (*resolver)();
+ if ( context.verboseBind )
+ dyld::log("dyld: resolver at %p returned 0x%08lX\n", resolver, result);
+ return result;
}
- typedef uintptr_t (*ResolverProc)(void);
- ResolverProc resolver = (ResolverProc)(read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)fMachOData);
- uintptr_t result = (*resolver)();
- if ( context.verboseBind )
- dyld::log("dyld: resolver at %p returned 0x%08lX\n", resolver, result);
- return result;
- }
- return read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)fMachOData;
- }
- else if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL ) {
- if ( flags & EXPORT_SYMBOL_FLAGS_STUB_AND_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);
+ 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);
+ return read_uleb128(exportNode, exportTrieEnd);
+ default:
dyld::throwf("unsupported exported symbol kind. flags=%d at node=%p", flags, symbol);
- return read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)fMachOData;
}
- else
- dyld::throwf("unsupported exported symbol kind. flags=%d at node=%p", flags, symbol);
}
bool ImageLoaderMachOCompressed::exportedSymbolIsWeakDefintion(const Symbol* symbol) const
{
const Symbol* sym;
if ( context.flatExportFinder(symbolName, &sym, foundIn) ) {
- if ( (*foundIn != this) && !(*foundIn)->neverUnload() )
- this->addDynamicReference(*foundIn);
+ if ( *foundIn != this )
+ context.addDynamicReference(this, const_cast<ImageLoader*>(*foundIn));
return (*foundIn)->getExportedSymbolAddress(sym, context, this, runResolver);
}
// if a bundle is loaded privately the above will not find its exports
case BIND_OPCODE_DO_BIND:
if ( address >= segmentEndAddress )
throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
- (this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "lazy forced", NULL, true);
+ (this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "forced lazy ", NULL, false);
address += sizeof(intptr_t);
break;
case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
}
break;
default:
- dyld::throwf("bad weak bind opcode %d", *p);
+ dyld::throwf("bad weak bind opcode '%d' found after processing %d bytes in '%s'", *p, (int)(p-start), this->getPath());
}
}
/// hmmm, BIND_OPCODE_DONE is missing...
default:
dyld::throwf("bad bind opcode %d in weak binding info", *p);
}
- }
- if ( boundSomething && (targetImage != this) && !targetImage->neverUnload() )
- this->addDynamicReference(targetImage);
+ }
+ // C++ weak coalescing cannot be tracked by reference counting. Error on side of never unloading.
+ if ( boundSomething && (targetImage != this) )
+ context.addDynamicReference(this, targetImage);
}
uintptr_t ImageLoaderMachOCompressed::interposeAt(const LinkContext& context, uintptr_t addr, uint8_t type, const char*,
#if __arm__ || __x86_64__
-void ImageLoaderMachOCompressed::updateAlternateLazyPointer(uint8_t* stub, void** originalLazyPointerAddr)
+void ImageLoaderMachOCompressed::updateAlternateLazyPointer(uint8_t* stub, void** originalLazyPointerAddr, const LinkContext& context)
{
#if __arm__
uint32_t* instructions = (uint32_t*)stub;
// if stub does not use original lazy pointer (meaning it was optimized by update_dyld_shared_cache)
if ( lazyPointerAddr != originalLazyPointerAddr ) {
+ // <rdar://problem/12928448> only de-optimization lazy pointers if they are part of shared cache not loaded (because overridden)
+ const ImageLoader* lazyPointerImage = context.findImageContainingAddress(lazyPointerAddr);
+ if ( lazyPointerImage != NULL )
+ return;
+
// copy newly re-bound lazy pointer value to shared lazy pointer
*lazyPointerAddr = *originalLazyPointerAddr;
+
+ if ( context.verboseBind )
+ dyld::log("dyld: alter bind: %s: *0x%08lX = 0x%08lX \n",
+ this->getShortName(), (long)lazyPointerAddr, (long)*originalLazyPointerAddr);
}
}
#endif
// sanity check symbol index of stub and lazy pointer match
if ( indirectTable[stubsIndirectTableOffset+i] != indirectTable[lazyPointersIndirectTableOffset+i] )
continue;
- this->updateAlternateLazyPointer(stub, lpa);
+ this->updateAlternateLazyPointer(stub, lpa, context);
}
#endif
virtual void rebase(const LinkContext& context);
virtual const ImageLoader::Symbol* findExportedSymbol(const char* name, const ImageLoader** foundIn) const;
virtual bool containsSymbol(const void* addr) const;
- virtual uintptr_t exportedSymbolAddress(const LinkContext& context, const Symbol* symbol, bool runResolver) const;
+ virtual uintptr_t exportedSymbolAddress(const LinkContext& context, const Symbol* symbol, const ImageLoader* requestor, bool runResolver) const;
virtual bool exportedSymbolIsWeakDefintion(const Symbol* symbol) const;
virtual const char* exportedSymbolName(const Symbol* symbol) const;
virtual unsigned int exportedSymbolCount() const;
uint8_t, intptr_t, int, 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);
+ void updateAlternateLazyPointer(uint8_t* stub, void** originalLazyPointerAddr, const LinkContext& context);
const struct dyld_info_command* fDyldInfo;
};
#include <dirent.h>
#include <sys/param.h>
#include <mach/mach_time.h> // mach_absolute_time()
+#include <mach/mach_init.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/syscall.h>
-#include <mach-o/fat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/syslog.h>
+#include <sys/uio.h>
+#include <mach-o/fat.h>
#include <mach-o/loader.h>
#include <mach-o/ldsyms.h>
#include <libkern/OSByteOrder.h>
#include <sys/dtrace.h>
#include <libkern/OSAtomic.h>
#include <Availability.h>
-#include <Kernel/sys/codesign.h>
+#include <System/sys/codesign.h>
+#include <_simple.h>
#ifndef CPU_SUBTYPE_ARM_V5TEJ
#include "ImageLoader.h"
#include "ImageLoaderMachO.h"
#include "dyldLibSystemInterface.h"
+#include "dyldSyscallInterface.h"
#if DYLD_SHARED_CACHE_SUPPORT
#include "dyld_cache_format.h"
#endif
#include "coreSymbolicationDyldSupport.hpp"
#endif
-// from _simple.h in libc
-typedef struct _SIMPLE* _SIMPLE_STRING;
-extern "C" void _simple_vdprintf(int __fd, const char *__fmt, va_list __ap);
-extern "C" void _simple_dprintf(int __fd, const char *__fmt, ...);
-extern "C" _SIMPLE_STRING _simple_salloc(void);
-extern "C" int _simple_vsprintf(_SIMPLE_STRING __b, const char *__fmt, va_list __ap);
-extern "C" void _simple_sfree(_SIMPLE_STRING __b);
-extern "C" char * _simple_string(_SIMPLE_STRING __b);
-
+// 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
//
//
//
+namespace dyld {
+ struct RegisteredDOF { const mach_header* mh; int registrationID; };
+ struct DylibOverride { const char* installName; const char* override; };
+}
+
+
+VECTOR_NEVER_DESTRUCTED(ImageLoader*);
+VECTOR_NEVER_DESTRUCTED(dyld::RegisteredDOF);
+VECTOR_NEVER_DESTRUCTED(dyld::ImageCallback);
+VECTOR_NEVER_DESTRUCTED(dyld::DylibOverride);
+VECTOR_NEVER_DESTRUCTED(ImageLoader::DynamicReference);
+VECTOR_NEVER_DESTRUCTED(dyld_image_state_change_handler);
namespace dyld {
// DYLD_PRINT_RPATHS ==> gLinkContext.verboseRPaths
// DYLD_PRINT_INTERPOSING ==> gLinkContext.verboseInterposing
};
-
+
+
+
typedef std::vector<dyld_image_state_change_handler> StateHandlers;
-struct RegisteredDOF { const mach_header* mh; int registrationID; };
-struct DylibOverride { const char* installName; const char* override; };
+
enum RestrictedReason { restrictedNot, restrictedBySetGUid, restrictedBySegment, restrictedByEntitlements };
// all global state
static const char* sExecPath = NULL;
+static const char* sExecShortName = NULL;
static const macho_header* sMainExecutableMachHeader = NULL;
#if CPU_SUBTYPES_SUPPORTED
static cpu_type_t sHostCPU;
#endif
static ImageLoader* sMainExecutable = NULL;
static bool sProcessIsRestricted = false;
-static RestrictedReason sRestrictedReason = restrictedNot;
+static RestrictedReason sRestrictedReason = restrictedNot;
static unsigned int sInsertedDylibCount = 0;
static std::vector<ImageLoader*> sAllImages;
static std::vector<ImageLoader*> sImageRoots;
static std::vector<RegisteredDOF> sImageFilesNeedingDOFUnregistration;
static std::vector<ImageCallback> sAddImageCallbacks;
static std::vector<ImageCallback> sRemoveImageCallbacks;
-static StateHandlers sSingleHandlers[7];
-static StateHandlers sBatchHandlers[7];
+static void* sSingleHandlers[7][3];
+static void* sBatchHandlers[7][3];
static ImageLoader* sLastImageByAddressCache;
static EnvironmentVariables sEnv;
static const char* sFrameworkFallbackPaths[] = { "$HOME/Library/Frameworks", "/Library/Frameworks", "/Network/Library/Frameworks", "/System/Library/Frameworks", NULL };
static const dyld_cache_header* sSharedCache = NULL;
static long sSharedCacheSlide = 0;
static bool sSharedCacheIgnoreInodeAndTimeStamp = false;
-#if __IPHONE_OS_VERSION_MIN_REQUIRED
+#if __IPHONE_OS_VERSION_MIN_REQUIRED && DYLD_SHARED_CACHE_SUPPORT
bool gSharedCacheOverridden = false;
static const char* sSharedCacheDir = IPHONE_DYLD_SHARED_CACHE_DIR;
static bool sDylibsOverrideCache = false;
bool gRunInitializersOldWay = false;
#endif
static std::vector<DylibOverride> sDylibOverrides;
+#if !TARGET_IPHONE_SIMULATOR
+static int sLogSocket = -1;
+#endif
+static bool sFrameworksFoundAsDylibs = false;
+
+static std::vector<ImageLoader::DynamicReference> sDynamicReferences;
+
//
// 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
#if LOG_BINDINGS
static int sBindingsLogfile = -1;
va_end(list);
}
}
-
#endif
-void log(const char* format, ...)
+#if !TARGET_IPHONE_SIMULATOR
+// based on CFUtilities.c: also_do_stderr()
+static bool useSyslog()
+{
+ // Use syslog() for processes managed by launchd
+ if ( (gLibSystemHelpers != NULL) && (gLibSystemHelpers->version >= 11) ) {
+ if ( (*gLibSystemHelpers->isLaunchdOwned)() ) {
+ return true;
+ }
+ }
+
+ // If stderr is not available, use syslog()
+ struct stat sb;
+ int result = fstat(STDERR_FILENO, &sb);
+ if ( result < 0 )
+ return true; // file descriptor 2 is closed
+
+ return false;
+}
+
+
+static void socket_syslogv(int priority, const char* format, va_list list)
+{
+ // lazily create socket and connection to syslogd
+ if ( sLogSocket == -1 ) {
+ sLogSocket = ::socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (sLogSocket == -1)
+ return; // cannot log
+ ::fcntl(sLogSocket, F_SETFD, 1);
+
+ struct sockaddr_un addr;
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, _PATH_LOG, sizeof(addr.sun_path));
+ if ( ::connect(sLogSocket, (struct sockaddr *)&addr, sizeof(addr)) == -1 ) {
+ ::close(sLogSocket);
+ sLogSocket = -1;
+ return;
+ }
+ }
+
+ // format message to syslogd like: "<priority>Process[pid]: message"
+ _SIMPLE_STRING buf = _simple_salloc();
+ if ( buf == NULL )
+ return;
+ if ( _simple_sprintf(buf, "<%d>%s[%d]: ", LOG_USER|LOG_NOTICE, sExecShortName, getpid()) == 0 ) {
+ if ( _simple_vsprintf(buf, format, list) == 0 ) {
+ const char* p = _simple_string(buf);
+ ::__sendto(sLogSocket, p, strlen(p), 0, NULL, 0);
+ }
+ }
+ _simple_sfree(buf);
+}
+
+void vlog(const char* format, va_list list)
+{
+ if ( useSyslog() )
+ socket_syslogv(LOG_ERR, format, list);
+ else
+ _simple_vdprintf(sLogfile, format, list);
+}
+
+void log(const char* format, ...)
{
va_list list;
va_start(list, format);
- _simple_vdprintf(sLogfile, format, list);
+ vlog(format, list);
va_end(list);
}
-void warn(const char* format, ...)
+
+void vwarn(const char* format, va_list list)
{
_simple_dprintf(sLogfile, "dyld: warning, ");
+ _simple_vdprintf(sLogfile, format, list);
+}
+
+void warn(const char* format, ...)
+{
va_list list;
va_start(list, format);
- _simple_vdprintf(sLogfile, format, list);
+ vwarn(format, list);
va_end(list);
}
+#endif // !TARGET_IPHONE_SIMULATOR
+
+
// <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;
FileOpener::FileOpener(const char* path)
: fd(-1)
{
- fd = open(path, O_RDONLY, 0);
+ fd = my_open(path, O_RDONLY, 0);
}
FileOpener::~FileOpener()
info.registrationID = (int)(ioctlData->dofiod_helpers[i].dofhp_dof);
sImageFilesNeedingDOFUnregistration.push_back(info);
if ( gLinkContext.verboseDOF ) {
- dyld::log("dyld: registering DOF section 0x%p in %s with dtrace, ID=0x%08X\n",
+ dyld::log("dyld: registering DOF section %p in %s with dtrace, ID=0x%08X\n",
dofs[i].dof, dofs[i].imageShortName, info.registrationID);
}
}
}
-static StateHandlers* stateToHandlers(dyld_image_states state, StateHandlers handlersArray[8])
+static StateHandlers* stateToHandlers(dyld_image_states state, void* handlersArray[7][3])
{
switch ( state ) {
case dyld_image_state_mapped:
- return &handlersArray[0];
+ return reinterpret_cast<StateHandlers*>(&handlersArray[0]);
case dyld_image_state_dependents_mapped:
- return &handlersArray[1];
+ return reinterpret_cast<StateHandlers*>(&handlersArray[1]);
case dyld_image_state_rebased:
- return &handlersArray[2];
+ return reinterpret_cast<StateHandlers*>(&handlersArray[2]);
case dyld_image_state_bound:
- return &handlersArray[3];
+ return reinterpret_cast<StateHandlers*>(&handlersArray[3]);
case dyld_image_state_dependents_initialized:
- return &handlersArray[4];
+ return reinterpret_cast<StateHandlers*>(&handlersArray[4]);
case dyld_image_state_initialized:
- return &handlersArray[5];
+ return reinterpret_cast<StateHandlers*>(&handlersArray[5]);
case dyld_image_state_terminated:
- return &handlersArray[6];
+ return reinterpret_cast<StateHandlers*>(&handlersArray[6]);
}
return NULL;
}
-
static void notifySingle(dyld_image_states state, const ImageLoader* image)
{
//dyld::log("notifySingle(state=%d, image=%s)\n", state, image->getPath());
if ( sEnv.DYLD_PRINT_CS_NOTIFICATIONS ) {
dyld::log("dyld core symbolication unload notification: %p %s\n", image->machHeader(), image->getPath());
}
- if ( dyld_all_image_infos.coreSymbolicationShmPage != NULL) {
- CSCppDyldSharedMemoryPage* connection = (CSCppDyldSharedMemoryPage*)dyld_all_image_infos.coreSymbolicationShmPage;
+ if ( dyld::gProcessInfo->coreSymbolicationShmPage != NULL) {
+ CSCppDyldSharedMemoryPage* connection = (CSCppDyldSharedMemoryPage*)dyld::gProcessInfo->coreSymbolicationShmPage;
if ( connection->is_valid_version() ) {
coresymbolication_unload_image(connection, image);
}
// dylibs needed by the main executable, dyld_all_image_infos is not yet set
// up, leading to usually brief crash logs.
//
-// This function manually adds the images loaded so far to dyld_all_image_infos.
+// This function manually adds the images loaded so far to dyld::gProcessInfo.
// It should only be called before terminating.
//
void syncAllImages()
info.imageFileModDate = image->lastModified();
// add to all_image_infos if not already there
bool found = false;
- int existingCount = dyld_all_image_infos.infoArrayCount;
- const dyld_image_info* existing = dyld_all_image_infos.infoArray;
+ int existingCount = dyld::gProcessInfo->infoArrayCount;
+ const dyld_image_info* existing = dyld::gProcessInfo->infoArray;
if ( existing != NULL ) {
for (int i=0; i < existingCount; ++i) {
if ( existing[i].imageLoadAddress == info.imageLoadAddress ) {
dyld::log("dyld core symbolication load notification: %p %s\n", (*it)->machHeader(), (*it)->getPath());
}
}
- if ( dyld_all_image_infos.coreSymbolicationShmPage != NULL) {
- CSCppDyldSharedMemoryPage* connection = (CSCppDyldSharedMemoryPage*)dyld_all_image_infos.coreSymbolicationShmPage;
+ if ( dyld::gProcessInfo->coreSymbolicationShmPage != NULL) {
+ CSCppDyldSharedMemoryPage* connection = (CSCppDyldSharedMemoryPage*)dyld::gProcessInfo->coreSymbolicationShmPage;
if ( connection->is_valid_version() ) {
// This needs to be captured now
uint64_t load_timestamp = mach_absolute_time();
}
#endif
+static void addDynamicReference(ImageLoader* from, ImageLoader* to) {
+ // don't add dynamic reference if either are in the shared cache
+ if( from->inSharedCache() )
+ return;
+ if( to->inSharedCache() )
+ return;
+
+ // don't add dynamic reference if there already is a static one
+ if ( from->dependsOn(to) )
+ return;
+
+ // don't add if this combination already exists
+ for (std::vector<ImageLoader::DynamicReference>::iterator it=sDynamicReferences.begin(); it != sDynamicReferences.end(); ++it) {
+ if ( (it->from == from) && (it->to == to) )
+ return;
+ }
+ //dyld::log("addDynamicReference(%s, %s\n", from->getShortName(), to->getShortName());
+ ImageLoader::DynamicReference t;
+ t.from = from;
+ t.to = to;
+ sDynamicReferences.push_back(t);
+}
+
static void addImage(ImageLoader* image)
{
// add to master list
}
+//
+// Helper for std::remove_if
+//
+class RefUsesImage {
+public:
+ RefUsesImage(ImageLoader* image) : _image(image) {}
+ bool operator()(const ImageLoader::DynamicReference& ref) const {
+ return ( (ref.from == _image) || (ref.to == _image) );
+ }
+private:
+ ImageLoader* _image;
+};
+
+
+
void removeImage(ImageLoader* image)
{
- // if in termination list, pull it out and run terminator
- for (std::vector<ImageLoader*>::iterator it=sImageFilesNeedingTermination.begin(); it != sImageFilesNeedingTermination.end(); it++) {
- if ( *it == image ) {
- sImageFilesNeedingTermination.erase(it);
- image->doTermination(gLinkContext);
- break;
- }
- }
-
// if has dtrace DOF section, tell dtrace it is going away, then remove from sImageFilesNeedingDOFUnregistration
for (std::vector<RegisteredDOF>::iterator it=sImageFilesNeedingDOFUnregistration.begin(); it != sImageFilesNeedingDOFUnregistration.end(); ) {
if ( it->mh == image->machHeader() ) {
// notify
notifySingle(dyld_image_state_terminated, image);
- // <rdar://problem/7740779> dyld should directly call __cxa_finalize()
- if ( (gLibSystemHelpers != NULL) && (gLibSystemHelpers->version >= 8) )
- (*gLibSystemHelpers->cxa_finalize)(image->machHeader());
-
// remove from mapped images table
removedMappedRanges(image);
}
allImagesUnlock();
+ // remove from sDynamicReferences
+ sDynamicReferences.erase(std::remove_if(sDynamicReferences.begin(), sDynamicReferences.end(), RefUsesImage(image)), sDynamicReferences.end());
+
// flush find-by-address cache (do this after removed from master list, so there is no chance it can come back)
if ( sLastImageByAddressCache == image )
sLastImageByAddressCache = NULL;
}
+void runImageTerminators(ImageLoader* image)
+{
+ // if in termination list, pull it out and run terminator
+ bool mightBeMore;
+ do {
+ mightBeMore = false;
+ for (std::vector<ImageLoader*>::iterator it=sImageFilesNeedingTermination.begin(); it != sImageFilesNeedingTermination.end(); it++) {
+ if ( *it == image ) {
+ sImageFilesNeedingTermination.erase(it);
+ 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)
{
sImageFilesNeedingTermination.push_back(image);
void initializeMainExecutable()
{
- // apply interposing to initial set of images
- // do this before making the __IMPORT segments in shared cache read-only
- sMainExecutable->applyInterposing(gLinkContext);
-
// record that we've reached this step
gLinkContext.startedInitializingMainExecutable = true;
if ( altVersion > prevVersion ) {
// found an even newer override
free((void*)(it->override));
- it->override = strdup(dylibFile);
+ char resolvedPath[PATH_MAX];
+ if ( realpath(dylibFile, resolvedPath) != NULL )
+ it->override = strdup(resolvedPath);
+ else
+ it->override = strdup(dylibFile);
break;
}
}
if ( ! entryExists ) {
DylibOverride entry;
entry.installName = strdup(sysInstallName);
- entry.override = strdup(dylibFile);
+ char resolvedPath[PATH_MAX];
+ if ( realpath(dylibFile, resolvedPath) != NULL )
+ entry.override = strdup(resolvedPath);
+ else
+ entry.override = strdup(dylibFile);
sDylibOverrides.push_back(entry);
//dyld::log("added override: %s -> %s\n", entry.installName, entry.override);
}
else if ( strcmp(key, "DYLD_PRINT_INTERPOSING") == 0 ) {
gLinkContext.verboseInterposing = true;
}
+ else if ( strcmp(key, "DYLD_PRINT_CODE_SIGNATURES") == 0 ) {
+ gLinkContext.verboseCodeSignatures = true;
+ }
else if ( strcmp(key, "DYLD_SHARED_REGION") == 0 ) {
if ( strcmp(value, "private") == 0 ) {
gLinkContext.sharedRegionMode = ImageLoader::kUsePrivateSharedRegion;
}
#endif // SUPPORT_LC_DYLD_ENVIRONMENT
+
+static bool hasCodeSignatureLoadCommand(const macho_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;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ if (cmd->cmd == LC_CODE_SIGNATURE)
+ return true;
+ cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+ }
+ return false;
+}
+
#if SUPPORT_VERSIONED_PATHS
static void checkVersionedPaths()
}
}
*d++ = NULL;
+// <rdar://11894054> Disable warnings about DYLD_ env vars being ignored. The warnings are causing too much confusion.
+#if 0
if ( removedCount != 0 ) {
dyld::log("dyld: DYLD_ environment variables being ignored because ");
switch (sRestrictedReason) {
break;
}
}
-
+#endif
// slide apple parameters
if ( removedCount > 0 ) {
*applep = d;
sEnv.DYLD_FALLBACK_LIBRARY_PATH = paths;
}
+ // <rdar://problem/11281064> DYLD_IMAGE_SUFFIX and DYLD_ROOT_PATH cannot be used together
+ if ( (gLinkContext.imageSuffix != NULL) && (gLinkContext.rootPaths != NULL) ) {
+ dyld::warn("Ignoring DYLD_IMAGE_SUFFIX because DYLD_ROOT_PATH is used.\n");
+ gLinkContext.imageSuffix = NULL;
+ }
+
#if SUPPORT_VERSIONED_PATHS
checkVersionedPaths();
#endif
// 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 },
+ // 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 },
+
// 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 },
// if stat() not done yet, do it now
struct stat statb;
if ( stat_buf == NULL ) {
- if ( stat(path, &statb) == -1 )
+ if ( my_stat(path, &statb) == -1 )
return false;
stat_buf = &statb;
}
// 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;
- if ( stat(aPath, &pathInCacheStatBuf) != -1 )
+ if ( my_stat(aPath, &pathInCacheStatBuf) != -1 )
cacheHit = ( (pathInCacheStatBuf.st_dev == stat_buf->st_dev) && (pathInCacheStatBuf.st_ino == stat_buf->st_ino) );
}
if ( cacheHit ) {
// just return NULL if file not found, but record any other errors
struct stat stat_buf;
- if ( stat(path, &stat_buf) == -1 ) {
+ if ( my_stat(path, &stat_buf) == -1 ) {
int err = errno;
if ( err != ENOENT ) {
exceptions->push_back(dyld::mkstringf("%s: stat() failed with errno=%d", path, err));
ImageLoader* image = NULL;
*imageFound = false;
*statErrNo = 0;
- if ( stat(path, stat_buf) == 0 ) {
+ if ( my_stat(path, stat_buf) == 0 ) {
// in case image was renamed or found via symlinks, check for inode match
image = findLoadedImage(*stat_buf);
if ( image != NULL ) {
}
}
}
- if ( libraryPaths != NULL ) {
+ // <rdar://problem/12649639> An executable with the same name as a framework & DYLD_LIBRARY_PATH pointing to it gets loaded twice
+ // <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);
for(const char* const* lp = libraryPaths; *lp != NULL; ++lp) {
for (std::vector<const char*>::iterator it = exceptions.begin(); it != exceptions.end(); ++it) {
free((void*)(*it));
}
-#if __IPHONE_OS_VERSION_MIN_REQUIRED
+#if __IPHONE_OS_VERSION_MIN_REQUIRED && 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 ) {
#elif __x86_64__
#define ARCH_NAME "x86_64"
#define ARCH_CACHE_MAGIC "dyld_v1 x86_64"
- #define SHARED_REGION_READ_ONLY_START 0x7FFF80000000LL
- #define SHARED_REGION_READ_ONLY_END 0x7FFFC0000000LL
- #define SHARED_REGION_WRITABLE_START 0x7FFF70000000LL
- #define SHARED_REGION_WRITABLE_END 0x7FFF80000000LL
- #define SLIDEABLE_CACHE_SUPPORT 1
#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"
- #define SHARED_REGION_READ_ONLY_START 0x30000000
- #define SHARED_REGION_READ_ONLY_END 0x3E000000
- #define SHARED_REGION_WRITABLE_START 0x3E000000
- #define SHARED_REGION_WRITABLE_END 0x40000000
- #define SLIDEABLE_CACHE_SUPPORT 1
#elif __ARM_ARCH_7A__
#define ARCH_NAME "armv7"
#define ARCH_CACHE_MAGIC "dyld_v1 armv7"
- #define SHARED_REGION_READ_ONLY_START 0x30000000
- #define SHARED_REGION_READ_ONLY_END 0x3E000000
- #define SHARED_REGION_WRITABLE_START 0x3E000000
- #define SHARED_REGION_WRITABLE_END 0x40000000
- #define SLIDEABLE_CACHE_SUPPORT 1
+#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"
- #define SHARED_REGION_READ_ONLY_START 0x30000000
- #define SHARED_REGION_READ_ONLY_END 0x3E000000
- #define SHARED_REGION_WRITABLE_START 0x3E000000
- #define SHARED_REGION_WRITABLE_END 0x40000000
- #define SLIDEABLE_CACHE_SUPPORT 1
#endif
}
-static int __attribute__((noinline)) _shared_region_map_and_slide_np(int fd, uint32_t count, const shared_file_mapping_np mappings[],
+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)
{
-#if __IPHONE_OS_VERSION_MIN_REQUIRED
// register code signature blob for whole dyld cache
if ( codeSignatureMappingIndex != -1 ) {
fsignatures_t siginfo;
siginfo.fs_blob_start = (void*)mappings[codeSignatureMappingIndex].sfm_file_offset;
siginfo.fs_blob_size = mappings[codeSignatureMappingIndex].sfm_size;
int result = fcntl(fd, F_ADDFILESIGS, &siginfo);
- if ( result == -1 )
- dyld::log("dyld: code signature for shared cache failed with errno=%d\n", errno);
+ // <rdar://problem/12891874> don't warn in chrooted case because mapping syscall is about to fail too
+ if ( (result == -1) && gLinkContext.verboseMapping )
+ dyld::log("dyld: code signature registration for shared cache failed with errno=%d\n", errno);
}
-#endif
+
if ( gLinkContext.sharedRegionMode == ImageLoader::kUseSharedRegion ) {
return syscall(438, fd, count, mappings, slide, slideInfo, slideInfoSize);
}
vm_deallocate(mach_task_self(), (vm_address_t)SHARED_REGION_BASE, SHARED_REGION_SIZE);
// notify gdb or other lurkers that this process is no longer using the shared region
- dyld_all_image_infos.processDetachedFromSharedRegion = true;
+ dyld::gProcessInfo->processDetachedFromSharedRegion = true;
// map cache just for this process with mmap()
const shared_file_mapping_np* const start = mappings;
}
}
-#if SLIDEABLE_CACHE_SUPPORT
// update all __DATA pages with slide info
if ( slide != 0 ) {
const uintptr_t dataPagesStart = mappings[1].sfm_address;
}
}
}
-#endif // SLIDEABLE_CACHE_SUPPORT
// succesfully mapped shared cache for just this process
gLinkContext.sharedRegionMode = ImageLoader::kUsePrivateSharedRegion;
int openSharedCacheFile()
{
- char path[1024];
- strcpy(path, sSharedCacheDir);
- strcat(path, "/");
- strcat(path, DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME);
- return ::open(path, O_RDONLY);
+ char path[MAXPATHLEN];
+ strlcpy(path, sSharedCacheDir, MAXPATHLEN);
+ strlcat(path, "/", MAXPATHLEN);
+ strlcat(path, DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME, MAXPATHLEN);
+ return my_open(path, O_RDONLY, 0);
}
-#if SLIDEABLE_CACHE_SUPPORT
static long pickCacheSlide(uint32_t mappingsCount, shared_file_mapping_np mappings[])
{
+#if __x86_64__
+ // x86_64 has a two memory regions:
+ // 256MB at 0x00007FFF70000000
+ // 1024MB at 0x00007FFF80000000
+ // Some old shared caches have r/w region after rx region, so all regions slide within 1GB range
+ // Newer shared caches have r/w region based at 0x7FFF70000000 and r/o regions at 0x7FFF80000000, so each part has max slide
+ if ( (mappingsCount >= 3) && (mappings[1].sfm_init_prot == (VM_PROT_READ|VM_PROT_WRITE)) && (mappings[1].sfm_address == 0x00007FFF70000000) ) {
+ const uint64_t rwSize = mappings[1].sfm_size;
+ const uint64_t rwSlop = 0x10000000ULL - rwSize;
+ const uint64_t roSize = (mappings[2].sfm_address + mappings[2].sfm_size) - mappings[0].sfm_address;
+ const uint64_t roSlop = 0x40000000ULL - roSize;
+ const uint64_t space = (rwSlop < roSlop) ? rwSlop : roSlop;
+
+ // choose new random slide
+ long slide = (arc4random() % space) & (-4096);
+ //dyld::log("rwSlop=0x%0llX, roSlop=0x%0llX\n", rwSlop, roSlop);
+ //dyld::log("space=0x%0llX, slide=0x%0lX\n", space, slide);
+
+ // update mappings
+ for(uint32_t i=0; i < mappingsCount; ++i) {
+ mappings[i].sfm_address += slide;
+ }
+
+ return slide;
+ }
+ // else fall through to handle old style cache
+#endif
// get bounds of cache
- uint64_t readOnlyLowAddress = 0;
- uint64_t readOnlyHighAddress = 0;
- uint64_t writableLowAddress = 0;
- uint64_t writableHighAddress = 0;
+ uint64_t lowAddress = 0;
+ uint64_t highAddress = 0;
for(uint32_t i=0; i < mappingsCount; ++i) {
- if ( mappings[i].sfm_init_prot & VM_PROT_WRITE ) {
- writableLowAddress = mappings[i].sfm_address;
- writableHighAddress = mappings[i].sfm_address + mappings[i].sfm_size;
+ if ( lowAddress == 0 ) {
+ lowAddress = mappings[i].sfm_address;
+ highAddress = mappings[i].sfm_address + mappings[i].sfm_size;
}
else {
- if ( readOnlyLowAddress == 0 ) {
- readOnlyLowAddress = mappings[i].sfm_address;
- readOnlyHighAddress = mappings[i].sfm_address + mappings[i].sfm_size;
- }
- else {
- if ( readOnlyLowAddress < mappings[i].sfm_address ) {
- readOnlyHighAddress = mappings[i].sfm_address + mappings[i].sfm_size;
- }
- else {
- readOnlyLowAddress = mappings[i].sfm_address;
- }
- }
+ 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;
}
}
- // find read-only slop space
- uint64_t roSpace = SHARED_REGION_READ_ONLY_END - readOnlyHighAddress;
-
- // find writable slop space
- uint64_t rwSpace = SHARED_REGION_WRITABLE_END - writableHighAddress;
+ // find slop space
+ const uint64_t space = (SHARED_REGION_BASE + SHARED_REGION_SIZE) - highAddress;
// choose new random slide
- long slideSpace = (roSpace > rwSpace) ? rwSpace : roSpace;
- long slide = (arc4random() % slideSpace) & (-4096);
- //dyld::log("roSpace=0x%0llX\n", roSpace);
- //dyld::log("rwSpace=0x%0llX\n", rwSpace);
- //dyld::log("slideSpace=0x%0lX\n", slideSpace);
+ long slide = (arc4random() % space) & (-4096);
+ //dyld::log("slideSpace=0x%0llX\n", space);
//dyld::log("slide=0x%0lX\n", slide);
// update mappings
return slide;
}
-#endif // SLIDEABLE_CACHE_SUPPORT
static void mapSharedCache()
{
- uint64_t cacheBaseAddress;
+ uint64_t cacheBaseAddress = 0;
// quick check if a cache is alreay 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 ) {
sSharedCache = NULL;
- if ( gLinkContext.verboseMapping )
+ if ( gLinkContext.verboseMapping ) {
dyld::log("dyld: existing shared cached in memory is not compatible\n");
+ return;
+ }
}
// check if cache file is slidable
- dyld_cache_header* header = (dyld_cache_header*)sSharedCache;
+ const dyld_cache_header* header = sSharedCache;
if ( (header->mappingOffset >= 0x48) && (header->slideInfoSize != 0) ) {
// solve for slide by comparing loaded address to address of first region
const uint8_t* loadedAddress = (uint8_t*)sSharedCache;
const dyld_cache_mapping_info* const mappings = (dyld_cache_mapping_info*)(loadedAddress+header->mappingOffset);
const uint8_t* preferedLoadAddress = (uint8_t*)(long)(mappings[0].address);
sSharedCacheSlide = loadedAddress - preferedLoadAddress;
- dyld_all_image_infos.sharedCacheSlide = sSharedCacheSlide;
+ dyld::gProcessInfo->sharedCacheSlide = sSharedCacheSlide;
//dyld::log("sSharedCacheSlide=0x%08lX, loadedAddress=%p, preferedLoadAddress=%p\n", sSharedCacheSlide, loadedAddress, preferedLoadAddress);
}
+ // if cache has a uuid, copy it
+ if ( header->mappingOffset >= 0x68 ) {
+ memcpy(dyld::gProcessInfo->sharedCacheUUID, header->uuid, 16);
+ }
}
else {
#if __i386__ || __x86_64__
// user booted machine in safe-boot mode
struct stat dyldCacheStatInfo;
// Don't use custom DYLD_SHARED_CACHE_DIR if provided, use standard path
- if ( ::stat(MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME, &dyldCacheStatInfo) == 0 ) {
+ if ( my_stat(MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME, &dyldCacheStatInfo) == 0 ) {
struct timeval bootTimeValue;
size_t bootTimeValueSize = sizeof(bootTimeValue);
if ( (sysctlbyname("kern.boottime", &bootTimeValue, &bootTimeValueSize, NULL, 0) == 0) && (bootTimeValue.tv_sec != 0) ) {
shared_file_mapping_np mappings[header->mappingCount+1]; // add room for code-sig
unsigned int mappingCount = header->mappingCount;
int codeSignatureMappingIndex = -1;
+ int readWriteMappingIndex = -1;
+ int readOnlyMappingIndex = -1;
// validate that the cache file has not been truncated
bool goodCache = false;
struct stat stat_buf;
dyld::log("dyld: shared cached file is corrupt: %s" DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME "\n", sSharedCacheDir);
goodCache = false;
}
+ if ( (mappings[i].sfm_init_prot & (VM_PROT_READ|VM_PROT_WRITE)) == (VM_PROT_READ|VM_PROT_WRITE) ) {
+ readWriteMappingIndex = i;
+ }
+ if ( mappings[i].sfm_init_prot == VM_PROT_READ ) {
+ readOnlyMappingIndex = i;
+ }
}
-#if __IPHONE_OS_VERSION_MIN_REQUIRED
// if shared cache is code signed, add a mapping for the code signature
uint32_t signatureSize = header->codeSignatureSize;
// zero size in header means signature runs to end-of-file
mappings[codeSignatureMappingIndex].sfm_max_prot = VM_PROT_READ;
mappings[codeSignatureMappingIndex].sfm_init_prot = VM_PROT_READ;
}
-#endif
}
#if __MAC_OS_X_VERSION_MIN_REQUIRED
// sanity check that /usr/lib/libSystem.B.dylib stat() info matches cache
if ( header->imagesCount * sizeof(dyld_cache_image_info) + header->imagesOffset < 8192 ) {
bool foundLibSystem = false;
- if ( stat("/usr/lib/libSystem.B.dylib", &stat_buf) == 0 ) {
+ if ( my_stat("/usr/lib/libSystem.B.dylib", &stat_buf) == 0 ) {
const dyld_cache_image_info* images = (dyld_cache_image_info*)&firstPages[header->imagesOffset];
const dyld_cache_image_info* const imagesEnd = &images[header->imagesCount];
for (const dyld_cache_image_info* p = images; p < imagesEnd; ++p) {
goodCache = false;
}
}
-#endif
+#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 && (readOnlyMappingIndex == -1) ) {
+ dyld::log("dyld: shared cached file is missing read-only 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;
- #if SLIDEABLE_CACHE_SUPPORT
// 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)
else {
// generate random slide amount
cacheSlide = pickCacheSlide(mappingCount, mappings);
- slideInfo = (void*)(long)(mappings[2].sfm_address + (header->slideInfoOffset - mappings[2].sfm_file_offset));
+ slideInfo = (void*)(long)(mappings[readOnlyMappingIndex].sfm_address + (header->slideInfoOffset - mappings[readOnlyMappingIndex].sfm_file_offset));
slideInfoSize = header->slideInfoSize;
// add VM_PROT_SLIDE bit to __DATA area of cache
- mappings[1].sfm_max_prot |= VM_PROT_SLIDE;
- mappings[1].sfm_init_prot |= VM_PROT_SLIDE;
+ mappings[readWriteMappingIndex].sfm_max_prot |= VM_PROT_SLIDE;
+ mappings[readWriteMappingIndex].sfm_init_prot |= VM_PROT_SLIDE;
}
}
- #endif
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;
sSharedCacheSlide = cacheSlide;
- dyld_all_image_infos.sharedCacheSlide = cacheSlide;
+ dyld::gProcessInfo->sharedCacheSlide = cacheSlide;
//dyld::log("sSharedCache=%p sSharedCacheSlide=0x%08lX\n", sSharedCache, sSharedCacheSlide);
+ // if cache has a uuid, copy it
+ if ( header->mappingOffset >= 0x68 ) {
+ memcpy(dyld::gProcessInfo->sharedCacheUUID, header->uuid, 16);
+ }
}
else {
if ( gLinkContext.verboseMapping )
}
#endif
}
-#if __IPHONE_OS_VERSION_MIN_REQUIRED
if ( gLinkContext.verboseMapping ) {
// list the code blob
dyld_cache_header* header = (dyld_cache_header*)sSharedCache;
// zero size in header means signature runs to end-of-file
if ( signatureSize == 0 ) {
struct stat stat_buf;
- if ( ::stat(IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME, &stat_buf) == 0 )
+ if ( my_stat(IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME, &stat_buf) == 0 )
signatureSize = stat_buf.st_size - header->codeSignatureOffset;
}
if ( signatureSize != 0 ) {
dyld::log(" 0x%08llX->0x%08llX (code signature)\n", codeBlobStart, codeBlobStart+signatureSize);
}
}
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
// check for file that enables dyld shared cache dylibs to be overridden
struct stat enableStatBuf;
- sDylibsOverrideCache = ( ::stat(IPHONE_DYLD_SHARED_CACHE_DIR "enable-dylibs-to-override-cache", &enableStatBuf) == 0 );
+ sDylibsOverrideCache = ( my_stat(IPHONE_DYLD_SHARED_CACHE_DIR "enable-dylibs-to-override-cache", &enableStatBuf) == 0 );
#endif
}
}
static void setErrorStrings(unsigned errorCode, const char* errorClientOfDylibPath,
const char* errorTargetDylibPath, const char* errorSymbol)
{
- dyld_all_image_infos.errorKind = errorCode;
- dyld_all_image_infos.errorClientOfDylibPath = errorClientOfDylibPath;
- dyld_all_image_infos.errorTargetDylibPath = errorTargetDylibPath;
- dyld_all_image_infos.errorSymbol = errorSymbol;
+ dyld::gProcessInfo->errorKind = errorCode;
+ dyld::gProcessInfo->errorClientOfDylibPath = errorClientOfDylibPath;
+ dyld::gProcessInfo->errorTargetDylibPath = errorTargetDylibPath;
+ dyld::gProcessInfo->errorSymbol = errorSymbol;
}
#if SUPPORT_OLD_CRT_INITIALIZATION
gLinkContext.setRunInitialzersOldWay= &setRunInitialzersOldWay;
#endif
+ gLinkContext.findImageContainingAddress = &findImageContainingAddress;
+ gLinkContext.addDynamicReference = &addDynamicReference;
gLinkContext.bindingOptions = ImageLoader::kBindingNone;
gLinkContext.argc = argc;
gLinkContext.argv = argv;
for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
ImageLoader* image = *it;
dyld_image_states imageState = image->getState();
- dyld::log(" state=%d, refcount=%d, name=%s\n", imageState, image->referenceCount(), image->getShortName());
- image->printReferenceCounts();
+ dyld::log(" state=%d, dlopen-count=%d, never-unload=%d, in-use=%d, name=%s\n",
+ imageState, image->dlopenCount(), image->neverUnload(), image->isMarkedInUse(), image->getShortName());
}
}
#endif
-void link(ImageLoader* image, bool forceLazysBound, const ImageLoader::RPathChain& loaderRPaths)
+void link(ImageLoader* image, bool forceLazysBound, bool neverUnload, const ImageLoader::RPathChain& loaderRPaths)
{
// add to list of known images. This did not happen at creation time for bundles
if ( image->isBundle() && !image->isLinked() )
// process images
try {
- image->link(gLinkContext, forceLazysBound, false, loaderRPaths);
+ image->link(gLinkContext, forceLazysBound, false, neverUnload, loaderRPaths);
}
catch (const char* msg) {
garbageCollectImages();
image->runInitializers(gLinkContext, initializerTimes[0]);
}
+// This function is called at the end of dlclose() when the reference count goes to zero.
+// The dylib being unloaded may have brought in other dependent dylibs when it was loaded.
+// Those dependent dylibs need to be unloaded, but only if they are not referenced by
+// something else. We use a standard mark and sweep garbage collection.
+//
+// The tricky part is that when a dylib is unloaded it may have a termination function that
+// can run and itself call dlclose() on yet another dylib. The problem is that this
+// sort of gabage collection is not re-entrant. Instead a terminator's call to dlclose()
+// which calls garbageCollectImages() will just set a flag to re-do the garbage collection
+// when the current pass is done.
+//
+// Also note that this is done within the dyld global lock, so it is always single threaded.
+//
void garbageCollectImages()
{
- // keep scanning list of images until entire list is scanned with no unreferenced images
- bool mightBeUnreferencedImages = true;
- while ( mightBeUnreferencedImages ) {
- mightBeUnreferencedImages = false;
+ static bool sDoingGC = false;
+ static bool sRedo = false;
+
+ if ( sDoingGC ) {
+ // GC is currently being run, just set a flag to have it run again.
+ sRedo = true;
+ return;
+ }
+
+ sDoingGC = true;
+ do {
+ sRedo = false;
+
+ // mark phase: mark all images not-in-use
for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
ImageLoader* image = *it;
- if ( (image->referenceCount() == 0) && !image->neverUnload() && !image->isBeingRemoved() ) {
- if ( image->isReferencedUpward() ) {
- // temp hack for rdar://problem/10973109
- // if an image is upwardly referenced, we really need to scan all images
- // to see if any are still using it.
- continue;
- }
- try {
- //dyld::log("garbageCollectImages: deleting %p %s\n", image, image->getPath());
- image->setBeingRemoved();
- removeImage(image);
- ImageLoader::deleteImage(image);
- }
- catch (const char* msg) {
- dyld::warn("problem deleting image: %s\n", msg);
- }
- mightBeUnreferencedImages = true;
- break;
+ //dyld::log("gc: neverUnload=%d name=%s\n", image->neverUnload(), image->getShortName());
+ image->markNotUsed();
+ }
+
+ // sweep phase: mark as in-use, images reachable from never-unload or in-use image
+ for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
+ ImageLoader* image = *it;
+ if ( (image->dlopenCount() != 0) || image->neverUnload() ) {
+ image->markedUsedRecursive(sDynamicReferences);
}
}
- }
+
+ // collect phase: build array of images not marked in-use
+ ImageLoader* deadImages[sAllImages.size()];
+ unsigned deadCount = 0;
+ unsigned i = 0;
+ for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
+ ImageLoader* image = *it;
+ if ( ! image->isMarkedInUse() ) {
+ deadImages[i++] = image;
+ if (gLogAPIs) dyld::log("dlclose(), found unused image %p %s\n", image, image->getShortName());
+ ++deadCount;
+ }
+ }
+
+ // 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
+ for (unsigned i=0; i < deadCount; ++i) {
+ ImageLoader* image = deadImages[i];
+ try {
+ if (gLogAPIs) dyld::log("dlclose(), running terminators for %p %s\n", image, image->getShortName());
+ runImageTerminators(image);
+ }
+ catch (const char* msg) {
+ dyld::warn("problem running terminators for image: %s\n", msg);
+ }
+ }
+
+ // collect phase: delete all images which are not marked in-use
+ bool mightBeMore;
+ do {
+ mightBeMore = false;
+ for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
+ ImageLoader* image = *it;
+ if ( ! image->isMarkedInUse() ) {
+ try {
+ if (gLogAPIs) dyld::log("dlclose(), deleting %p %s\n", image, image->getShortName());
+ removeImage(image);
+ ImageLoader::deleteImage(image);
+ mightBeMore = true;
+ break; // interator in invalidated by this removal
+ }
+ catch (const char* msg) {
+ dyld::warn("problem deleting image: %s\n", msg);
+ }
+ }
+ }
+ } while ( mightBeMore );
+ } while (sRedo);
+ sDoingGC = false;
+
//printAllImages();
+
}
try {
if ( image->isBundle() )
sBundleBeingLoaded = image; // hack
- image->link(gLinkContext, false, true, loaderRPaths);
+ image->link(gLinkContext, false, true, false, loaderRPaths);
}
catch (const char* msg) {
preflight_finally(image);
context.origin = NULL; // can't use @loader_path with DYLD_INSERT_LIBRARIES
context.rpath = NULL;
image = load(path, context);
- image->setNeverUnload();
+ }
+ catch (const char* msg) {
+ halt(dyld::mkstringf("could not load inserted library '%s' because %s\n", path, msg));
}
catch (...) {
- halt(dyld::mkstringf("could not load inserted library: %s\n", path));
+ halt(dyld::mkstringf("could not load inserted library '%s'\n", path));
}
}
static bool processRestricted(const macho_header* mainExecutableMH)
-{
- // all processes with setuid or setgid bit set are restricted
+{
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+ // ask kernel if code signature of program makes it restricted
+ uint32_t flags;
+ if ( csops(0, CS_OPS_STATUS, &flags, sizeof(flags)) != -1 ) {
+ if ( flags & CS_ENFORCEMENT ) {
+ gLinkContext.codeSigningEnforced = true;
+ }
+ }
+ if (flags & CS_RESTRICT) {
+ sRestrictedReason = restrictedByEntitlements;
+ return true;
+ }
+#else
+ gLinkContext.codeSigningEnforced = true;
+#endif
+
+ // all processes with setuid or setgid bit set are restricted
if ( issetugid() ) {
sRestrictedReason = restrictedBySetGUid;
return true;
}
- const uid_t euid = geteuid();
- if ( (euid != 0) && hasRestrictedSegment(mainExecutableMH) ) {
+ // <rdar://problem/13158444&13245742> Respect __RESTRICT,__restrict section for root processes
+ if ( hasRestrictedSegment(mainExecutableMH) ) {
// existence of __RESTRICT/__restrict section make process restricted
sRestrictedReason = restrictedBySegment;
return true;
}
-
-#if __MAC_OS_X_VERSION_MIN_REQUIRED
- // ask kernel if code signature of program makes it restricted
- uint32_t flags;
- if ( syscall(SYS_csops /* 169 */,
- 0 /* asking about myself */,
- CS_OPS_STATUS,
- &flags,
- sizeof(flags)) != -1) {
- if (flags & CS_RESTRICT) {
- sRestrictedReason = restrictedByEntitlements;
- return true;
- }
- }
-#endif
return false;
}
+bool processIsRestricted()
+{
+ return sProcessIsRestricted;
+}
// <rdar://problem/10583252> Add dyld to uuidArray to enable symbolication of stackshots
}
}
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+typedef int (*open_proc_t)(const char*, int, int);
+typedef int (*fcntl_proc_t)(int, int, void*);
+typedef int (*ioctl_proc_t)(int, unsigned long, void*);
+static void* getProcessInfo() { return dyld::gProcessInfo; }
+static SyscallHelpers sSysCalls = {
+ 1,
+ (open_proc_t)&open,
+ &close,
+ &pread,
+ &write,
+ &mmap,
+ &munmap,
+ &madvise,
+ &stat,
+ (fcntl_proc_t)&fcntl,
+ (ioctl_proc_t)&ioctl,
+ &issetugid,
+ &getcwd,
+ &realpath,
+ &vm_allocate,
+ &vm_deallocate,
+ &vm_protect,
+ &vlog,
+ &vwarn,
+ &pthread_mutex_lock,
+ &pthread_mutex_unlock,
+ &mach_thread_self,
+ &mach_port_deallocate,
+ &task_self_trap,
+ &mach_timebase_info,
+ &OSAtomicCompareAndSwapPtrBarrier,
+ &OSMemoryBarrier,
+ &getProcessInfo,
+ &__error,
+ &mach_absolute_time
+};
+
+__attribute__((noinline))
+static uintptr_t useSimulatorDyld(int fd, const macho_header* mainExecutableMH, const char* dyldPath,
+ int argc, const char* argv[], const char* envp[], const char* apple[], uintptr_t* startGlue)
+{
+ *startGlue = 0;
+
+ // verify simulator dyld file is owned by root
+ struct stat sb;
+ if ( fstat(fd, &sb) == -1 )
+ return 0;
+ if ( sb.st_uid != 0 )
+ return 0;
+
+ // read first page of dyld file
+ uint8_t firstPage[4096];
+ if ( pread(fd, firstPage, 4096, 0) != 4096 )
+ return 0;
+
+ // if fat file, pick matching slice
+ uint64_t fileOffset = 0;
+ uint64_t fileLength = sb.st_size;
+ const fat_header* fileStartAsFat = (fat_header*)firstPage;
+ if ( fileStartAsFat->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
+ if ( !fatFindBest(fileStartAsFat, &fileOffset, &fileLength) )
+ return 0;
+ // re-read buffer from start of mach-o slice in fat file
+ if ( pread(fd, firstPage, 4096, fileOffset) != 4096 )
+ return 0;
+ }
+ else if ( !isCompatibleMachO(firstPage, dyldPath) ) {
+ return 0;
+ }
+
+ // calculate total size of dyld segments
+ const macho_header* mh = (const macho_header*)firstPage;
+ uintptr_t mappingSize = 0;
+ uintptr_t preferredLoadAddress = 0;
+ 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;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ switch (cmd->cmd) {
+ case LC_SEGMENT_COMMAND:
+ {
+ struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
+ mappingSize += seg->vmsize;
+ if ( seg->fileoff == 0 )
+ preferredLoadAddress = seg->vmaddr;
+ }
+ break;
+ }
+ cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+ }
+
+ // reserve space, then mmap each segment
+ vm_address_t loadAddress = 0;
+ uintptr_t entry = 0;
+ if ( ::vm_allocate(mach_task_self(), &loadAddress, mappingSize, VM_FLAGS_ANYWHERE) != 0 )
+ return 0;
+ cmd = cmds;
+ struct linkedit_data_command* codeSigCmd = NULL;
+ for (uint32_t i = 0; i < cmd_count; ++i) {
+ switch (cmd->cmd) {
+ case LC_SEGMENT_COMMAND:
+ {
+ struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
+ uintptr_t requestedLoadAddress = seg->vmaddr - preferredLoadAddress + loadAddress;
+ void* segAddress = ::mmap((void*)requestedLoadAddress, seg->filesize, seg->initprot, MAP_FIXED | MAP_PRIVATE, fd, fileOffset + seg->fileoff);
+ //dyld::log("dyld_sim %s mapped at %p\n", seg->segname, segAddress);
+ if ( segAddress == (void*)(-1) )
+ return 0;
+ }
+ break;
+ case LC_UNIXTHREAD:
+ {
+ #if __i386__
+ const i386_thread_state_t* registers = (i386_thread_state_t*)(((char*)cmd) + 16);
+ entry = (registers->__eip + loadAddress - preferredLoadAddress);
+ #elif __x86_64__
+ const x86_thread_state64_t* registers = (x86_thread_state64_t*)(((char*)cmd) + 16);
+ entry = (registers->__rip + loadAddress - preferredLoadAddress);
+ #endif
+ }
+ break;
+ case LC_CODE_SIGNATURE:
+ codeSigCmd = (struct linkedit_data_command*)cmd;
+ break;
+ }
+ cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+ }
+
+ if ( codeSigCmd != NULL ) {
+ fsignatures_t siginfo;
+ siginfo.fs_file_start=fileOffset; // start of mach-o slice in fat file
+ siginfo.fs_blob_start=(void*)(long)(codeSigCmd->dataoff); // start of code-signature in mach-o file
+ siginfo.fs_blob_size=codeSigCmd->datasize; // size of code-signature
+ int result = fcntl(fd, F_ADDFILESIGS, &siginfo);
+ if ( result == -1 ) {
+ if ( (errno == EPERM) || (errno == EBADEXEC) )
+ return 0;
+ }
+ }
+ close(fd);
+
+ // notify debugger that dyld_sim is loaded
+ dyld_image_info info;
+ info.imageLoadAddress = (mach_header*)loadAddress;
+ info.imageFilePath = strdup(dyldPath);
+ info.imageFileModDate = sb.st_mtime;
+ addImagesToAllImages(1, &info);
+ dyld::gProcessInfo->notification(dyld_image_adding, 1, &info);
+
+ // jump into new simulator dyld
+ typedef uintptr_t (*sim_entry_proc_t)(int argc, const char* argv[], const char* envp[], const char* apple[],
+ const macho_header* mainExecutableMH, const macho_header* dyldMH, uintptr_t dyldSlide,
+ const dyld::SyscallHelpers* vtable, uintptr_t* startGlue);
+ sim_entry_proc_t newDyld = (sim_entry_proc_t)entry;
+ return (*newDyld)(argc, argv, envp, apple, mainExecutableMH, (macho_header*)loadAddress,
+ loadAddress - preferredLoadAddress,
+ &sSysCalls, startGlue);
+}
+#endif
//
_main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide,
int argc, const char* argv[], const char* envp[], const char* apple[],
uintptr_t* startGlue)
-{
+{
uintptr_t result = 0;
+ sMainExecutableMachHeader = mainExecutableMH;
+#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");
+ if ( rootPath != NULL ) {
+ // look to see if simulator has its own dyld
+ char simDyldPath[PATH_MAX];
+ strlcpy(simDyldPath, rootPath, PATH_MAX);
+ strlcat(simDyldPath, "/usr/lib/dyld_sim", PATH_MAX);
+ int fd = my_open(simDyldPath, O_RDONLY, 0);
+ if ( fd != -1 ) {
+ result = useSimulatorDyld(fd, mainExecutableMH, simDyldPath, argc, argv, envp, apple, startGlue);
+ if ( !result && (*startGlue == 0) )
+ halt("problem loading iOS simulator dyld");
+ return result;
+ }
+ }
+#endif
+
CRSetCrashLogMessage("dyld: launch started");
#ifdef ALTERNATIVE_LOGFILE
sLogfile = open(ALTERNATIVE_LOGFILE, O_WRONLY | O_CREAT | O_APPEND);
setContext(mainExecutableMH, argc, argv, envp, apple);
// Pickup the pointer to the exec path.
+ sExecPath = _simple_getenv(apple, "executable_path");
+
+ // <rdar://problem/13868260> Remove interim apple[0] transition code from dyld
+ if (!sExecPath) sExecPath = apple[0];
+
sExecPath = apple[0];
bool ignoreEnvironmentVariables = false;
if ( sExecPath[0] != '/' ) {
sExecPath = s;
}
}
- sMainExecutableMachHeader = mainExecutableMH;
+ // Remember short name of process for later logging
+ sExecShortName = ::strrchr(sExecPath, '/');
+ if ( sExecShortName != NULL )
+ ++sExecShortName;
+ else
+ sExecShortName = sExecPath;
sProcessIsRestricted = processRestricted(mainExecutableMH);
if ( sProcessIsRestricted ) {
#if SUPPORT_LC_DYLD_ENVIRONMENT
#ifdef WAIT_FOR_SYSTEM_ORDER_HANDSHAKE
// <rdar://problem/6849505> Add gating mechanism to dyld support system order file generation process
- WAIT_FOR_SYSTEM_ORDER_HANDSHAKE(dyld_all_image_infos.systemOrderFlag);
+ WAIT_FOR_SYSTEM_ORDER_HANDSHAKE(dyld::gProcessInfo->systemOrderFlag);
#endif
+
try {
// add dyld itself to UUID list
addDyldImageToUUIDList();
- CRSetCrashLogMessage("dyld: launch, loading dependent libraries");
+ if ( sProcessIsRestricted )
+ CRSetCrashLogMessage("dyld: launch, loading dependent libraries, ignoring DYLD_* env vars");
+ else
+ CRSetCrashLogMessage("dyld: launch, loading dependent libraries");
// instantiate ImageLoader for main executable
sMainExecutable = instantiateFromLoadedImage(mainExecutableMH, mainExecutableSlide, sExecPath);
- sMainExecutable->setNeverUnload();
gLinkContext.mainExecutable = sMainExecutable;
gLinkContext.processIsRestricted = sProcessIsRestricted;
+ gLinkContext.mainExecutableCodeSigned = hasCodeSignatureLoadCommand(mainExecutableMH);
// load shared cache
checkSharedRegionDisable();
#if DYLD_SHARED_CACHE_SUPPORT
// link main executable
gLinkContext.linkingMainExecutable = true;
- link(sMainExecutable, sEnv.DYLD_BIND_AT_LAUNCH, ImageLoader::RPathChain(NULL, NULL));
- gLinkContext.linkingMainExecutable = false;
+ link(sMainExecutable, sEnv.DYLD_BIND_AT_LAUNCH, true, ImageLoader::RPathChain(NULL, NULL));
+ sMainExecutable->setNeverUnloadRecursive();
if ( sMainExecutable->forceFlat() ) {
gLinkContext.bindFlat = true;
gLinkContext.prebindUsage = ImageLoader::kUseNoPrebinding;
if ( sInsertedDylibCount > 0 ) {
for(unsigned int i=0; i < sInsertedDylibCount; ++i) {
ImageLoader* image = sAllImages[i+1];
- link(image, sEnv.DYLD_BIND_AT_LAUNCH, ImageLoader::RPathChain(NULL, NULL));
+ link(image, sEnv.DYLD_BIND_AT_LAUNCH, true, ImageLoader::RPathChain(NULL, NULL));
+ image->setNeverUnloadRecursive();
// only INSERTED libraries can interpose
image->registerInterposing();
}
}
+ // apply interposing to initial set of images
+ for(int i=0; i < sImageRoots.size(); ++i) {
+ sImageRoots[i]->applyInterposing(gLinkContext);
+ }
+ gLinkContext.linkingMainExecutable = false;
+
+ // <rdar://problem/12186933> do weak binding only after all inserted images linked
+ sMainExecutable->weakBind(gLinkContext);
CRSetCrashLogMessage("dyld: launch, running initializers");
#if SUPPORT_OLD_CRT_INITIALIZATION
else {
// main executable uses LC_UNIXTHREAD, dyld needs to let "start" in program set up for main()
result = (uintptr_t)sMainExecutable->getMain();
- *startGlue = NULL;
+ *startGlue = 0;
}
}
catch(const char* message) {
-
-}; // namespace
+} // namespace
*/
#include <stdint.h>
+#include <sys/stat.h>
#include "ImageLoader.h"
#include "mach-o/dyld_priv.h"
extern ImageLoader::LinkContext gLinkContext;
+ extern struct dyld_all_image_infos* gProcessInfo;
extern bool gLogAPIs;
+#if DYLD_SHARED_CACHE_SUPPORT
extern bool gSharedCacheOverridden;
+#endif
extern const struct LibSystemHelpers* gLibSystemHelpers;
#if SUPPORT_OLD_CRT_INITIALIZATION
extern bool gRunInitializersOldWay;
extern void registerUndefinedHandler(UndefinedHandler);
extern void initializeMainExecutable();
extern void preflight(ImageLoader* image, const ImageLoader::RPathChain& loaderRPaths);
- extern void link(ImageLoader* image, bool forceLazysBound, 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 const char* getExecutablePath();
extern bool validImage(const ImageLoader*);
extern ImageLoader* getIndexedImage(uint32_t index);
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);
+ const char* apple[], uintptr_t* startGlue) __attribute__((noinline)); // <rdar://problem/11340356>
extern void halt(const char* message) __attribute__((noreturn));
extern void setErrorMessage(const char* msg);
extern const char* getErrorMessage();
extern int openSharedCacheFile();
extern const void* imMemorySharedCacheHeader();
extern uintptr_t fastBindLazySymbol(ImageLoader** imageLoaderCache, uintptr_t lazyBindingInfoOffset);
+#if DYLD_SHARED_CACHE_SUPPORT
extern bool inSharedCache(const char* path);
+#endif
#if LOG_BINDINGS
extern void logBindings(const char* format, ...);
#endif
-};
+ extern bool processIsRestricted();
+ extern int my_stat(const char* path, struct stat* buf);
+ extern int my_open(const char* path, int flag, int other);
+}
#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 },
// deprecated
#if DEPRECATED_APIS_SUPPORTED
const void* imageBaseAddress; // not used with OFI created from files
size_t imageLength; // not used with OFI created from files
};
+
+
+VECTOR_NEVER_DESTRUCTED(NSObjectFileImage);
static std::vector<NSObjectFileImage> sObjectFileImages;
if ( image != NULL ) {
if ( context.matchByInstallName )
image->setMatchInstallPath(true);
- dyld::link(image, false, callersRPaths);
+ dyld::link(image, false, false, callersRPaths);
dyld::runInitializers(image);
// images added with NSAddImage() can never be unloaded
image->setNeverUnload();
dyld::clearErrorMessage();
try {
+ if ( (options & NSLINKMODULE_OPTION_CAN_UNLOAD) != 0 )
+ objectFileImage->image->setCanUnload();
+
// NSLinkModule allows a bundle to be link multpile times
// each link causes the bundle to be copied to a new address
if ( objectFileImage->image->isLinked() ) {
bool forceLazysBound = ( (options & NSLINKMODULE_OPTION_BINDNOW) != 0 );
// load libraries, rebase, bind, to make this image usable
- dyld::link(objectFileImage->image, forceLazysBound, ImageLoader::RPathChain(NULL,NULL));
+ dyld::link(objectFileImage->image, forceLazysBound, false, ImageLoader::RPathChain(NULL,NULL));
// bump reference count to keep this bundle from being garbage collected
objectFileImage->image->incrementDlopenReferenceCount();
bool forceLazysBound = ( (options & NSLINKMODULE_OPTION_BINDNOW) != 0 );
// load libraries, rebase, bind, to make this image usable
- dyld::link(image, forceLazysBound, ImageLoader::RPathChain(NULL,NULL));
+ dyld::link(image, forceLazysBound, false, ImageLoader::RPathChain(NULL,NULL));
// run initializers unless magic flag says not to
if ( (options & NSLINKMODULE_OPTION_DONT_CALL_MOD_INIT_ROUTINES) == 0 )
ImageLoader* image = NSModuleToImageLoader(module);
if ( image == NULL )
return false;
+ dyld::runImageTerminators(image);
dyld::removeImage(image);
if ( (options & NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED) != 0 )
// If dyld is sending load/unload notices to CoreSymbolication, the shared memory
// page is not copied on fork. <rdar://problem/6797342>
// NULL the CoreSymbolication shared memory pointer to prevent a crash.
- dyld_all_image_infos.coreSymbolicationShmPage = NULL;
+ dyld::gProcessInfo->coreSymbolicationShmPage = NULL;
// for safety, make sure child starts with clean systemOrderFlag
- dyld_all_image_infos.systemOrderFlag = 0;
+ dyld::gProcessInfo->systemOrderFlag = 0;
}
typedef void (*MonitorProc)(char *lowpc, char *highpc);
dyld::gLibSystemHelpers = helpers;
// let gdb know it is safe to run code in inferior that might call malloc()
- dyld_all_image_infos.libSystemInitialized = true;
+ dyld::gProcessInfo->libSystemInitialized = true;
#if __arm__
if ( helpers->version >= 5 ) {
static void dlerrorClear()
{
if ( dyld::gLibSystemHelpers != NULL ) {
+ // <rdar://problem/10595338> dlerror buffer leak
+ // dlerrorClear() should not force allocation, but zero it if already allocated
+ if ( dyld::gLibSystemHelpers->version >= 10 ) {
+ if ( ! (*dyld::gLibSystemHelpers->hasPerThreadBufferFor_dlerror)() )
+ return;
+ }
+
// first char of buffer is flag whether string (starting at second char) is valid
char* buffer = (*dyld::gLibSystemHelpers->getThreadBufferFor_dlerror)(2);
buffer[0] = '\0';
if ( (mode & RTLD_NOLOAD) == 0 ) {
bool alreadyLinked = image->isLinked();
bool forceLazysBound = ( (mode & RTLD_NOW) != 0 );
- dyld::link(image, forceLazysBound, callersRPaths);
+ dyld::link(image, forceLazysBound, false, callersRPaths);
if ( ! alreadyLinked ) {
// only hide exports if image is not already in use
if ( (mode & RTLD_LOCAL) != 0 )
// load() succeeded but, link() failed
// back down reference count and do GC
image->decrementDlopenReferenceCount();
- dyld::garbageCollectImages();
+ if ( image->dlopenCount() == 0 )
+ dyld::garbageCollectImages();
}
const char* str = dyld::mkstringf("dlopen(%s, %d): %s", path, mode, msg);
+ if ( dyld::gLogAPIs )
+ dyld::log(" %s() failed, error: '%s'\n", __func__, str);
dlerrorSet(str);
free((void*)str);
free((void*)msg); // our free() will do nothing if msg is a string literal
CRSetCrashLogMessage(NULL);
dyld::gLibSystemHelpers->releaseGlobalDyldLock();
}
+ if ( dyld::gLogAPIs && (result != NULL) )
+ dyld::log(" %s(%s) ==> %p\n", __func__, path, result);
return result;
}
return -1;
}
// remove image if reference count went to zero
- dyld::garbageCollectImages();
+ if ( image->dlopenCount() == 0 )
+ dyld::garbageCollectImages();
return 0;
}
else {
dyld::log("%s()\n", __func__);
if ( dyld::gLibSystemHelpers != NULL ) {
+ // if using newer libdyld.dylib and buffer if buffer not yet allocated, return NULL
+ if ( dyld::gLibSystemHelpers->version >= 10 ) {
+ if ( ! (*dyld::gLibSystemHelpers->hasPerThreadBufferFor_dlerror)() )
+ return NULL;
+ }
+
// first char of buffer is flag whether string (starting at second char) is valid
char* buffer = (*dyld::gLibSystemHelpers->getThreadBufferFor_dlerror)(2);
if ( buffer[0] != '\0' ) { // if valid buffer
const struct dyld_all_image_infos* _dyld_get_all_image_infos()
{
- return &dyld_all_image_infos;
+ return dyld::gProcessInfo;
}
#if !__arm__
#if __IPHONE_OS_VERSION_MIN_REQUIRED
bool dyld_shared_cache_some_image_overridden()
{
+ #if DYLD_SHARED_CACHE_SUPPORT
return dyld::gSharedCacheOverridden;
+ #else
+ return true;
+ #endif
}
#endif
/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
*
- * Copyright (c) 2004-2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2012 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <stddef.h>
#include <string.h>
#include <malloc/malloc.h>
+#include <sys/mman.h>
#include <crt_externs.h>
#include <Availability.h>
+#include <vproc_priv.h>
#include "mach-o/dyld.h"
#include "mach-o/dyld_priv.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);
return(-1);
}
+#define PACKED_VERSION(major, minor, tiny) ((((major) & 0xffff) << 16) | (((minor) & 0xff) << 8) | ((tiny) & 0xff))
+
/*
* Returns the sdk version (encode as nibble XXXX.YY.ZZ) the
*/
uint32_t dyld_get_sdk_version(const mach_header* mh)
{
-#if __LP64__
- const load_command* cmds = (load_command*)((char *)mh + sizeof(mach_header_64));
-#else
- const load_command* cmds = (load_command*)((char *)mh + sizeof(mach_header));
-#endif
+ const load_command* cmds = NULL;
+ if ( mh->magic == MH_MAGIC_64 )
+ cmds = (load_command*)((char *)mh + sizeof(mach_header_64));
+ else if ( mh->magic == MH_MAGIC )
+ cmds = (load_command*)((char *)mh + sizeof(mach_header));
+ else
+ return 0; // not a mach-o file, or wrong endianness
+
const version_min_command* versCmd;
const dylib_command* dylibCmd;
const load_command* cmd = cmds;
+ const char* dylibName;
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
+ uint32_t foundationVers = 0;
+#else
uint32_t libSystemVers = 0;
+#endif
for(uint32_t i = 0; i < mh->ncmds; ++i) {
switch ( cmd->cmd ) {
- case LC_VERSION_MIN_MACOSX:
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
case LC_VERSION_MIN_IPHONEOS:
+#else
+ case LC_VERSION_MIN_MACOSX:
+#endif
versCmd = (version_min_command*)cmd;
+#ifdef DICE_KIND_DATA
if ( versCmd->sdk != 0 )
return versCmd->sdk; // found explicit SDK version
+#else
+ if ( versCmd->reserved != 0 )
+ return versCmd->reserved; // found explicit SDK version
+#endif
break;
case LC_LOAD_DYLIB:
case LC_LOAD_WEAK_DYLIB:
case LC_LOAD_UPWARD_DYLIB:
dylibCmd = (dylib_command*)cmd;
- if ( strcmp((char*)dylibCmd + dylibCmd->dylib.name.offset, "/usr/lib/libSystem.B.dylib") == 0 )
+ dylibName = (char*)dylibCmd + dylibCmd->dylib.name.offset;
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
+ if ( strcmp(dylibName, "/System/Library/Frameworks/Foundation.framework/Foundation") == 0 )
+ foundationVers = dylibCmd->dylib.current_version;
+#else
+ if ( strcmp(dylibName, "/usr/lib/libSystem.B.dylib") == 0 )
libSystemVers = dylibCmd->dylib.current_version;
- else if ( strcmp((char*)dylibCmd + dylibCmd->dylib.name.offset, "/usr/lib/libSystem.dylib") == 0 )
- return 0x00040000; // all iOS simulator have same libSystem.dylib version
+#endif
break;
}
cmd = (load_command*)((char *)cmd + cmd->cmdsize);
}
+
+ struct DylibToOSMapping {
+ uint32_t dylibVersion;
+ uint32_t osVersion;
+ };
- if ( libSystemVers != 0 ) {
- // found linked libSystem.B.dylib version linked against
#if __IPHONE_OS_VERSION_MIN_REQUIRED
- // convert libSystem.B.dylib version to iOS sdk version
- if ( libSystemVers < 0x006F0010 ) // libSystem 111.0.16 in 3.0
- return 0x00020000; // 2.0
- else if ( libSystemVers < 0x006F0201 ) // libSystem 111.2.1 in 3.1
- return 0x00030000; // 3.0
- else if ( libSystemVers < 0x007D020B ) // libSystem 125.2.11 in 4.0
- return 0x00030100; // 3.1
- else if ( libSystemVers < 0x007D0400 ) // libSystem 125.4 in 4.1 and in 4.2
- return 0x00040000; // 4.0
- else if ( libSystemVers < 0x009F0000 ) // libSystem 159 in 4.3
- return 0x00040100; // 4.1
- else if ( libSystemVers < 0x00A10000 ) // libSystem 161 in 5.0
- return 0x00040300; // 4.3
- else
- return 0x00050000;
+ static const DylibToOSMapping foundationMapping[] = {
+ { PACKED_VERSION(678,24,0), DYLD_IOS_VERSION_2_0 },
+ { PACKED_VERSION(678,26,0), DYLD_IOS_VERSION_2_1 },
+ { PACKED_VERSION(678,29,0), DYLD_IOS_VERSION_2_2 },
+ { PACKED_VERSION(678,47,0), DYLD_IOS_VERSION_3_0 },
+ { PACKED_VERSION(678,51,0), DYLD_IOS_VERSION_3_1 },
+ { PACKED_VERSION(678,60,0), DYLD_IOS_VERSION_3_2 },
+ { PACKED_VERSION(751,32,0), DYLD_IOS_VERSION_4_0 },
+ { PACKED_VERSION(751,37,0), DYLD_IOS_VERSION_4_1 },
+ { PACKED_VERSION(751,49,0), DYLD_IOS_VERSION_4_2 },
+ { PACKED_VERSION(751,58,0), DYLD_IOS_VERSION_4_3 },
+ { PACKED_VERSION(881,0,0), DYLD_IOS_VERSION_5_0 },
+ { PACKED_VERSION(890,1,0), DYLD_IOS_VERSION_5_1 },
+ { PACKED_VERSION(992,0,0), DYLD_IOS_VERSION_6_0 },
+ { PACKED_VERSION(993,0,0), DYLD_IOS_VERSION_6_1 },
+ { PACKED_VERSION(1038,14,0),DYLD_IOS_VERSION_7_0 }, // check final
+ { PACKED_VERSION(0,0,0), DYLD_IOS_VERSION_7_0 }
+ };
+
+ if ( foundationVers != 0 ) {
+ uint32_t lastOsVersion = 0;
+ for (const DylibToOSMapping* p=foundationMapping; ; ++p) {
+ if ( p->dylibVersion == 0 )
+ return p->osVersion;
+ if ( foundationVers < p->dylibVersion )
+ return lastOsVersion;
+ lastOsVersion = p->osVersion;
+ }
+ }
+
#else
- // convert libSystem.B.dylib version to MacOSX sdk version
- if ( libSystemVers < 0x006F0000 ) // libSystem 111 in 10.5
- return 0x000A0400; // 10.4
- else if ( libSystemVers < 0x007B0000 ) // libSystem 123 in 10.6
- return 0x000A0500; // 10.5
- else if ( libSystemVers < 0x009F0000 ) // libSystem 159 in 10.7
- return 0x000A0600; // 10.6
- else if ( libSystemVers < 0x00A10000 ) // libSystem 161 in 10.8
- return 0x000A0700; // 10.7
- else
- return 0x000A0800; // 10.8
-#endif
+ // Note: versions are for the GM release. The last entry should
+ // always be zero. At the start of the next major version,
+ // a new last entry needs to be added and the previous zero
+ // updated to the GM dylib version.
+ static const DylibToOSMapping libSystemMapping[] = {
+ { PACKED_VERSION(88,1,3), DYLD_MACOSX_VERSION_10_4 },
+ { PACKED_VERSION(111,0,0), DYLD_MACOSX_VERSION_10_5 },
+ { PACKED_VERSION(123,0,0), DYLD_MACOSX_VERSION_10_6 },
+ { PACKED_VERSION(159,0,0), DYLD_MACOSX_VERSION_10_7 },
+ { PACKED_VERSION(169,3,0), DYLD_MACOSX_VERSION_10_8 },
+ { PACKED_VERSION(1197,0,0), DYLD_MACOSX_VERSION_10_9 },
+ { PACKED_VERSION(0,0,0), DYLD_MACOSX_VERSION_10_9 }
+ };
+
+ if ( libSystemVers != 0 ) {
+ uint32_t lastOsVersion = 0;
+ for (const DylibToOSMapping* p=libSystemMapping; ; ++p) {
+ if ( p->dylibVersion == 0 )
+ return p->osVersion;
+ if ( libSystemVers < p->dylibVersion )
+ return lastOsVersion;
+ lastOsVersion = p->osVersion;
+ }
}
+#endif
return 0;
}
uint32_t dyld_get_min_os_version(const struct mach_header* mh)
{
-#if __LP64__
- const load_command* cmds = (load_command*)((char *)mh + sizeof(mach_header_64));
-#else
- const load_command* cmds = (load_command*)((char *)mh + sizeof(mach_header));
-#endif
+ const load_command* cmds = NULL;
+ if ( mh->magic == MH_MAGIC_64 )
+ cmds = (load_command*)((char *)mh + sizeof(mach_header_64));
+ else if ( mh->magic == MH_MAGIC )
+ cmds = (load_command*)((char *)mh + sizeof(mach_header));
+ else
+ return 0; // not a mach-o file, or wrong endianness
+
const version_min_command* versCmd;
const load_command* cmd = cmds;
for(uint32_t i = 0; i < mh->ncmds; ++i) {
switch ( cmd->cmd ) {
- case LC_VERSION_MIN_MACOSX:
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
case LC_VERSION_MIN_IPHONEOS:
+#else
+ case LC_VERSION_MIN_MACOSX:
+#endif
versCmd = (version_min_command*)cmd;
return versCmd->version; // found explicit min OS version
break;
return data->message;
}
+// <rdar://problem/10595338> dlerror buffer leak
+// Only allocate buffer if an actual error message needs to be set
+static bool hasPerThreadBufferFor_dlerror()
+{
+ if (!dlerrorPerThreadKeyInitialized )
+ return false;
+
+ return (pthread_getspecific(dlerrorPerThreadKey) != NULL);
+}
+
+// use non-lazy pointer to vproc_swap_integer so that lazy binding does not recurse
+typedef vproc_err_t (*vswapproc)(vproc_t vp, vproc_gsk_t key,int64_t *inval, int64_t *outval);
+static vswapproc swapProc = &vproc_swap_integer;
+
+static bool isLaunchdOwned() {
+ static bool first = true;
+ static bool result;
+ if ( first ) {
+ int64_t val = 0;
+ (*swapProc)(NULL, VPROC_GSK_IS_MANAGED, NULL, &val);
+ result = ( val != 0 );
+ first = false;
+ }
+ return result;
+}
+
#if DYLD_SHARED_CACHE_SUPPORT
static void shared_cache_missing()
}
#endif // DYLD_SHARED_CACHE_SUPPORT
-extern void* start;
// the table passed to dyld containing thread helpers
-static dyld::LibSystemHelpers sHelpers = { 9, &dyldGlobalLockAcquire, &dyldGlobalLockRelease,
+static dyld::LibSystemHelpers sHelpers = { 12, &dyldGlobalLockAcquire, &dyldGlobalLockRelease,
&getPerThreadBufferFor_dlerror, &malloc, &free, &__cxa_atexit,
#if DYLD_SHARED_CACHE_SUPPORT
&shared_cache_missing, &shared_cache_out_of_date,
&malloc_size,
&pthread_getspecific,
&__cxa_finalize,
- &start};
+ address_of_start,
+ &hasPerThreadBufferFor_dlerror,
+ &isLaunchdOwned,
+ &vm_allocate,
+ &mmap};
//
extern "C" void tlv_initializer();
extern "C" void _dyld_initializer();
void _dyld_initializer()
-{
- DYLD_LOCK_INITIALIZER;
-
+{
void (*p)(dyld::LibSystemHelpers*);
_dyld_func_lookup("__dyld_register_thread_helpers", (void**)&p);
#endif
+bool dyld_process_is_restricted()
+{
+ DYLD_NO_LOCK_THIS_BLOCK;
+ static bool (*p)() = NULL;
+
+ if(p == NULL)
+ _dyld_func_lookup("__dyld_process_is_restricted", (void**)&p);
+ return p();
+}
+
+
+
+
// SPI called __fork
void _dyld_fork_child()
{
char* __cxa_get_globals()
{
// if libSystem.dylib not yet initialized, or is old libSystem, use shared global
- if ( (_ZN4dyld17gLibSystemHelpersE == NULL) || (_ZN4dyld17gLibSystemHelpersE->version < 5) )
+ if ( (_ZN4dyld17gLibSystemHelpersE == NULL) || (_ZN4dyld17gLibSystemHelpersE->version < 7) )
return sPreMainCxaGlobals;
if ( sCxaKey == 0 ) {
// we don't need a lock because only one thread can be in dyld at a time
_ZN4dyld17gLibSystemHelpersE->pthread_key_create(&sCxaKey, &free);
}
- char* data = (char*)pthread_getspecific(sCxaKey);
+ char* data = (char*)_ZN4dyld17gLibSystemHelpersE->pthread_getspecific(sCxaKey);
if ( data == NULL ) {
data = calloc(2,sizeof(void*));
_ZN4dyld17gLibSystemHelpersE->pthread_setspecific(sCxaKey, data);
char* __cxa_get_globals_fast()
{
// if libSystem.dylib not yet initialized, or is old libSystem, use shared global
- if ( (_ZN4dyld17gLibSystemHelpersE == NULL) || (_ZN4dyld17gLibSystemHelpersE->version < 5) )
+ if ( (_ZN4dyld17gLibSystemHelpersE == NULL) || (_ZN4dyld17gLibSystemHelpersE->version < 7) )
return sPreMainCxaGlobals;
- return pthread_getspecific(sCxaKey);
+ return _ZN4dyld17gLibSystemHelpersE->pthread_getspecific(sCxaKey);
}
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
+#include <Availability.h>
#include <mach/mach.h>
#include <mach-o/loader.h>
#include <mach-o/ldsyms.h>
#include <mach-o/x86_64/reloc.h>
#endif
#include "dyld.h"
+#include "dyldSyscallInterface.h"
+
+// from dyld_gdb.cpp
+extern void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[]);
+extern void syncProcessInfo();
#ifndef MH_PIE
#define MH_PIE 0x200000
#endif
+// currently dyld has no initializers, but if some come back, set this to non-zero
+#define DYLD_INITIALIZER_SUPPORT 0
#if __LP64__
#define LC_SEGMENT_COMMAND LC_SEGMENT_64
#define POINTER_RELOC GENERIC_RELOC_VANILLA
#endif
-// from dyld.cpp
-namespace dyld { extern bool isRosetta(); };
+
+#if TARGET_IPHONE_SIMULATOR
+const dyld::SyscallHelpers* gSyscallHelpers = NULL;
+#endif
//
namespace dyldbootstrap {
+
+#if DYLD_INITIALIZER_SUPPORT
+
typedef void (*Initializer)(int argc, const char* argv[], const char* envp[], const char* apple[]);
+extern const Initializer inits_start __asm("section$start$__DATA$__mod_init_func");
+extern const Initializer inits_end __asm("section$end$__DATA$__mod_init_func");
+
//
// For a regular executable, the crt code calls dyld to run the executables initializers.
// For a static executable, crt directly runs the initializers.
//
static void runDyldInitializers(const struct macho_header* mh, intptr_t slide, int argc, const char* argv[], const char* envp[], const char* apple[])
{
- 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;
- 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_MOD_INIT_FUNC_POINTERS ){
- Initializer* inits = (Initializer*)(sect->addr + slide);
- const uint32_t count = sect->size / sizeof(uintptr_t);
- for (uint32_t i=0; i < count; ++i) {
- Initializer func = inits[i];
- func(argc, argv, envp, apple);
- }
- }
- }
- }
- break;
- }
- cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+ for (const Initializer* p = &inits_start; p < &inits_end; ++p) {
+ (*p)(argc, argv, envp, apple);
}
}
+#endif // DYLD_INITIALIZER_SUPPORT
//
extern "C" void mach_init();
-
-//
-// _pthread_keys is partitioned in a lower part that dyld will use; libSystem
-// will use the upper part. We set __pthread_tsd_first to 1 as the start of
-// the lower part. Libc will take #1 and c++ exceptions will take #2. There
-// is one free key=3 left.
-//
-extern "C" {
- extern int __pthread_tsd_first;
- extern void _pthread_keys_init();
-}
+extern "C" void __guard_setup(const char* apple[]);
//
rebaseDyld(dyldsMachHeader, slide);
}
-#if __IPHONE_OS_VERSION_MIN_REQUIRED
- // set pthread keys to dyld range
- __pthread_tsd_first = 1;
- _pthread_keys_init();
-#endif
-
// allow dyld to use mach messaging
mach_init();
while(*apple != NULL) { ++apple; }
++apple;
+ // set up random value for stack canary
+ __guard_setup(apple);
+
+#if DYLD_INITIALIZER_SUPPORT
// run all C++ initializers inside dyld
runDyldInitializers(dyldsMachHeader, slide, argc, argv, envp, apple);
-
+#endif
+
// now that we are done bootstrapping dyld, call dyld's main
uintptr_t appsSlide = slideOfMainExecutable(appsMachHeader);
return dyld::_main(appsMachHeader, appsSlide, argc, argv, envp, apple, startGlue);
}
+#if TARGET_IPHONE_SIMULATOR
+
+extern "C" uintptr_t start_sim(int argc, const char* argv[], const char* envp[], const char* apple[],
+ const macho_header* mainExecutableMH, const macho_header* dyldMH, uintptr_t dyldSlide,
+ const dyld::SyscallHelpers*, uintptr_t* startGlue);
+
+
+uintptr_t start_sim(int argc, const char* argv[], const char* envp[], const char* apple[],
+ const macho_header* mainExecutableMH, const macho_header* dyldMH, uintptr_t dyldSlide,
+ const dyld::SyscallHelpers* sc, uintptr_t* startGlue)
+{
+ // if simulator dyld loaded slid, it needs to rebase itself
+ // we have to do this before using any global variables
+ if ( dyldSlide != 0 ) {
+ rebaseDyld(dyldMH, dyldSlide);
+ }
+
+ // save table of syscall pointers
+ gSyscallHelpers = sc;
+
+ // allow dyld to use mach messaging
+ mach_init();
+
+ // set up random value for stack canary
+ __guard_setup(apple);
+
+ // setup gProcessInfo to point to host dyld's struct
+ dyld::gProcessInfo = (struct dyld_all_image_infos*)(sc->getProcessInfo());
+ syncProcessInfo();
+
+ // now that we are done bootstrapping dyld, call dyld's main
+ uintptr_t appsSlide = slideOfMainExecutable(mainExecutableMH);
+ return dyld::_main(mainExecutableMH, appsSlide, argc, argv, envp, apple, startGlue);
+}
+#endif
} // end of namespace
#include <Availability.h>
#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
void (*cxa_finalize)(const void*);
// added in version 9
void* startGlueToCallExit;
+ // added in version 10
+ bool (*hasPerThreadBufferFor_dlerror)();
+ // added in version 11
+ bool (*isLaunchdOwned)();
+ // 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);
};
#if __cplusplus
-};
+}
#endif
/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
*
- * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2012 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
-static pthread_mutex_t sGlobalMutex;
+static pthread_mutex_t sGlobalMutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
// <rdar://problem/6361143> Need a way to determine if a gdb call to dlopen() would block
int __attribute__((visibility("hidden"))) _dyld_global_lock_held = 0;
-//
-// This initializer can go away once the following is available:
-// <rdar://problem/4927311> implement PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
-//
-void dyldGlobalLockInitialize()
-{
- pthread_mutexattr_t recursiveMutexAttr;
- pthread_mutexattr_init(&recursiveMutexAttr);
- pthread_mutexattr_settype(&recursiveMutexAttr, PTHREAD_MUTEX_RECURSIVE);
- pthread_mutex_init(&sGlobalMutex, &recursiveMutexAttr);
-}
-
-
LockHelper::LockHelper()
{
dyldGlobalLockAcquire();
void dyldGlobalLockAcquire()
{
pthread_mutex_lock(&sGlobalMutex);
- _dyld_global_lock_held = 1;
+ ++_dyld_global_lock_held;
}
void dyldGlobalLockRelease()
{
- _dyld_global_lock_held = 0;
+ --_dyld_global_lock_held;
pthread_mutex_unlock(&sGlobalMutex);
}
/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
*
- * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2012 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
// }
//
-#define DYLD_LOCK_INITIALIZER dyldGlobalLockInitialize()
#define DYLD_LOCK_THIS_BLOCK LockHelper _dyld_lock;
#define DYLD_NO_LOCK_THIS_BLOCK
#include <stdint.h>
#include <string.h>
#include <mach/mach.h>
+#include <sys/mman.h>
extern "C" void* __dso_handle;
#if __LP64__
// room for about ~1000 initial dylibs
- #define DYLD_POOL_CHUNK_SIZE 200*1024
+ #define DYLD_POOL_CHUNK_SIZE 224*1024
#else
// room for about ~900 initial dylibs
#define DYLD_POOL_CHUNK_SIZE 150*1024
int _malloc_lock = 0;
+// <rdar://problem/12857033> dyld calls this which uses libSystem.dylib's vm_allocate if available
+int vm_alloc(vm_address_t* addr, vm_size_t size, uint32_t flags)
+{
+ if ( (dyld::gLibSystemHelpers != NULL) && (dyld::gLibSystemHelpers->version >= 12) ) {
+ return dyld::gLibSystemHelpers->vm_alloc(mach_task_self(), addr, size, flags);
+ }
+ else {
+ return ::vm_allocate(mach_task_self(), addr, size, flags);
+ }
+}
+
+void* xmmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset)
+{
+ if ( (dyld::gLibSystemHelpers != NULL) && (dyld::gLibSystemHelpers->version >= 12) ) {
+ return dyld::gLibSystemHelpers->mmap(addr, len, prot, flags, fd, offset);
+ }
+ else {
+ return ::mmap(addr, len, prot, flags, fd, offset);
+ }
+}
+
+
+
*/
-
- // Hack to make _offset_to_dyld_all_image_infos work
- // Without this local symbol, assembler will error out about in subtraction expression
- // The real _dyld_all_image_infos (non-weak) _dyld_all_image_infos is defined in dyld_gdb.o
- // and the linker with throw this one away and use the real one instead.
- .section __DATA,__datacoal_nt,coalesced
- .globl _dyld_all_image_infos
- .weak_definition _dyld_all_image_infos
-_dyld_all_image_infos: .long 0
-
-
+#include <TargetConditionals.h>
.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
nop
nop
nop
-_offset_to_dyld_all_image_infos:
- .long _dyld_all_image_infos - . + 0x1010
- .long 0
+
# space for future stable entry points
- .space 16
+ .space 32
-
+#if !TARGET_IPHONE_SIMULATOR
.text
.align 4, 0x90
.globl __dyld_start
movl %ebx,12(%esp) # main param4 = apple
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:
#if __x86_64__
+#if !TARGET_IPHONE_SIMULATOR
.data
.align 3
__dyld_start_static:
.quad __dyld_start
+#endif
# stable entry points into dyld
.text
nop
nop
nop
-_offset_to_dyld_all_image_infos:
- .long _dyld_all_image_infos - . + 0x1010
- .long 0
- # space for future stable entry points
- .space 16
+ # space for future stable entry points
+ .space 24
+#if !TARGET_IPHONE_SIMULATOR
.text
.align 2,0x90
.globl __dyld_start
testq %r8,%r8 # look for NULL ending env[] array
jne Lapple # main param4 = apple into %rcx
jmp *%rax # jump to main(argc,argv,env,apple) with return address set to _start
-
+
+#endif /* TARGET_IPHONE_SIMULATOR */
#endif /* __x86_64__ */
b _branch_to_lookupDyldFunction
nop
-_offset_to_dyld_all_image_infos:
- .long _dyld_all_image_infos - . + 0x1010
- .long 0
# space for future stable entry points
- .space 16
+ .space 24
// Hack to make ___dso_handle work
--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2004-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@
+ */
+
+
+#ifndef __DYLD_SYSCALL_HELPERS__
+#define __DYLD_SYSCALL_HELPERS__
+
+
+#if __cplusplus
+namespace dyld {
+#endif
+
+ //
+ // This file contains the table of function pointers the host dyld supplies
+ // to the iOS simulator dyld.
+ //
+ struct SyscallHelpers
+ {
+ uintptr_t version;
+ int (*open)(const char* path, int oflag, int extra);
+ int (*close)(int fd);
+ ssize_t (*pread)(int fd, void* buf, size_t nbyte, off_t offset);
+ ssize_t (*write)(int fd, const void* buf, size_t nbyte);
+ void* (*mmap)(void* addr, size_t len, int prot, int flags, int fd, off_t offset);
+ int (*munmap)(void* addr, size_t len);
+ int (*madvise)(void* addr, size_t len, int advice);
+ int (*stat)(const char* path, struct stat* buf);
+ int (*fcntl)(int fildes, int cmd, void* result);
+ int (*ioctl)(int fildes, unsigned long request, void* result);
+ int (*issetugid)(void);
+ char* (*getcwd)(char* buf, size_t size);
+ char* (*realpath)(const char* file_name, char* resolved_name);
+ kern_return_t (*vm_allocate)(vm_map_t target_task, vm_address_t *address, vm_size_t size, int flags);
+ kern_return_t (*vm_deallocate)(vm_map_t target_task, vm_address_t address, vm_size_t size);
+ kern_return_t (*vm_protect)(vm_map_t target_task, vm_address_t address, vm_size_t size, boolean_t max, vm_prot_t prot);
+ void (*vlog)(const char* format, va_list list);
+ void (*vwarn)(const char* format, va_list list);
+ int (*pthread_mutex_lock)(pthread_mutex_t* m);
+ int (*pthread_mutex_unlock)(pthread_mutex_t* m);
+ mach_port_t (*mach_thread_self)(void);
+ kern_return_t (*mach_port_deallocate)(ipc_space_t task, mach_port_name_t name);
+ mach_port_name_t(*task_self_trap)(void);
+ kern_return_t (*mach_timebase_info)(mach_timebase_info_t info);
+ bool (*OSAtomicCompareAndSwapPtrBarrier)(void* old, void* nw, void * volatile *value);
+ void (*OSMemoryBarrier)(void);
+ void* (*getProcessInfo)(void); // returns dyld_all_image_infos*;
+ int* (*errnoAddress)();
+ uint64_t (*mach_absolute_time)();
+ };
+
+ extern const struct SyscallHelpers* gSyscallHelpers;
+
+
+#if __cplusplus
+}
+#endif
+
+#endif
\ No newline at end of file
#include "mach-o/dyld_gdb.h"
#include "mach-o/dyld_images.h"
#include "ImageLoader.h"
+#include "dyld.h"
#if __IPHONE_OS_VERSION_MIN_REQUIRED
#define INITIAL_UUID_IMAGE_COUNT 4
#define INITIAL_UUID_IMAGE_COUNT 32
#endif
+VECTOR_NEVER_DESTRUCTED(dyld_image_info);
+VECTOR_NEVER_DESTRUCTED(dyld_uuid_info);
+
static std::vector<dyld_image_info> sImageInfos;
static std::vector<dyld_uuid_info> sImageUUIDs;
+
void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[])
{
// make initial size large enough that we probably won't need to re-alloc it
if ( sImageUUIDs.capacity() == 0 )
sImageUUIDs.reserve(4);
// set infoArray to NULL to denote it is in-use
- dyld_all_image_infos.infoArray = NULL;
+ dyld::gProcessInfo->infoArray = NULL;
// append all new images
for (uint32_t i=0; i < infoCount; ++i)
sImageInfos.push_back(info[i]);
- dyld_all_image_infos.infoArrayCount = sImageInfos.size();
+ dyld::gProcessInfo->infoArrayCount = sImageInfos.size();
// set infoArray back to base address of vector (other process can now read)
- dyld_all_image_infos.infoArray = &sImageInfos[0];
+ dyld::gProcessInfo->infoArray = &sImageInfos[0];
}
+#if TARGET_IPHONE_SIMULATOR
+// called once in dyld_sim start up to copy image list from host dyld to sImageInfos
+void syncProcessInfo()
+{
+ // may want to set version field of gProcessInfo if it might be different than host
+ if ( sImageInfos.size() == 0 ) {
+ sImageInfos.reserve(INITIAL_IMAGE_COUNT);
+ if ( dyld::gProcessInfo->infoArray != NULL ) {
+ for (uint32_t i=0; i < dyld::gProcessInfo->infoArrayCount; ++i) {
+ sImageInfos.push_back(dyld::gProcessInfo->infoArray[i]);
+ }
+ dyld::gProcessInfo->infoArray = &sImageInfos[0];
+ dyld::gProcessInfo->infoArrayCount = sImageInfos.size();
+ }
+ }
+ dyld::gProcessInfo->notification(dyld_image_info_change, 0, NULL);
+}
+#endif
const char* notifyGDB(enum dyld_image_states state, uint32_t infoCount, const dyld_image_info info[])
{
// tell gdb that about the new images
- dyld_all_image_infos.notification(dyld_image_adding, infoCount, info);
+ dyld::gProcessInfo->notification(dyld_image_adding, infoCount, info);
// <rdar://problem/7739489> record initial count of images
// so CrashReporter can note which images were dynamically loaded
- if ( dyld_all_image_infos.initialImageCount == 0 )
- dyld_all_image_infos.initialImageCount = infoCount;
+ if ( dyld::gProcessInfo->initialImageCount == 0 )
+ dyld::gProcessInfo->initialImageCount = infoCount;
return NULL;
}
void addNonSharedCacheImageUUID(const dyld_uuid_info& info)
{
// set uuidArray to NULL to denote it is in-use
- dyld_all_image_infos.uuidArray = NULL;
+ dyld::gProcessInfo->uuidArray = NULL;
// append all new images
sImageUUIDs.push_back(info);
- dyld_all_image_infos.uuidArrayCount = sImageUUIDs.size();
+ dyld::gProcessInfo->uuidArrayCount = sImageUUIDs.size();
// set uuidArray back to base address of vector (other process can now read)
- dyld_all_image_infos.uuidArray = &sImageUUIDs[0];
+ dyld::gProcessInfo->uuidArray = &sImageUUIDs[0];
}
void removeImageFromAllImages(const struct mach_header* loadAddress)
dyld_image_info goingAway;
// set infoArray to NULL to denote it is in-use
- dyld_all_image_infos.infoArray = NULL;
+ dyld::gProcessInfo->infoArray = NULL;
// remove image from infoArray
for (std::vector<dyld_image_info>::iterator it=sImageInfos.begin(); it != sImageInfos.end(); it++) {
break;
}
}
- dyld_all_image_infos.infoArrayCount = sImageInfos.size();
+ dyld::gProcessInfo->infoArrayCount = sImageInfos.size();
// set infoArray back to base address of vector
- dyld_all_image_infos.infoArray = &sImageInfos[0];
+ dyld::gProcessInfo->infoArray = &sImageInfos[0];
// set uuidArrayCount to NULL to denote it is in-use
- dyld_all_image_infos.uuidArray = NULL;
+ dyld::gProcessInfo->uuidArray = NULL;
// remove image from infoArray
for (std::vector<dyld_uuid_info>::iterator it=sImageUUIDs.begin(); it != sImageUUIDs.end(); it++) {
break;
}
}
- dyld_all_image_infos.uuidArrayCount = sImageUUIDs.size();
+ dyld::gProcessInfo->uuidArrayCount = sImageUUIDs.size();
// set infoArray back to base address of vector
- dyld_all_image_infos.uuidArray = &sImageUUIDs[0];
+ dyld::gProcessInfo->uuidArray = &sImageUUIDs[0];
// tell gdb that about the new images
- dyld_all_image_infos.notification(dyld_image_removing, 1, &goingAway);
+ dyld::gProcessInfo->notification(dyld_image_removing, 1, &goingAway);
}
-#if __arm__
-// work around for: <rdar://problem/6530727> gdb-1109: notifier in dyld does not work if it is in thumb
-extern "C" void gdb_image_notifier(enum dyld_image_mode mode, uint32_t infoCount, const dyld_image_info info[]);
-#else
-static void gdb_image_notifier(enum dyld_image_mode mode, uint32_t infoCount, const dyld_image_info info[])
-{
- // do nothing
- // gdb sets a break point here to catch notifications
- //dyld::log("dyld: gdb_image_notifier(%s, %d, ...)\n", mode ? "dyld_image_removing" : "dyld_image_adding", infoCount);
- //for (uint32_t i=0; i < infoCount; ++i)
- // dyld::log("dyld: %d loading at %p %s\n", i, info[i].imageLoadAddress, info[i].imageFilePath);
- //for (uint32_t i=0; i < dyld_all_image_infos.infoArrayCount; ++i)
- // dyld::log("dyld: %d loading at %p %s\n", i, dyld_all_image_infos.infoArray[i].imageLoadAddress, dyld_all_image_infos.infoArray[i].imageFilePath);
-}
-#endif
-
void setAlImageInfosHalt(const char* message, uintptr_t flags)
{
- dyld_all_image_infos.errorMessage = message;
- dyld_all_image_infos.terminationFlags = flags;
+ dyld::gProcessInfo->errorMessage = message;
+ dyld::gProcessInfo->terminationFlags = flags;
}
-extern void* __dso_handle;
-#define STR(s) # s
-#define XSTR(s) STR(s)
+#if TARGET_IPHONE_SIMULATOR
+ namespace dyld {
+ struct dyld_all_image_infos* gProcessInfo = NULL;
+ }
+#else
-struct dyld_all_image_infos dyld_all_image_infos __attribute__ ((section ("__DATA,__all_image_info")))
- = {
- 12, 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
- };
+ #if __arm__
+ // work around for: <rdar://problem/6530727> gdb-1109: notifier in dyld does not work if it is in thumb
+ extern "C" void gdb_image_notifier(enum dyld_image_mode mode, uint32_t infoCount, const dyld_image_info info[]);
+ #else
+ static void gdb_image_notifier(enum dyld_image_mode mode, uint32_t infoCount, const dyld_image_info info[])
+ {
+ // do nothing
+ // gdb sets a break point here to catch notifications
+ //dyld::log("dyld: gdb_image_notifier(%s, %d, ...)\n", mode ? "dyld_image_removing" : "dyld_image_adding", infoCount);
+ //for (uint32_t i=0; i < infoCount; ++i)
+ // dyld::log("dyld: %d loading at %p %s\n", i, info[i].imageLoadAddress, info[i].imageFilePath);
+ //for (uint32_t i=0; i < dyld::gProcessInfo->infoArrayCount; ++i)
+ // dyld::log("dyld: %d loading at %p %s\n", i, dyld::gProcessInfo->infoArray[i].imageLoadAddress, dyld::gProcessInfo->infoArray[i].imageFilePath);
+ }
+ #endif
+
+ extern void* __dso_handle;
+ #define STR(s) # s
+ #define XSTR(s) STR(s)
-struct dyld_shared_cache_ranges dyld_shared_cache_ranges;
+ struct dyld_all_image_infos dyld_all_image_infos __attribute__ ((section ("__DATA,__all_image_info")))
+ = {
+ 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
+ };
+ struct dyld_shared_cache_ranges dyld_shared_cache_ranges;
+ namespace dyld {
+ struct dyld_all_image_infos* gProcessInfo = &dyld_all_image_infos;
+ }
+#endif
--- /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@
+#
+
+#
+# Be sure the following are not dead stripped
+#
+
+# Used by various tools to see build number of dyld
+_dyld_simVersionString
+_dyld_simVersionNumber
+
/*
- * Copyright (c) 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2008-2013 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* @APPLE_LICENSE_HEADER_END@
*/
+#include <TargetConditionals.h>
+#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__
movl %eax,LP_LOCAL(%esp)
movl %ebp,LP_OLD_BP_SAVE(%esp) # store epb back chain
movl %esp,%ebp # set epb to be this frame
- add $LP_OLD_BP_SAVE,%ebp
+ add $LP_OLD_BP_SAVE,%ebp
movl %ecx,ECX_SAVE(%esp)
movl %edx,EDX_SAVE(%esp)
.align 0,0x90
#define R8_SAVE 32
#define R9_SAVE 40
#define RAX_SAVE 48
-#define XMMM0_SAVE 64 /* 16-byte align */
-#define XMMM1_SAVE 80
-#define XMMM2_SAVE 96
-#define XMMM3_SAVE 112
-#define XMMM4_SAVE 128
-#define XMMM5_SAVE 144
-#define XMMM6_SAVE 160
-#define XMMM7_SAVE 176
-#define STACK_SIZE 192 /* (XMMM7_SAVE+16) must be 16 byte aligned too */
-
+#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
+
/*
* sp+4 lazy binding info offset
movq %r9,R9_SAVE(%rsp)
movq %rax,RAX_SAVE(%rsp)
misaligned_stack_error_entering_dyld_stub_binder:
- movdqa %xmm0,XMMM0_SAVE(%rsp)
- movdqa %xmm1,XMMM1_SAVE(%rsp)
- movdqa %xmm2,XMMM2_SAVE(%rsp)
- movdqa %xmm3,XMMM3_SAVE(%rsp)
- movdqa %xmm4,XMMM4_SAVE(%rsp)
- movdqa %xmm5,XMMM5_SAVE(%rsp)
- movdqa %xmm6,XMMM6_SAVE(%rsp)
- movdqa %xmm7,XMMM7_SAVE(%rsp)
+ 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
call __Z21_dyld_fast_stub_entryPvl
movq %rax,%r11 # save target
- movdqa XMMM0_SAVE(%rsp),%xmm0 # restore registers
- movdqa XMMM1_SAVE(%rsp),%xmm1
- movdqa XMMM2_SAVE(%rsp),%xmm2
- movdqa XMMM3_SAVE(%rsp),%xmm3
- movdqa XMMM4_SAVE(%rsp),%xmm4
- movdqa XMMM5_SAVE(%rsp),%xmm5
- movdqa XMMM6_SAVE(%rsp),%xmm6
- movdqa XMMM7_SAVE(%rsp),%xmm7
- movq RDI_SAVE(%rsp),%rdi
+ 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
#endif /* __arm__ */
+
+
+// simulator does not have full libdyld.dylib - just a small libdyld_sim.dylib
+#endif // ! TARGET_IPHONE_SIMULATOR
#include <string.h>
#include <stdint.h>
#include <time.h>
+#include <fcntl.h>
#include <unistd.h>
#include <stdarg.h>
#include <stdio.h>
-#include <mach/mach_error.h>
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <TargetConditionals.h>
+#include <libkern/OSAtomic.h>
+#include <errno.h>
+#include <pthread.h>
+#if TARGET_IPHONE_SIMULATOR
+ #include "dyldSyscallInterface.h"
+#endif
// from _simple.h in libc
typedef struct _SIMPLE* _SIMPLE_STRING;
// make our own custom ones.
//
long __stack_chk_guard = 0;
-static __attribute__((constructor))
-void __guard_setup(int argc, const char* argv[], const char* envp[], const char* apple[])
+
+
+void __guard_setup(const char* apple[])
{
for (const char** p = apple; *p != NULL; ++p) {
if ( strncmp(*p, "stack_guard=", 12) == 0 ) {
return;
}
}
-
+#if !TARGET_IPHONE_SIMULATOR
#if __LP64__
__stack_chk_guard = ((long)arc4random() << 32) | arc4random();
#else
__stack_chk_guard = arc4random();
#endif
+#endif
}
+
extern void _ZN4dyld4haltEPKc(const char*);
void __stack_chk_fail()
{
return b;
}
+
+// <rdar://problem/10111032> wrap calls to stat() with check for EAGAIN
+int _ZN4dyld7my_statEPKcP4stat(const char* path, struct stat* buf)
+{
+ int result;
+ do {
+ result = stat(path, buf);
+ } while ((result == -1) && (errno == EAGAIN));
+
+ return result;
+}
+
+// <rdar://problem/13805025> dyld should retry open() if it gets an EGAIN
+int _ZN4dyld7my_openEPKcii(const char* path, int flag, int other)
+{
+ int result;
+ do {
+ result = open(path, flag, other);
+ } while ((result == -1) && (errno == EAGAIN));
+
+ return result;
+}
+
+
+//
+// The dyld in the iOS simulator cannot do syscalls, so it calls back to
+// host dyld.
+//
+
+#if TARGET_IPHONE_SIMULATOR
+int myopen(const char* path, int oflag, int extra) __asm("_open");
+int myopen(const char* path, int oflag, int extra) {
+ return gSyscallHelpers->open(path, oflag, extra);
+}
+
+int close(int fd) {
+ return gSyscallHelpers->close(fd);
+}
+
+ssize_t pread(int fd, void* buf, size_t nbytes, off_t offset) {
+ return gSyscallHelpers->pread(fd, buf , nbytes, offset);
+}
+
+ssize_t write(int fd, const void *buf, size_t nbytes) {
+ return gSyscallHelpers->write(fd, buf , nbytes);
+}
+
+void* mmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset) {
+ return gSyscallHelpers->mmap(addr, len, prot, flags, fd, offset);
+}
+
+int munmap(void* addr, size_t len) {
+ return gSyscallHelpers->munmap(addr, len);
+}
+
+int madvise(void* addr, size_t len, int advice) {
+ return gSyscallHelpers->madvise(addr, len, advice);
+}
+
+int stat(const char* path, struct stat* buf) {
+ return gSyscallHelpers->stat(path, buf);
+}
+
+int myfcntl(int fd, int cmd, void* result) __asm("_fcntl");
+int myfcntl(int fd, int cmd, void* result) {
+ return gSyscallHelpers->fcntl(fd, cmd, result);
+}
+
+int myioctl(int fd, unsigned long request, void* result) __asm("_ioctl");
+int myioctl(int fd, unsigned long request, void* result) {
+ return gSyscallHelpers->ioctl(fd, request, result);
+}
+
+int issetugid() {
+ return gSyscallHelpers->issetugid();
+}
+
+char* getcwd(char* buf, size_t size) {
+ return gSyscallHelpers->getcwd(buf, size);
+}
+
+char* realpath(const char* file_name, char* resolved_name) {
+ return gSyscallHelpers->realpath(file_name, resolved_name);
+}
+
+
+
+kern_return_t vm_allocate(vm_map_t target_task, vm_address_t *address,
+ vm_size_t size, int flags) {
+ return gSyscallHelpers->vm_allocate(target_task, address, size, flags);
+}
+
+kern_return_t vm_deallocate(vm_map_t target_task, vm_address_t address,
+ vm_size_t size) {
+ return gSyscallHelpers->vm_deallocate(target_task, address, size);
+}
+
+kern_return_t vm_protect(vm_map_t target_task, vm_address_t address,
+ vm_size_t size, boolean_t max, vm_prot_t prot) {
+ return gSyscallHelpers->vm_protect(target_task, address, size, max, prot);
+}
+
+
+void _ZN4dyld3logEPKcz(const char* format, ...) {
+ va_list list;
+ va_start(list, format);
+ gSyscallHelpers->vlog(format, list);
+ va_end(list);
+}
+
+void _ZN4dyld4warnEPKcz(const char* format, ...) {
+ va_list list;
+ va_start(list, format);
+ gSyscallHelpers->vwarn(format, list);
+ va_end(list);
+}
+
+
+int pthread_mutex_lock(pthread_mutex_t* m) {
+ return gSyscallHelpers->pthread_mutex_lock(m);
+}
+
+int pthread_mutex_unlock(pthread_mutex_t* m) {
+ return gSyscallHelpers->pthread_mutex_unlock(m);
+}
+
+mach_port_t mach_thread_self() {
+ return gSyscallHelpers->mach_thread_self();
+}
+
+kern_return_t mach_port_deallocate(ipc_space_t task, mach_port_name_t name) {
+ return gSyscallHelpers->mach_port_deallocate(task, name);
+}
+
+mach_port_name_t task_self_trap() {
+ return gSyscallHelpers->task_self_trap();
+}
+
+kern_return_t mach_timebase_info(mach_timebase_info_t info) {
+ return gSyscallHelpers->mach_timebase_info(info);
+}
+
+bool OSAtomicCompareAndSwapPtrBarrier(void* old, void* new, void * volatile *value) {
+ return gSyscallHelpers->OSAtomicCompareAndSwapPtrBarrier(old, new, value);
+}
+
+void OSMemoryBarrier() {
+ return gSyscallHelpers->OSMemoryBarrier();
+}
+
+uint64_t mach_absolute_time(void) {
+ return gSyscallHelpers->mach_absolute_time();
+}
+
+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;
+
+extern int myerrno_fallback __asm("_errno");
+int myerrno_fallback = 0;
+
+#endif // TARGET_IPHONE_SIMULATOR
+
+
--- /dev/null
+_dyld_get_sdk_version
+_dyld_get_program_sdk_version
+_dyld_get_min_os_version
+_dyld_get_program_min_os_version
+
--- /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@
+ */
+
+#ifndef __START_GLUE_H__
+#define __START_GLUE_H__
+
+// Implemented in start_glue.s
+extern "C" void start();
+
+
+// <rdar://problem/12792039> need 'start' to be one atom, but entry is in interior
+
+#if __x86_64__ || __i386__
+ #define address_of_start (void*)((uintptr_t)&start + 1)
+#elif __arm__
+ #define address_of_start (void*)((uintptr_t)&start + 2)
+#endif
+
+
+
+#endif // __START_GLUE_H__
.align 2
.globl _start
.private_extern _start
-start:
- nop # <rdar://problem/10753356> backtraces of LC_MAIN binaries don't end in "start"
_start:
+ nop # <rdar://problem/10753356> backtraces of LC_MAIN binaries don't end in "start"
+Lstart:
movl %eax,(%esp) # pass result from main() to exit()
call _exit
hlt
-
+
#endif /* __i386__ */
.align 2
.globl _start
.private_extern _start
-start:
- nop # <rdar://problem/10753356> backtraces of LC_MAIN binaries don't end in "start"
_start:
+ nop # <rdar://problem/10753356> backtraces of LC_MAIN binaries don't end in "start"
+Lstart:
movl %eax,%edi # pass result from main() to exit()
call _exit
hlt
#if __arm__
.align 2
+ .code 16
.globl _start
.private_extern _start
-start:
- nop // <rdar://problem/10753356> backtraces of LC_MAIN binaries don't end in "start"
+ .thumb_func _start
_start:
+ nop // <rdar://problem/10753356> backtraces of LC_MAIN binaries don't end in "start"
+Lstart:
bl _exit // result in r0 already in param reg r0
trap
#endif /* __arm__ */
+ .subsections_via_symbols
+
/*
- * Copyright (c) 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2010-2013 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* @APPLE_LICENSE_HEADER_END@
*/
-
-
+#include <System/machine/cpu_capabilities.h>
+
+// 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
+
.globl _tlv_get_addr
.private_extern _tlv_get_addr
_tlv_get_addr:
LlazyAllocate:
pushq %rbp
movq %rsp, %rbp
- subq $592,%rsp
+ 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 %r9,-48(%rbp)
movq %r10,-56(%rbp)
movq %r11,-64(%rbp)
- fxsave -592(%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
- fxrstor -592(%rbp)
- movq -64(%rbp),%r11
+ call _tlv_allocate_and_initialize_for_key
+
+ 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 -16(%rbp),%rsi
movq -8(%rbp),%rdi
addq 16(%rdi),%rax // result = buffer + offset
- addq $592,%rsp
+ addq $STACK_SIZE,%rsp
popq %rbp
ret
#endif
#endif
#endif
+ .subsections_via_symbols
+
#define MH_HAS_TLV_DESCRIPTORS 0x800000
#endif
-#if __i386__ || __x86_64__
+
+typedef void (*TermFunc)(void*);
+
+
+
+#if __has_feature(tls)
typedef struct TLVHandler {
struct TLVHandler *next;
void* tlv_allocate_and_initialize_for_key(pthread_key_t key)
{
const struct mach_header* mh = tlv_get_image_for_key(key);
+ if ( mh == NULL )
+ return NULL; // if data structures are screwed up, don't crash
+
// first pass, find size and template
uint8_t* start = NULL;
- unsigned long size;
+ unsigned long size = 0;
intptr_t slide = 0;
bool slideComputed = false;
bool hasInitializers = false;
// destructor key to come before the deallocation key.
//
-typedef void (*TermFunc)(void*);
struct TLVTerminatorListEntry
{
TermFunc termFunc;
}
}
-// called by pthreads when the current thread is going way and
+// called by pthreads when the current thread is going away and
// _tlv_atexit() has been called on the thread.
static void tlv_finalize(void* storage)
{
struct TLVTerminatorList* list = (struct TLVTerminatorList*)storage;
- for(uint32_t i=0; i < list->useCount; ++i) {
- struct TLVTerminatorListEntry* entry = &list->entries[i];
+ // destroy in reverse order of construction
+ for(uint32_t i=list->useCount; i > 0 ; --i) {
+ struct TLVTerminatorListEntry* entry = &list->entries[i-1];
if ( entry->termFunc != NULL ) {
(*entry->termFunc)(entry->objAddr);
}
free(storage);
}
+// <rdar://problem/13741816>
+// called by exit() before it calls cxa_finalize() so that thread_local
+// objects are destroyed before global objects.
+void _tlv_exit()
+{
+ void* termFuncs = pthread_getspecific(tlv_terminators_key);
+ if ( termFuncs != NULL )
+ tlv_finalize(termFuncs);
+}
+
__attribute__((visibility("hidden")))
void tlv_initializer()
}
-// __i386__ || __x86_64__
+
#else
-// !(__i386__ || __x86_64__)
+
void dyld_register_tlv_state_change_handler(enum dyld_tlv_states state, dyld_tlv_state_change_handler handler)
{
}
+void _tlv_exit()
+{
+}
+
+void _tlv_atexit(TermFunc func, void* objAddr)
+{
+}
+
__attribute__((visibility("hidden")))
void tlv_initializer()
{
}
-// !(__i386__ || __x86_64__)
-#endif
+
+#endif // __has_feature(tls)
IOSROOT =
ifeq "$(OS_NAME)" "iPhoneOS"
- IOSROOT = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.Internal.sdk
- CC = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/cc -arch ${ARCH} -miphoneos-version-min=$(OS_VERSION) -isysroot $(IOSROOT)
- CXX = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/c++ -arch ${ARCH} -miphoneos-version-min=$(OS_VERSION) -isysroot $(IOSROOT)
+ #IOSROOT = $(shell xcodebuild -version -sdk iphoneos.internal Path)
+ IOSROOT = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.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)
+ STRIP = $(shell xcrun -sdk iphoneos.internal -find strip)
+ INSTALL_NAME_TOOL = $(shell xcrun -sdk iphoneos.internal -find install_name_tool)
else
- CC = cc -arch ${ARCH} -mmacosx-version-min=$(OS_VERSION)
- CXX = c++ -arch ${ARCH} -mmacosx-version-min=$(OS_VERSION)
+ CC = $(shell xcrun -find cc) -arch ${ARCH} -mmacosx-version-min=$(OS_VERSION)
+ CXX = $(shell xcrun -find c++) -arch ${ARCH} -mmacosx-version-min=$(OS_VERSION)
+ LIPO = $(shell xcrun -find lipo)
+ STRIP = $(shell xcrun -find strip)
+ INSTALL_NAME_TOOL = $(shell xcrun -find install_name_tool)
endif
CCFLAGS = -Wall -std=c99
else
FILEARCH = $(ARCH)
endif
+
defaults write com.apple.CrashReporter DialogType basic
# run test targeting different OS versions
-for OSVERSION in 10.8 10.7 10.6 10.5 10.4
+for OSVERSION in 10.9 10.8 10.7 10.6 10.5 10.4
do
echo ""
echo " * * * Running all unit tests i386 built for $OSVERSION * * *"
check-macosx:
./main 10
- export DYLD_VERSIONED_FRAMEWORK_PATH="${PWD}/alt11" && ./main 11
+ export DYLD_VERSIONED_FRAMEWORK_PATH="${PWD}/alt11" && ./main 11 "alt11/Foo.framework/Versions/A/Foo"
export DYLD_VERSIONED_FRAMEWORK_PATH="${PWD}/alt9" && ./main 10
export DYLD_VERSIONED_FRAMEWORK_PATH="${PWD}/alt9:${PWD}/alt11" && ./main 11
export DYLD_VERSIONED_FRAMEWORK_PATH="${PWD}/alt11:${PWD}/alt12" && ./main 12
all:
- mkdir -p Foo.framework alt11/Foo.framework alt9/Foo.framework alt12/Foo.framework
+ mkdir -p Foo.framework alt11/Foo.framework/Versions/A alt9/Foo.framework alt12/Foo.framework
${CC} ${CCFLAGS} -dynamiclib foo.c -DRESULT=10 -current_version 10 -install_name "${PWD}/Foo.framework/Foo" -o Foo.framework/Foo
${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c Foo.framework/Foo
- ${CC} ${CCFLAGS} -dynamiclib foo.c -DRESULT=11 -current_version 11 -install_name "${PWD}/Foo.framework/Foo" -o alt11/Foo.framework/Foo
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -DRESULT=11 -current_version 11 -install_name "${PWD}/Foo.framework/Foo" -o alt11/Foo.framework/Versions/A/Foo
+ cd alt11/Foo.framework && ln -sf Versions/A/Foo
${CC} ${CCFLAGS} -dynamiclib foo.c -DRESULT=9 -current_version 9 -install_name "${PWD}/Foo.framework/Foo" -o alt9/Foo.framework/Foo
${CC} ${CCFLAGS} -dynamiclib foo.c -DRESULT=12 -current_version 12 -install_name "${PWD}/Foo.framework/Foo" -o alt12/Foo.framework/Foo
#include <dlfcn.h>
#include <string.h>
#include <stdlib.h> // for atoi()
+#include <mach-o/dyld.h>
#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
int main(int argc, const char* argv[])
{
#if __MAC_OS_X_VERSION_MIN_REQUIRED
+ if ( argc > 2 ) {
+ bool found = false;
+ uint32_t count = _dyld_image_count();
+ for(uint32_t i=0; i < count; ++i) {
+ const char* name = _dyld_get_image_name(i);
+ if ( strstr(name, argv[2]) != NULL )
+ found = true;
+ //fprintf(stderr, "image[%d]=%s\n", i, name);
+ }
+ if ( !found ) {
+ FAIL("DYLD_VERSIONED_FRAMEWORK_PATH-basic dylib has wrong path");
+ return EXIT_SUCCESS;
+ }
+ }
+
int expectedResult = atoi(argv[1]);
int actualResult = foo();
//fprintf(stderr, "foo() returned %d, expected %d\n", actualResult, expectedResult);
--- /dev/null
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# verify addends work
+#
+
+all-check: all check
+
+check:
+ ./main
+
+all:
+
+ ${CC} ${CCFLAGS} foo.c abs.s -dynamiclib -o libfoo.dylib
+ ${CC} ${CCFLAGS} -I${TESTROOT}/include libfoo.dylib -o main main.c
+
+
+clean:
+ ${RM} ${RMFLAGS} *~ main libfoo.dylib
+
--- /dev/null
+
+ .global _myAbs1
+_myAbs1 = 0
+
+
+
+ .global _myAbs2
+_myAbs2 = 1
+
+
+
+_myLocalAbs = 3
--- /dev/null
+
+
+int var = 5;
+void func() { }
+
--- /dev/null
+#include <stdio.h> // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+extern int var;
+extern void func();
+extern int myAbs1 __attribute__((weak_import));
+extern int myAbs2;
+
+
+int main()
+{
+
+ if (&myAbs1 != 0 ) {
+ FAIL("absolute-symbol: &myAbs1 != 0");
+ return 0;
+ }
+
+
+ if ((uintptr_t)&myAbs2 != 1 ) {
+ FAIL("absolute-symbol: &myAbs2 != 1");
+ return 0;
+ }
+
+
+ PASS("absolute-symbol");
+ return 0;
+}
/*
- * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2006-2012 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
foo(stackSize, stackStart);
}
-#if __ppc__
-static bool isRosetta()
-{
- int mib[] = { CTL_KERN, KERN_CLASSIC, getpid() };
- int is_classic = 0;
- size_t len = sizeof(int);
- int ret = sysctl(mib, 3, &is_classic, &len, NULL, 0);
- if ((ret != -1) && is_classic) {
- // we're running under Rosetta
- return true;
- }
- return false;
-}
-#endif
int
main()
{
char start;
-#if __ppc__
- // programs running under rosetta cannot use large amounts of stack
- if ( isRosetta() )
- foo(0x02000000, &start);
- else
-#endif
- foo(STACK_SIZE, &start);
+ foo(STACK_SIZE, &start);
return EXIT_SUCCESS;
}
TESTROOT = ../..
include ${TESTROOT}/include/common.makefile
-FATFLAGS = $(shell lipo -detailed_info $(IOSROOT)/usr/lib/libSystem.B.dylib | grep architecture | sed -e 's/architecture/-arch/')
+FATFLAGS = $(shell ${LIPO} -detailed_info $(IOSROOT)/usr/lib/libSystem.B.dylib | grep architecture | sed -e 's/architecture/-arch/')
all-check: all check
--- /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
+
+all-check: all check
+
+check:
+ ./main
+
+all:
+ ${CXX} ${CXXFLAGS} -bundle -o test.bundle bundle.cxx
+ ${CC} ${CCFLAGS} -Wno-deprecated-declarations -I${TESTROOT}/include -o main main.c
+
+clean:
+ ${RM} ${RMFLAGS} *~ main test.bundle
+
--- /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 <stdlib.h>
+
+
+class Foo {
+public:
+ Foo() { buffer = malloc(100); }
+ ~Foo() { free(buffer); }
+ void* get() { return buffer; }
+private:
+ void* buffer;
+
+};
+
+
+Foo myObject;
+
--- /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>
+#include <stdbool.h>
+#include <mach-o/dyld.h>
+#include <Availability.h>
+
+#include "test.h" // PASS(), FAIL()
+
+typedef bool (*CheckFunc)();
+
+int main()
+{
+// NSCreateObjectFileImageFromMemory is only available on Mac OS X - not iPhone OS
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+ NSObjectFileImage ofi;
+ if ( NSCreateObjectFileImageFromFile("test.bundle", &ofi) != NSObjectFileImageSuccess ) {
+ FAIL("NSCreateObjectFileImageFromFile failed");
+ return 1;
+ }
+
+ NSModule mod = NSLinkModule(ofi, "test.bundle", NSLINKMODULE_OPTION_NONE);
+ if ( mod == NULL ) {
+ FAIL("NSLinkModule failed");
+ return 1;
+ }
+
+
+ if ( !NSUnLinkModule(mod, NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED) ) {
+ FAIL("NSUnLinkModule failed");
+ return 1;
+ }
+
+ if ( !NSDestroyObjectFileImage(ofi) ) {
+ FAIL("NSDestroyObjectFileImage failed");
+ return 1;
+ }
+
+#endif
+
+ PASS("bundle-terminator");
+ return 0;
+}
\ No newline at end of file
${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c -w
main.stripped: main
- strip main -o main.stripped
+ ${STRIP} main -o main.stripped
main-setuid: main
cp main main-setuid
${CC} ${CCFLAGS} -I${TESTROOT}/include $(CRTLIB) -o main main.c
main.stripped: main
- strip main -o main.stripped
+ ${STRIP} main -o main.stripped
clean:
${RM} ${RMFLAGS} *~ main main.stripped
all:
${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
- strip main
+ ${STRIP} main
clean:
--- /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
+
+all-check: all check
+
+check:
+ ./main
+
+all:
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib
+ ${CC} ${CCFLAGS} -dynamiclib baz.c -o libbaz.dylib
+ ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c -o main
+
+
+clean:
+ ${RM} ${RMFLAGS} *~ main libfoo.dylib libbar.dylib libbaz.dylib
+
--- /dev/null
+__attribute__((weak))
+int mydata;
+
+
+int bar()
+{
+ return mydata;
+}
--- /dev/null
+__attribute__((weak))
+int mydata;
+
+
+int baz()
+{
+ return mydata;
+}
--- /dev/null
+__attribute__((weak))
+int mydata;
+
+
+int foo()
+{
+ return mydata;
+}
--- /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()
+
+
+
+
+int main()
+{
+ Dl_info info;
+
+ // load foo
+ void* handleFoo = dlopen("libfoo.dylib", RTLD_LAZY);
+ if ( handleFoo == NULL ) {
+ FAIL("dlclose-dylib-dynamic-ref: dlopen(\"libfoo.dylib\", RTLD_LAZY) failed with dlerror()=%s", dlerror());
+ exit(0);
+ }
+
+ // load bar
+ void* handleBar = dlopen("libbar.dylib", RTLD_LAZY);
+ if ( handleBar == NULL ) {
+ FAIL("dlclose-dylib-dynamic-ref: dlopen(\"libbar.dylib\", RTLD_LAZY) failed with dlerror()=%s", dlerror());
+ exit(0);
+ }
+
+ // load baz
+ void* handleBaz = dlopen("libbaz.dylib", RTLD_LAZY);
+ if ( handleBaz == NULL ) {
+ FAIL("dlclose-dylib-dynamic-ref: dlopen(\"libbaz.dylib\", RTLD_LAZY) failed with dlerror()=%s", dlerror());
+ exit(0);
+ }
+
+
+ void* sym_foo = dlsym(handleFoo, "foo");
+ if ( sym_foo == NULL ) {
+ FAIL("dlclose-dylib-dynamic-ref: dlsym(handleFoo, \"foo\") failed");
+ exit(0);
+ }
+
+ void* sym_bar = dlsym(handleBar, "bar");
+ if ( sym_bar == NULL ) {
+ FAIL("dlclose-dylib-dynamic-ref: dlsym(handleBar, \"bar\") failed");
+ exit(0);
+ }
+
+ void* sym_baz = dlsym(handleBaz, "baz");
+ if ( sym_baz == NULL ) {
+ FAIL("dlclose-dylib-dynamic-ref: dlsym(handleBaz, \"baz\") failed");
+ exit(0);
+ }
+
+ // since foo loaded first, bar and baz should have a dynamic reference to foo because all
+ // the weak mydata symbols were coaleseced to the one in foo.
+
+
+ if ( dlclose(handleFoo) != 0 ) {
+ FAIL("dlclose-dylib-dynamic-ref: dlclose(handleBar) != 0, dlerrr()=%s", dlerror());
+ exit(0);
+ }
+
+ // sym_foo should still be accessible via dladdr() because libbar and libbaz
+ // have dynamic references to libfoo.
+ if ( dladdr(sym_foo, &info) == 0 ) {
+ FAIL("dlclose-dylib-dynamic-ref: dladdr(sym_base) == 0, but should have succeeded");
+ exit(0);
+ }
+
+
+ if ( dlclose(handleBar) != 0 ) {
+ FAIL("dlclose-dylib-dynamic-ref: dlclose(handleBar) != 0, dlerrr()=%s", dlerror());
+ exit(0);
+ }
+
+
+ // sym_bar should not be accessible via dladdr() because libbar was dlclose'ed
+ if ( dladdr(sym_bar, &info) != 0 ) {
+ FAIL("dlclose-dylib-dynamic-ref: dladdr(sym_bar) != 0, but should have failed");
+ exit(0);
+ }
+
+ // sym_foo should still be accessible via dladdr() because of external libbaz
+ // has a dynamic references to libfoo.
+ if ( dladdr(sym_foo, &info) == 0 ) {
+ FAIL("dlclose-dylib-dynamic-ref: dladdr(sym_base) == 0, but should have succeeded");
+ exit(0);
+ }
+
+
+ if ( dlclose(handleBaz) != 0 ) {
+ FAIL("dlclose-dylib-dynamic-ref: dlclose(handleBar) != 0, dlerrr()=%s", dlerror());
+ exit(0);
+ }
+
+ // sym_baz should not be accessible via dladdr() because libbar was dlclose'ed
+ if ( dladdr(sym_baz, &info) != 0 ) {
+ FAIL("dlclose-dylib-dynamic-ref: dladdr(sym_baz) != 0, but should have failed");
+ exit(0);
+ }
+
+
+ // sym_foo should finally be inaccessible via dladdr() because all dynamic references to libfoo are gone
+ if ( dladdr(sym_foo, &info) != 0 ) {
+ FAIL("dlclose-dylib-dynamic-ref: dladdr(sym_foo) == 0, but should have succeeded");
+ exit(0);
+ }
+
+
+ PASS("dlclose-dylib-dynamic-ref");
+ return EXIT_SUCCESS;
+}
--- /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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+all-check: all check
+
+check:
+ ./main
+
+all:
+ ${CC} ${CCFLAGS} -dynamiclib base.c -o libbase.dylib
+ ${CC} ${CCFLAGS} -dynamiclib foo.c libbase.dylib -o libfoo.dylib
+ ${CC} ${CCFLAGS} -dynamiclib bar.c libbase.dylib -o libbar.dylib
+ ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c -o main
+
+
+clean:
+ ${RM} ${RMFLAGS} *~ main libfoo.dylib libbar.dylib libbase.dylib
+
--- /dev/null
+
+
+int bar()
+{
+ return 10;
+}
--- /dev/null
+void base() { }
--- /dev/null
+
+int foo()
+{
+ return 10;
+}
--- /dev/null
+/*
+ * Copyright (c) 2012 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()
+
+
+
+
+int main()
+{
+ Dl_info info;
+
+ // load bar
+ void* handleBar = dlopen("libbar.dylib", RTLD_LAZY);
+ if ( handleBar == NULL ) {
+ FAIL("dlclose-dylib-ref-count: dlopen(\"libbar.dylib\", RTLD_LAZY) failed with dlerror()=%s", dlerror());
+ exit(0);
+ }
+
+ // load foo
+ void* handleFoo = dlopen("libfoo.dylib", RTLD_LAZY);
+ if ( handleFoo == NULL ) {
+ FAIL("dlclose-dylib-ref-count: dlopen(\"libfoo.dylib\", RTLD_LAZY) failed with dlerror()=%s", dlerror());
+ exit(0);
+ }
+
+ void* sym_base = dlsym(handleBar, "base");
+ if ( sym_base == NULL ) {
+ FAIL("dlclose-dylib-ref-count: dlsym(handleBar, \"base\") failed");
+ exit(0);
+ }
+
+ void* sym_foo = dlsym(handleFoo, "foo");
+ if ( sym_foo == NULL ) {
+ FAIL("dlclose-dylib-ref-count: dlsym(handleBar, \"base\") failed");
+ exit(0);
+ }
+
+ void* sym_bar = dlsym(handleBar, "bar");
+ if ( sym_bar == NULL ) {
+ FAIL("dlclose-dylib-ref-count: dlsym(handleBar, \"base\") failed");
+ exit(0);
+ }
+
+ if ( dlclose(handleBar) != 0 ) {
+ FAIL("dlclose-dylib-ref-count: dlclose(handleBar) != 0, dlerrr()=%s", dlerror());
+ exit(0);
+ }
+
+ // sym_base should still be accessible via dladdr() because of external reference from libfoo.dylib
+ if ( dladdr(sym_base, &info) == 0 ) {
+ FAIL("dlclose-dylib-ref-count: dladdr(sym_base) == 0, but should have succeeded");
+ exit(0);
+ }
+
+ // sym_foo should still be accessible via dladdr() because libfoo was dlopen'ed
+ if ( dladdr(sym_foo, &info) == 0 ) {
+ FAIL("dlclose-dylib-ref-count: dladdr(sym_foo) == 0, but should have succeeded");
+ exit(0);
+ }
+
+ // sym_bar should not be accessible via dladdr() because libbar was dlclose'ed
+ if ( dladdr(sym_bar, &info) != 0 ) {
+ FAIL("dlclose-dylib-ref-count: dladdr(sym_bar) != 0, but should have failed");
+ exit(0);
+ }
+
+ if ( dlclose(handleFoo) != 0 ) {
+ FAIL("dlclose-dylib-ref-count: dlclose(handleBar) != 0, dlerrr()=%s", dlerror());
+ exit(0);
+ }
+
+ // sym_base should no longer be accessible via dladdr() because libfoo and libbar both closed
+ if ( dladdr(sym_base, &info) != 0 ) {
+ FAIL("dlclose-dylib-ref-count: dladdr(base) != 0, but should have failed");
+ exit(0);
+ }
+
+ // sym_foo should still be accessible via dladdr() because libfoo was dlclose'ed
+ if ( dladdr(sym_foo, &info) != 0 ) {
+ FAIL("dlclose-dylib-ref-count: dladdr(sym_foo) != 0, but should have failed");
+ exit(0);
+ }
+
+ PASS("dlclose-dylib-ref-count");
+ 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
+
+
+# <rdar://problem/13728515> dylibs need to be unloaded in reverse order of creation
+
+all-check: all check
+
+check:
+ ./main
+
+all:
+ ${CC} ${CCFLAGS} -dynamiclib baz.c -o libbaz.dylib
+ ${CXX} ${CXXFLAGS} -dynamiclib bar.cpp libbaz.dylib -o libbar.dylib
+ ${CXX} ${CXXFLAGS} -dynamiclib foo.cpp libbaz.dylib libbar.dylib -o libfoo.dylib
+ ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c -o main
+
+
+clean:
+ ${RM} ${RMFLAGS} *~ main libfoo.dylib libbar.dylib libbaz.dylib
+
--- /dev/null
+extern "C" int bazData;
+
+class BazUser {
+public:
+ BazUser() { }
+ ~BazUser() { bazData = 0; }
+};
+
+
+BazUser b;
+
+
+int bar()
+{
+ return bazData;
+}
+
--- /dev/null
+int bazData = 5;
+
+
+int baz()
+{
+ return bazData;
+}
--- /dev/null
+
+extern void bar();
+
+
+
+class A {
+public:
+ A() { bar(); }
+ ~A() { bar(); }
+};
+
+
+// Create global object which will have its destructor run when
+// this dylib is unloaded. The destructor will call into libbar,
+// so libbar.dylib can't be unloaded before this dylib.
+A a;
+
+
+
+
+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 <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+
+
+int main()
+{
+ // load foo
+ void* handleFoo = dlopen("libfoo.dylib", RTLD_LAZY);
+ if ( handleFoo == NULL ) {
+ FAIL("dlclose-dylib-order: dlopen(\"libfoo.dylib\", RTLD_LAZY) failed with dlerror()=%s", dlerror());
+ exit(0);
+ }
+
+ if ( dlclose(handleFoo) != 0 ) {
+ FAIL("dlclose-dylib-order: dlclose(handleFoo) != 0, dlerrr()=%s", dlerror());
+ exit(0);
+ }
+
+
+ PASS("dlclose-dylib-order");
+ return EXIT_SUCCESS;
+}
FAIL("dlclose-unload-c++: libfoo should have been unloaded");
exit(0);
}
-
+
PASS("dlclose-unload-c++");
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
+
+
+#
+# verify uncodesigned dylibs gracefully fail to load
+#
+
+
+all-check: all check
+
+check:
+ ./main
+ ./main-enforce
+
+all:
+ ${CC} foo.c -dynamiclib -o libfoo.dylib
+ ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c -DENFORCE -o main-enforce
+ codesign -s - main-enforce
+ ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c -o main
+
+clean:
+ ${RM} ${RMFLAGS} *~ main main-enforce libfoo.dylib
--- /dev/null
+void foo()
+{
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <mach/mach.h>
+#include <System/sys/codesign.h>
+
+#include "test.h"
+
+
+int main()
+{
+#if ENFORCE
+ uint32_t flags = CS_ENFORCEMENT | CS_KILL;
+ if ( csops(0, CS_OPS_SET_STATUS, &flags, sizeof(flags)) != 0 ) {
+ FAIL("dlopen-codesign-dynamic: csops() failed");
+ return EXIT_SUCCESS;
+ }
+
+ void* handle = dlopen("libfoo.dylib", RTLD_LAZY);
+ if ( handle != NULL ) {
+ FAIL("dlopen-codesign-dynamic: load of libfoo.dylib should have failed");
+ return EXIT_SUCCESS;
+ }
+ const char* msg = dlerror();
+ if ( strstr(msg, "signature") == NULL ) {
+ FAIL("dlopen-codesign-dynamic: load of libfoo.dylib failed, but message was wrong: %s", msg);
+ return EXIT_SUCCESS;
+ }
+
+#else
+ void* handle = dlopen("libfoo.dylib", RTLD_LAZY);
+ if ( handle == NULL ) {
+ FAIL("dlopen-codesign-dynamic: load of libfoo.dylib failed");
+ return EXIT_SUCCESS;
+ }
+
+#endif
+
+ PASS("dlopen-codesign-dynamic");
+ 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
+
+
+#
+# verify uncodesigned dylibs gracefully fail to load
+#
+
+
+all-check: all check
+
+check:
+ ./main
+
+all:
+ ${CC} foo.c -dynamiclib -o libfoo.dylib
+ ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c -o main
+ codesign -s - -o enforcement,hard main
+
+clean:
+ ${RM} ${RMFLAGS} *~ main libfoo.dylib
--- /dev/null
+void foo()
+{
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include "test.h"
+
+
+int main()
+{
+ void* handle = dlopen("libfoo.dylib", RTLD_LAZY);
+ if ( handle != NULL ) {
+ FAIL("dlopen-codesign: load of libfoo.dylib should have failed");
+ return EXIT_SUCCESS;
+ }
+ const char* msg = dlerror();
+ if ( strstr(msg, "signature") == NULL ) {
+ FAIL("dlopen-codesign: load of libfoo.dylib failed, but message was wrong: %s", msg);
+ return EXIT_SUCCESS;
+ }
+
+ PASS("dlopen-codesign");
+ return EXIT_SUCCESS;
+}
check: ${CHECK}
check-real:
- ${TESTROOT}/bin/exit-zero-pass.pl "dlopen-leak" "dlopen-leak" "DYLD_LIBRARY_PATH=hide && ./main | grep '0 leaks for 0 total leaked bytes' > /dev/null"
- ${TESTROOT}/bin/exit-zero-pass.pl "dlopen-leak" "dlopen-leak" "./main | grep '0 leaks for 0 total leaked bytes' > /dev/null"
+ DYLD_LIBRARY_PATH=hide && ./main
+ ./main
check-xfail:
echo "XFAIL dlopen-leak";
// execute leaks command on myself
char cmd[512];
- sprintf(cmd, "leaks %u\n", getpid());
- system(cmd);
+ sprintf(cmd, "leaks %u > /dev/null\n", getpid());
+ int status = system(cmd);
+ if ( status == EXIT_SUCCESS )
+ PASS("dlopen-leak-threaded");
+ else
+ FAIL("dlopen-leak-threaded");
return EXIT_SUCCESS;
}
check: ${CHECK}
check-real:
- ${TESTROOT}/bin/exit-zero-pass.pl "dlopen-leak" "dlopen-leak" "DYLD_LIBRARY_PATH=hide && ./main | grep '0 leaks for 0 total leaked bytes' > /dev/null"
- ${TESTROOT}/bin/exit-zero-pass.pl "dlopen-leak" "dlopen-leak" "./main | grep '0 leaks for 0 total leaked bytes' > /dev/null"
+ DYLD_LIBRARY_PATH=hide && ./main
+ ./main
check-xfail:
echo "XFAIL dlopen-leak";
/*
- * Copyright (c) 2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2013 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
dlopen("libnotthere.dylib", RTLD_LAZY);
}
+
// execute leaks command on myself
char cmd[512];
- sprintf(cmd, "leaks %u\n", getpid());
- system(cmd);
-
+ sprintf(cmd, "leaks %u > /dev/null\n", getpid());
+ int result = system(cmd);
+ if ( result == EXIT_SUCCESS )
+ PASS("dlopen-leak");
+ else
+ FAIL("dlopen-leak");
+
return EXIT_SUCCESS;
}
check: ${CHECK}
check-real:
- DYLD_LIBRARY_PATH=hide:other:places && ./main | grep '0 leaks for 0 total leaked bytes' > /dev/null && echo "PASS dlopen-search-leak"
+ DYLD_LIBRARY_PATH=hide:other:places && ./main
check-xfail:
echo "XFAIL dlopen-leak";
// execute leaks command on myself
char cmd[512];
- sprintf(cmd, "leaks %u\n", getpid());
- system(cmd);
+ sprintf(cmd, "leaks %u > /dev/null\n", getpid());
+ int result = system(cmd);
+ if ( result == EXIT_SUCCESS )
+ PASS("dlopen-search-leak");
+ else
+ FAIL("dlopen-search-leak");
return EXIT_SUCCESS;
}
check: ${CHECK}
check-real:
- ${TESTROOT}/bin/exit-zero-pass.pl "dlopen_preflight-leak-image-deny-single" "dlopen_preflight-leak-image-deny-single" "./main | grep '0 leaks for 0 total leaked bytes' > /dev/null"
+ ./main
check-xfail:
echo "XFAIL dlopen-leak";
// execute leaks command on myself
char cmd[512];
- sprintf(cmd, "leaks %u\n", getpid());
- system(cmd);
+ sprintf(cmd, "leaks %u > /dev/null\n", getpid());
+ int result = system(cmd);
+ if ( result == EXIT_SUCCESS )
+ PASS("dlopen_preflight-leak-image-deny-single");
+ else
+ FAIL("dlopen_preflight-leak-image-deny-single");
return EXIT_SUCCESS;
}
check: ${CHECK}
check-real:
- ${TESTROOT}/bin/exit-zero-pass.pl "dlopen_preflight-leak" "dlopen_preflight-leak" "DYLD_LIBRARY_PATH=hide && ./main | grep '0 leaks for 0 total leaked bytes' > /dev/null"
- ${TESTROOT}/bin/exit-zero-pass.pl "dlopen_preflight-leak" "dlopen_preflight-leak" "./main | grep '0 leaks for 0 total leaked bytes' > /dev/null"
+ DYLD_LIBRARY_PATH=hide && ./main
+ ./main
check-xfail:
echo "XFAIL dlopen-leak";
// execute leaks command on myself
char cmd[512];
- sprintf(cmd, "leaks %u\n", getpid());
- system(cmd);
+ sprintf(cmd, "leaks %u > /dev/null\n", getpid());
+ int result = system(cmd);
+ if ( result == EXIT_SUCCESS )
+ PASS("dlopen_preflight-leak");
+ else
+ FAIL("dlopen_preflight-leak");
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
+
+PWD = $(shell pwd)
+
+all-check: all check
+
+check:
+ ./main 10
+ export DYLD_LIBRARY_PATH=${PWD}/hide && ./main 10
+
+all:
+ mkdir -p Foo.framework
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -DRESULT=10 -o "${PWD}/Foo.framework/Foo"
+ mkdir -p hide
+ ${CC} ${CCFLAGS} -dynamiclib foo.c -DRESULT=0 -o "${PWD}/hide/Foo"
+ ${CC} ${CCFLAGS} main.c -framework Foo -F. -I../../include -o main
+
+
+clean:
+ ${RM} -rf Foo.framework hide main
\ No newline at end of file
--- /dev/null
+
+int foo()
+{
+ return RESULT;
+}
--- /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 <string.h>
+#include <stdlib.h> // for atoi()
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+
+extern int foo();
+
+int main(int argc, const char* argv[])
+{
+ int expectedResult = atoi(argv[1]);
+ int actualResult = foo();
+ //fprintf(stderr, "foo() returned %d, expected %d\n", actualResult, expectedResult);
+ if ( actualResult != expectedResult )
+ FAIL("framework-DYLD_LIBRARY_PATH using wrong dylib. foo() returned %d, expected %d", actualResult, expectedResult);
+ else
+ PASS("framework-DYLD_LIBRARY_PATH");
+
+ 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@
+#
+
+#
+# This unit test verifies that multiple interposing libraries can all
+# interpose the same function and the result is that they chain together.
+# That is, each one calls through to the next.
+#
+# On Tiger (10.4.0), this test fails with infinite recursion.
+#
+# The function foo() does string appends. This allows us to check:
+# 1) every interposer was called, and 2) they were called in the
+# correct order.
+#
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+all-check: all check
+
+check:
+ export DYLD_INSERT_LIBRARIES="libfoo1.dylib:libfoo2.dylib" && ./main
+ export DYLD_INSERT_LIBRARIES="libfoo2.dylib:libfoo1.dylib" && ./main
+
+all:
+ ${CC} ${CCFLAGS} -dynamiclib base.c -o libbase.dylib
+ ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c libbase.dylib -o main
+ ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib foo1.c libbase.dylib -o libfoo1.dylib
+ ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib foo2.c libbase.dylib -o libfoo2.dylib
+
+
+clean:
+ ${RM} ${RMFLAGS} *~ main libbase.dylib libfoo1.dylib libfoo2.dylib
+
--- /dev/null
+#include <stdio.h>
+#include "base.h"
+
+int base1() { return 1; }
+int base2() { return 2; }
+
--- /dev/null
+
+extern int base1();
+extern int base2();
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include <mach-o/dyld-interposing.h>
+#include "base.h"
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+int (*p2)() = &base2;
+
+__attribute__((constructor))
+void myinit()
+{
+ if ( (*p2)() == 20 )
+ PASS("interpose-multiple");
+ else
+ FAIL("interpose-multiple");
+}
+
+
+int mybase1()
+{
+ return 10;
+}
+
+
+DYLD_INTERPOSE(mybase1, base1)
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include <mach-o/dyld-interposing.h>
+#include "base.h"
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+int (*p1)() = &base1;
+
+__attribute__((constructor))
+void myinit()
+{
+ if ( (*p1)() == 10 )
+ PASS("interpose-multiple");
+ else
+ FAIL("interpose-multiple");
+}
+
+
+int mybase2()
+{
+ return 20;
+}
+
+
+DYLD_INTERPOSE(mybase2, base2)
--- /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 <string.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+#include "base.h"
+
+int main()
+{
+ return EXIT_SUCCESS;
+}
main : main.c foo/libfoo.dylib bar/libbar.dylib
${CC} -I${TESTROOT}/include main.c -o main foo/libfoo.dylib bar/libbar.dylib
# this breaks partial makes, but ld can't see @loader_path or it freaks
- install_name_tool -change foo/libbase.dylib '@loader_path/libbase.dylib' foo/libfoo.dylib
- install_name_tool -change bar/libbase.dylib '@loader_path/libbase.dylib' bar/libbar.dylib
+ ${INSTALL_NAME_TOOL} -change foo/libbase.dylib '@loader_path/libbase.dylib' foo/libfoo.dylib
+ ${INSTALL_NAME_TOOL} -change bar/libbase.dylib '@loader_path/libbase.dylib' bar/libbar.dylib
clean:
main : main.c libfoo2.dylib hide/libbar.dylib hide/libfoo3.dylib
${CC} -Wno-deprecated-declarations -I${TESTROOT}/include main.c -o main hide/libbar.dylib libfoo2.dylib
- install_name_tool -change libfoo2.dylib '@loader_path/libfoo2.dylib' main
- install_name_tool -change libbar.dylib '@loader_path/hide/libbar.dylib' main
+ ${INSTALL_NAME_TOOL} -change libfoo2.dylib '@loader_path/libfoo2.dylib' main
+ ${INSTALL_NAME_TOOL} -change libbar.dylib '@loader_path/hide/libbar.dylib' main
clean:
${RM} ${RMFLAGS} *~ main libfoo.dylib hide libfoo2.dylib
##
-# Copyright (c) 2009 Apple Inc. All rights reserved.
+# Copyright (c) 2009-2013 Apple Inc. All rights reserved.
#
# @APPLE_LICENSE_HEADER_START@
#
ifeq "$(OS_NAME)" "iPhoneOS"
RUN_AS_USER = login -f -l mobile
+ RUN_AS_ROOT =
else
RUN_AS_USER =
+ RUN_AS_ROOT = sudo
endif
PWD = `pwd`
check:
${RUN_AS_USER} $(PWD)/main-with-env 2>/dev/null
+ ${RUN_AS_ROOT} $(PWD)/main-with-env 2>/dev/null
all: main
#include <stdio.h> // fprintf(), NULL
#include <stdlib.h> // exit(), EXIT_SUCCESS
#include <string.h> // strcmp(), strncmp()
+#include <mach-o/dyld_priv.h> // dyld_process_is_restricted()
#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
return EXIT_SUCCESS;
}
+ // verify SPI says process is restricted
+ if ( !dyld_process_is_restricted() ) {
+ FAIL("restrict-environ: dyld_process_is_restrictet() returns false");
+ return EXIT_SUCCESS;
+ }
+
+
PASS("restrict-environ");
return EXIT_SUCCESS;
}
check:
if [ ${EMULATED} == 0 ]; \
then \
- ${TESTROOT}/bin/exit-zero-pass.pl "rpath-dlopen-leak" "rpath-dlopen-leak" "./main | grep '0 leaks for 0 total leaked bytes' > /dev/null"; \
- ${TESTROOT}/bin/exit-zero-pass.pl "rpath-dlopen-leak" "rpath-dlopen-leak" "./main.bad | grep '0 leaks for 0 total leaked bytes' > /dev/null"; \
+ ./main ; \
+ ./main.bad ; \
else \
echo "XFAIL rpath-dlopen-leak"; \
fi;
// execute leaks command on myself
char cmd[512];
- sprintf(cmd, "leaks %u\n", getpid());
- system(cmd);
+ int result = system(cmd);
+ if ( result == EXIT_SUCCESS )
+ PASS("rpath-dlopen-leak");
+ else
+ FAIL("rpath-dlopen-leak");
return EXIT_SUCCESS;
}
int myfoo()
{
+ foo();
return 20;
}
--- /dev/null
+##
+# Copyright (c) 2010 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
+
+
+##
+## Test that resolver function is not run before initializer
+## even when lazy pointers are bound early.
+##
+
+all-check: all_$(OS_LION_FEATURES) check_$(OS_LION_FEATURES)
+
+all: all_$(OS_LION_FEATURES)
+
+check: check_$(OS_LION_FEATURES)
+
+check_:
+ ${PASS_IFF} true
+
+all_:
+
+
+check_1:
+ ./main
+
+all_1:
+ ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -I${TESTROOT}/include
+ ${CC} ${CCFLAGS} -dynamiclib foo.c libbar.dylib -o libfoo.dylib
+ ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c -o main
+
+
+
+clean:
+ ${RM} ${RMFLAGS} main libfoo.dylib libbar.dylib
+
--- /dev/null
+/*
+ * Copyright (c) 2012 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 <stdlib.h>
+#include <stdbool.h>
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+static bool hasBeenInited = false;
+
+__attribute__((constructor))
+void myInit()
+{
+ hasBeenInited = true;
+}
+
+
+int barGood()
+{
+ return 1;
+}
+
+int barBad()
+{
+ return 0;
+}
+
+
+// This bar is a "resolver" function that return the actual address of "bar"
+void* bar()
+{
+ __asm__(".symbol_resolver _bar"); // magic until we have compiler support
+ // <rdar://problem/12629331> Resolver function run before initializers
+ if ( hasBeenInited )
+ return &barGood;
+ else
+ return &barBad;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2010 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 <stdlib.h>
+
+
+extern int bar();
+
+int foo()
+{
+ return bar();
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2012 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()
+
+typedef int (*Func_t)(void);
+
+int main()
+{
+ // RTLD_NOW force lazy pointers to be bound early
+ void* handle = dlopen("libfoo.dylib", RTLD_NOW);
+ Func_t pFoo = (Func_t)dlsym(handle, "foo");
+ int result = (*pFoo)();
+ if ( result == 0 )
+ FAIL("symbol-resolver-lazy-prebound: resolver ran before initializer");
+ else
+ PASS("symbol-resolver-lazy-prebound");
+
+ 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
+
+all-check: all check
+
+check:
+ DYLD_INSERT_LIBRARIES=libfoo1.dylib:libfoo2.dylib ./main
+
+all: main
+
+main:
+ ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o libbase.dylib base.c
+ ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o libfoo1.dylib foo1.c libbase.dylib
+ ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o libfoo2.dylib foo2.c libbase.dylib
+ ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libbase.dylib
+
+
+clean:
+ ${RM} ${RMFLAGS} *~ main libfoo1.dylib libfoo2.dylib libbase.dylib
+
--- /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 <stdio.h>
+#include <stdbool.h>
+
+#include "base.h"
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+static bool wasProblem = false;
+
+static const char* coal1Where = NULL;
+static int* coal1Addr = NULL;
+static int checkInCountCoal1 = 0;
+
+void baseVerifyCoal1(const char* where, int* addr)
+{
+ //fprintf(stderr, "baseVerifyCoal1(%s, %p)\n", where, addr);
+ ++checkInCountCoal1;
+ if ( coal1Where == NULL ) {
+ coal1Where = where;
+ coal1Addr = addr;
+ }
+ else {
+ if ( addr != coal1Addr ) {
+ fprintf(stderr, "coal1 resolved to different locations. %p %s and %p %s\n",
+ coal1Addr, coal1Where, addr, where);
+ wasProblem = true;
+ }
+ }
+}
+
+
+static const char* coal2Where = NULL;
+static int* coal2Addr = NULL;
+static int checkInCountCoal2 = 0;
+
+void baseVerifyCoal2(const char* where, int* addr)
+{
+ //fprintf(stderr, "baseVerifyCoal2(%s, %p)\n", where, addr);
+ ++checkInCountCoal2;
+ if ( coal2Where == NULL ) {
+ coal2Where = where;
+ coal2Addr = addr;
+ }
+ else {
+ if ( addr != coal2Addr ) {
+ fprintf(stderr, "coal2 resolved to different locations. %p %s and %p %s\n",
+ coal2Addr, coal2Where, addr, where);
+ wasProblem = true;
+ }
+ }
+}
+
+
+
+void baseCheck()
+{
+ if ( wasProblem || (checkInCountCoal1 != 3) || (checkInCountCoal2 != 2) )
+ FAIL("weak-coal");
+ else
+ PASS("weak-coal");
+}
+
--- /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@
+ */
+
+
+extern void baseCheck();
+
+extern int coal1;
+extern int coal2;
+
+extern void baseVerifyCoal1(const char* where, int* addr);
+extern void baseVerifyCoal2(const char* where, int* addr);
--- /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 <stdio.h>
+#include "base.h"
+
+
+
+int __attribute__((weak)) coal1 = 1;
+int __attribute__((weak)) coal2 = 1;
+
+
+static __attribute__((constructor)) void myinit()
+{
+ //fprintf(stderr, "myinit() in foo1.c\n");
+ baseVerifyCoal1("in foo1", &coal1);
+ baseVerifyCoal2("in foo1", &coal2);
+}
+
+
--- /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 <stdio.h>
+#include "base.h"
+
+
+int __attribute__((weak)) coal1 = 2;
+int __attribute__((weak)) coal2 = 2;
+
+static __attribute__((constructor)) void myinit()
+{
+ //fprintf(stderr, "myinit() in foo1.c\n");
+ baseVerifyCoal1("in foo2", &coal1);
+ baseVerifyCoal2("in foo2", &coal2);
+}
--- /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 <stdio.h> // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+#include "base.h"
+
+int __attribute__((weak)) coal1 = 3;
+
+
+int main()
+{
+ baseVerifyCoal1("in main", &coal1);
+
+ baseCheck();
+ return EXIT_SUCCESS;
+}
+
+
$(CC) $(CCFLAGS) -I${TESTROOT}/include main.c -o main
$(CC) $(CCFLAGS) bar.c -dynamiclib -o libbar.dylib
$(CC) $(CCFLAGS) foo.c -dynamiclib -o libfoo.dylib
- strip -c -x libfoo.dylib -o libstub.dylib
+ $(STRIP) -c -x libfoo.dylib -o libstub.dylib
clean:
${RM} ${RMFLAGS} libbar.dylib libfoo.dylib libstub.dylib main