]> git.saurik.com Git - apple/dyld.git/commitdiff
dyld-239.3.tar.gz os-x-109 os-x-1091 v239.3
authorApple <opensource@apple.com>
Tue, 29 Oct 2013 00:03:35 +0000 (00:03 +0000)
committerApple <opensource@apple.com>
Tue, 29 Oct 2013 00:03:35 +0000 (00:03 +0000)
125 files changed:
doc/ReleaseNotes.txt
doc/man/man3/dlopen.3
doc/man/man3/dlsym.3
dyld.xcodeproj/project.pbxproj
include/dlfcn.h
include/mach-o/dyld.h
include/mach-o/dyld_debug.h [deleted file]
include/mach-o/dyld_images.h
include/mach-o/dyld_priv.h
include/objc-shared-cache.h
launch-cache/CacheFileAbstraction.hpp
launch-cache/MachOBinder.hpp
launch-cache/MachOLayout.hpp
launch-cache/MachORebaser.hpp
launch-cache/dsc_extractor.cpp
launch-cache/dsc_iterator.cpp
launch-cache/dsc_iterator.h
launch-cache/dyld_cache_format.h
launch-cache/dyld_shared_cache_util.cpp
launch-cache/update_dyld_shared_cache.cpp
src/ImageLoader.cpp
src/ImageLoader.h
src/ImageLoaderMachO.cpp
src/ImageLoaderMachO.h
src/ImageLoaderMachOClassic.cpp
src/ImageLoaderMachOClassic.h
src/ImageLoaderMachOCompressed.cpp
src/ImageLoaderMachOCompressed.h
src/dyld.cpp
src/dyld.h
src/dyldAPIs.cpp
src/dyldAPIsInLibSystem.cpp
src/dyldExceptions.c
src/dyldInitialization.cpp
src/dyldLibSystemGlue.c
src/dyldLibSystemInterface.h
src/dyldLock.cpp
src/dyldLock.h
src/dyldNew.cpp
src/dyldStartup.s
src/dyldSyscallInterface.h [new file with mode: 0644]
src/dyld_gdb.cpp
src/dyld_sim.exp [new file with mode: 0644]
src/dyld_stub_binder.s
src/glue.c
src/libdyld_sim.exp [new file with mode: 0644]
src/start_glue.h [new file with mode: 0644]
src/start_glue.s
src/threadLocalHelpers.s
src/threadLocalVariables.c
unit-tests/include/common.makefile
unit-tests/run-all-unit-tests
unit-tests/test-cases/DYLD_VERSIONED_FRAMEWORK_PATH-basic/Makefile
unit-tests/test-cases/DYLD_VERSIONED_FRAMEWORK_PATH-basic/main.c
unit-tests/test-cases/absolute-symbol/Makefile [new file with mode: 0644]
unit-tests/test-cases/absolute-symbol/abs.s [new file with mode: 0644]
unit-tests/test-cases/absolute-symbol/foo.c [new file with mode: 0644]
unit-tests/test-cases/absolute-symbol/main.c [new file with mode: 0644]
unit-tests/test-cases/big-stack/main.c
unit-tests/test-cases/bundle-memory-load-fat/Makefile
unit-tests/test-cases/bundle-terminator/Makefile [new file with mode: 0644]
unit-tests/test-cases/bundle-terminator/bundle.cxx [new file with mode: 0644]
unit-tests/test-cases/bundle-terminator/main.c [new file with mode: 0644]
unit-tests/test-cases/crt-apple/Makefile
unit-tests/test-cases/crt-libSystem/Makefile
unit-tests/test-cases/dladdr-stripped/Makefile
unit-tests/test-cases/dlclose-dylib-dynamic-ref/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlclose-dylib-dynamic-ref/bar.c [new file with mode: 0644]
unit-tests/test-cases/dlclose-dylib-dynamic-ref/baz.c [new file with mode: 0644]
unit-tests/test-cases/dlclose-dylib-dynamic-ref/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlclose-dylib-dynamic-ref/main.c [new file with mode: 0644]
unit-tests/test-cases/dlclose-dylib-ref-count/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlclose-dylib-ref-count/bar.c [new file with mode: 0644]
unit-tests/test-cases/dlclose-dylib-ref-count/base.c [new file with mode: 0644]
unit-tests/test-cases/dlclose-dylib-ref-count/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlclose-dylib-ref-count/main.c [new file with mode: 0644]
unit-tests/test-cases/dlclose-dylib-terminators/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlclose-dylib-terminators/bar.cpp [new file with mode: 0644]
unit-tests/test-cases/dlclose-dylib-terminators/baz.c [new file with mode: 0644]
unit-tests/test-cases/dlclose-dylib-terminators/foo.cpp [new file with mode: 0644]
unit-tests/test-cases/dlclose-dylib-terminators/main.c [new file with mode: 0644]
unit-tests/test-cases/dlclose-unload-c++/main.c
unit-tests/test-cases/dlopen-codesign-dynamic/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen-codesign-dynamic/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-codesign-dynamic/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-codesign/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen-codesign/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-codesign/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-leak-threaded/Makefile
unit-tests/test-cases/dlopen-leak-threaded/main.c
unit-tests/test-cases/dlopen-leak/Makefile
unit-tests/test-cases/dlopen-leak/main.c
unit-tests/test-cases/dlopen-search-leak/Makefile
unit-tests/test-cases/dlopen-search-leak/main.c
unit-tests/test-cases/dlopen_preflight-leak-image-deny-single/Makefile
unit-tests/test-cases/dlopen_preflight-leak-image-deny-single/main.c
unit-tests/test-cases/dlopen_preflight-leak/Makefile
unit-tests/test-cases/dlopen_preflight-leak/main.c
unit-tests/test-cases/framework-DYLD_LIBRARY_PATH/Makefile [new file with mode: 0644]
unit-tests/test-cases/framework-DYLD_LIBRARY_PATH/foo.c [new file with mode: 0644]
unit-tests/test-cases/framework-DYLD_LIBRARY_PATH/main.c [new file with mode: 0644]
unit-tests/test-cases/interpose-multiple/Makefile [new file with mode: 0644]
unit-tests/test-cases/interpose-multiple/base.c [new file with mode: 0644]
unit-tests/test-cases/interpose-multiple/base.h [new file with mode: 0644]
unit-tests/test-cases/interpose-multiple/foo1.c [new file with mode: 0644]
unit-tests/test-cases/interpose-multiple/foo2.c [new file with mode: 0644]
unit-tests/test-cases/interpose-multiple/main.c [new file with mode: 0644]
unit-tests/test-cases/loader_path-dup/Makefile
unit-tests/test-cases/loader_path/Makefile
unit-tests/test-cases/restrict-environ/Makefile
unit-tests/test-cases/restrict-environ/main.c
unit-tests/test-cases/rpath-dlopen-leak/Makefile
unit-tests/test-cases/rpath-dlopen-leak/main.c
unit-tests/test-cases/symbol-resolver-interposed/myfoo.c
unit-tests/test-cases/symbol-resolver-lazy-prebound/Makefile [new file with mode: 0644]
unit-tests/test-cases/symbol-resolver-lazy-prebound/bar.c [new file with mode: 0644]
unit-tests/test-cases/symbol-resolver-lazy-prebound/foo.c [new file with mode: 0644]
unit-tests/test-cases/symbol-resolver-lazy-prebound/main.c [new file with mode: 0644]
unit-tests/test-cases/weak-coalesce-inserted/Makefile [new file with mode: 0644]
unit-tests/test-cases/weak-coalesce-inserted/base.c [new file with mode: 0644]
unit-tests/test-cases/weak-coalesce-inserted/base.h [new file with mode: 0644]
unit-tests/test-cases/weak-coalesce-inserted/foo1.c [new file with mode: 0644]
unit-tests/test-cases/weak-coalesce-inserted/foo2.c [new file with mode: 0644]
unit-tests/test-cases/weak-coalesce-inserted/main.c [new file with mode: 0644]
unit-tests/test-cases/weak-coalesce-stubs/Makefile

index 33ce9add9df294395d84fb6fc1be883659e1ac50..18d5f8123262608f6f78ca2ecc4fa33be61f23af 100644 (file)
@@ -44,9 +44,11 @@ dyld-200.3
 <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
 
index 679d267865a95cafad013ea58568d6f456145ec0..1da4927ae0baabb16c212d8d2cc45f7113ad747e 100644 (file)
@@ -1,4 +1,4 @@
-.Dd Nov 7, 2011
+.Dd Aug 7, 2012
 .Os
 .Dt DLOPEN 3
 .Sh NAME
@@ -121,34 +121,49 @@ returned will only search the main executable.
 .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
@@ -162,16 +177,11 @@ If
 .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
index 2cd3f441b0b314bd79383de2debd7bd7448c042c..5f7c4ed26207a6e36db2d5e3ff74ebc1d0654b4b 100644 (file)
@@ -88,7 +88,6 @@ If you looking up a C++ symbol, you need to use the mangled C++ symbol
 name.  
 .Sh SEE ALSO
 .Xr dlopen 3
-.Xr dlsym 3
 .Xr dlerror 3
 .Xr dyld 3
 .Xr ld 1
index 504873ce1a416ac08347dcebcc455fbd7c98d759..d8e3000a6a4ea7cff037f5ac487fa54bdb06d6dd 100644 (file)
@@ -17,6 +17,7 @@
                                F908137111D3FB5000626CC1 /* usr|local|include|mach-o */,
                                F908137211D3FB5000626CC1 /* usr|share|man|man1 */,
                                F908137311D3FB5000626CC1 /* usr|share|man|man3 */,
+                               F9F479FE152A63F2008F75C2 /* simulator clean up */,
                        );
                        dependencies = (
                                F9B4D78012AD9736000605A6 /* PBXTargetDependency */,
@@ -58,6 +59,8 @@
                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;
                        };
index 7e4ae35cfa2c0d46c09b0b0d84e2f8abd813b6e3..bcb0c098d43f03489748010f9f00c4a370c7c29a 100644 (file)
@@ -38,7 +38,7 @@ extern "C" {
 
 #if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
 #include <stdbool.h>
-#include <AvailabilityMacros.h>
+#include <Availability.h>
 /*
  * Structure filled in by dladdr().
  */
@@ -58,7 +58,7 @@ extern void * dlopen(const char * __path, int __mode);
 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 */
 
 
index 3f579ef1ea3a968cdb887fe4e0c8c457db1ff4f2..642ca42f96b0e474ea1b570f189d91ebffe05e5a 100644 (file)
@@ -71,7 +71,7 @@ extern int32_t NSVersionOfRunTimeLibrary(const char* libraryName)            __O
 
 
 /*
- * 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.
diff --git a/include/mach-o/dyld_debug.h b/include/mach-o/dyld_debug.h
deleted file mode 100644 (file)
index a0590f5..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * 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_ */
index ed710ef342d46892ff42e1a92c03b269a633d166..ba287f9a5aa75c102224025118d0695ac0a60ca9 100644 (file)
@@ -63,7 +63,7 @@ extern "C" {
  *
  */
 
-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 */
@@ -122,17 +122,11 @@ struct dyld_all_image_infos {
        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
-
 
 
 /*
index 9464fb818e339e7ed794da295709bb919f02664d..49d5775c5a4c1586e8c386d4783a9e7fca304cba 100644 (file)
@@ -178,12 +178,36 @@ extern const char* dyld_image_path_containing_address(const void* addr);
 
 
 
+// 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);
 
 
@@ -192,6 +216,7 @@ 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();
 
 
@@ -200,6 +225,7 @@ 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);
 
 
@@ -208,6 +234,7 @@ 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();
 
 
@@ -221,6 +248,21 @@ 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
index b7db57d3fe3c3de5f0b55b551ed7ea854db7f272..8d59bfb4a197f7682532fc57fb1afa0c0c4e6ec8 100644 (file)
@@ -82,7 +82,7 @@ Source is http://burtleburtle.net/bob/c/perfect.c
 #include <stdint.h>
 #include <stdlib.h>
 #ifdef SELOPT_WRITE
-#include <ext/hash_map>
+#include <unordered_map>
 #endif
 /*
   DO NOT INCLUDE ANY objc HEADERS HERE
@@ -108,6 +108,8 @@ namespace objc_opt {
 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.
@@ -133,18 +135,23 @@ struct eqstr {
     }
 };
 
+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.
@@ -169,40 +176,55 @@ struct objc_stringhash_t {
     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
index c2e536c97c7a9aa415669314a888792923d302b3..cd2524eb525baf0573238e4ddb4d8aeffc35f871 100644 (file)
@@ -62,6 +62,15 @@ public:
        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;
 };
@@ -144,6 +153,51 @@ struct dyldCacheSlideInfoEntry {
 
 
 
+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__
 
 
index 332478fa19112648dc9185bfe16b1755e5237026..6f377270ac7d9a96de04190fd56516ffaaa5f29b 100644 (file)
@@ -40,8 +40,8 @@
 
 #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);
@@ -73,16 +85,14 @@ public:
        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; };
        
@@ -100,7 +110,8 @@ private:
                                                                                                                                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);
@@ -115,6 +126,7 @@ private:
        std::vector<BinderAndReExportFlag>                      fDependentDylibs;
        NameToAddrMap                                                           fHashTable;
        NameSet                                                                         fSymbolResolvers;
+       NameSet                                                                         fAbsoluteSymbols;
        std::vector<SymbolReExport>                                     fReExportedSymbols;
        uint64_t                                                                        fDyldBaseAddress;
        const macho_nlist<P>*                                           fSymbolTable;
@@ -127,7 +139,7 @@ private:
        bool                                                                            fOriginallyPrebound;
        bool                                                                            fReExportedSymbolsResolved;
     std::vector<ClientAndSymbol>                fClientAndSymbols;
-    std::vector<SymbolAndLazyPointer>           fSymbolAndLazyPointers;
+       NameToAddrMap                                                           fResolverLazyPointers;
 };
 
 template <> 
@@ -211,27 +223,36 @@ Binder<A>::Binder(const MachOLayoutAbstraction& layout, uint64_t dyldBaseAddress
                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);
                }
@@ -240,7 +261,7 @@ Binder<A>::Binder(const MachOLayoutAbstraction& layout, uint64_t dyldBaseAddress
                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);
@@ -249,7 +270,7 @@ Binder<A>::Binder(const MachOLayoutAbstraction& layout, uint64_t dyldBaseAddress
                }
                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);
@@ -422,10 +443,13 @@ void Binder<A>::setDependentBinders(const Map& map)
                                ++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;
+                                               }
                                        }
                                }
                        }       
@@ -567,28 +591,22 @@ void Binder<A>::bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uin
        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());
         }
@@ -618,7 +636,8 @@ void Binder<A>::bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uin
                default:
                        throw "bad bind type";
        }
-       pointersInData.push_back(mappedAddr);
+       if ( !isAbsolute )
+               pointersInData.push_back(mappedAddr);
 }
 
 
@@ -993,15 +1012,16 @@ typename A::P::uint_t Binder<A>::resolveUndefined(const macho_nlist<P>* undefine
                }       
                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()
@@ -1012,17 +1032,18 @@ bool Binder<A>::findExportedSymbolAddress(const char* name, pint_t* result, Bind
                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;
                }
@@ -1036,18 +1057,20 @@ bool Binder<A>::findExportedSymbolAddress(const char* name, pint_t* result, Bind
                *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;
                }
        }
@@ -1065,24 +1088,60 @@ void Binder<A>::addResolverClient(Binder<A>* clientDylib, const char* symbolName
     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 = &sectionsStart[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;
 }
 
index 4d6583b6bb858f1a6623d3b230e45a082a73dffc..dbcbe76d1e3811f3a426d0c05ac1e2d96248cc63 100644 (file)
@@ -41,7 +41,7 @@
 
 #include <vector>
 #include <set>
-#include <ext/hash_map>
+#include <unordered_map>
 
 #include "MachOFileAbstraction.hpp"
 #include "Architectures.hpp"
@@ -151,6 +151,7 @@ public:
        // 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;
 };
 
 
@@ -195,6 +196,7 @@ public:
        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;
@@ -230,6 +232,7 @@ private:
        bool                                                                            fIsDylib;
        bool                                                                            fHasDyldInfo;
        mutable const uint8_t*                                          fDyldInfoExports;
+       uuid_t                                                                          fUUID;
 };
 
 
@@ -245,10 +248,19 @@ public:
        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);
 
@@ -422,7 +434,8 @@ MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char*
        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";
@@ -496,6 +509,12 @@ MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char*
                                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());
        }
index 88c4f83d0db08ef6fab0fd6fe07f1719c73f9ccc..4493cc3f2abb04b21c451faf7a40e8e971431f56 100644 (file)
@@ -120,7 +120,7 @@ private:
 
 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)
 {
index c94cbe0e645c4e4adef03d605763507b58075c51..4f68041027f87f496c832bb0e0bef5e0284c16a6 100644 (file)
 #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>
 
@@ -60,15 +61,24 @@ struct seg_info
        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;
@@ -160,31 +170,91 @@ int optimize_linkedit(macho_header<typename A::P>* mh, const void* mapped_cache,
                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
@@ -196,6 +266,7 @@ int optimize_linkedit(macho_header<typename A::P>* mh, const void* mapped_cache,
                dataInCode->set_dataoff(newDataInCodeOffset);
                dataInCode->set_datasize(dataInCodeSize);
        }
+       symtab->set_nsyms(symbolsCopied);
        symtab->set_symoff(newSymTabOffset);
        symtab->set_stroff(newStringPoolOffset);
        symtab->set_strsize(poolOffset);
@@ -226,7 +297,7 @@ static void make_dirs(const char* file_path)
        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';
@@ -254,7 +325,7 @@ size_t dylib_maker(const void* mapped_cache, std::vector<uint8_t> &dylib_data, c
     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)))
     
@@ -278,11 +349,12 @@ size_t dylib_maker(const void* mapped_cache, std::vector<uint8_t> &dylib_data, c
     
        // 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());
             
@@ -309,7 +381,7 @@ size_t dylib_maker(const void* mapped_cache, std::vector<uint8_t> &dylib_data, c
     
        // 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);
@@ -343,7 +415,7 @@ int dyld_shared_cache_extract_dylibs_progress(const char* shared_cache_file_path
        }
     
     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 ) 
@@ -365,12 +437,16 @@ int dyld_shared_cache_extract_dylibs_progress(const char* shared_cache_file_path
        }
 
        // iterate through all images in cache and build map of dylibs and segments
-       __block NameToSegments map;
-       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();
@@ -390,7 +466,7 @@ int dyld_shared_cache_extract_dylibs_progress(const char* shared_cache_file_path
             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);
             
@@ -457,6 +533,11 @@ int dyld_shared_cache_extract_dylibs(const char* shared_cache_file_path, const c
 
 
 #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));
@@ -468,7 +549,8 @@ int main(int argc, const char* argv[])
                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;
@@ -484,6 +566,8 @@ int main(int argc, const char* argv[])
        fprintf(stderr, "dyld_shared_cache_extract_dylibs_progress() => %d\n", result);
        return 0;
 }
+
+
 #endif
 
  
index 50ff8c9ad5a521b9accecc155ace7a1a0eb41b41..d57be709102c2072238293c664fa271cc4866ff3 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- 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@
  * 
@@ -41,13 +41,18 @@ namespace dyld {
 
        // 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;
@@ -55,14 +60,35 @@ namespace dyld {
 
        // 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;
@@ -74,39 +100,72 @@ namespace dyld {
                                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;
        }
@@ -118,25 +177,34 @@ namespace dyld {
 // 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)
 {
index 981386f7cc8496d22d740d195014dfbaa4b91040..b08eecc5bff4c956bc6939006e7d6b6b548c5863 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- 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
index 70d897cb7e7f9ed165239e13a1934e8426872b6c..9407ff62e7d753a728662980ba729084a6c7be1d 100644 (file)
@@ -41,6 +41,9 @@ struct dyld_cache_header
        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 {
@@ -73,6 +76,24 @@ struct dyld_cache_slide_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/"
index b0b69182cc1aee5591472dc1889cbb78939f5c51..9d4686ac348acad3e5cd319d5f2e37636a1fd186 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- 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@
  * 
@@ -34,9 +34,7 @@
 #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");
 }
 
 /*
@@ -86,6 +92,8 @@ static const char* default_shared_cache_path() {
        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
@@ -93,132 +101,112 @@ static const char* default_shared_cache_path() {
 #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);
                }
        }
 }
@@ -228,15 +216,14 @@ static void add_linkedit(uint32_t pageStart, uint32_t pageEnd, char* message)
  * 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;
@@ -244,35 +231,35 @@ void process_linkedit(const char* dylib, void* headerAddr) {
                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());
@@ -280,163 +267,139 @@ void process_linkedit(const char* dylib, void* headerAddr) {
 }
 
 
-
 /*
- * 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());
@@ -447,53 +410,121 @@ int main (int argc, char **argv) {
                                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);
                }
        }
index ac9cc1ccc006a8be19b2a00e3d8b5e5dda11bb25..73cb11474a2a83cc4fcda9e68d7ecfbb0daa8bbf 100644 (file)
@@ -31,7 +31,9 @@
 #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
@@ -95,15 +101,27 @@ static void warn(const char *arch, const char *format, ...)
 }
 
 
-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);
@@ -140,7 +158,7 @@ private:
                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) {}
@@ -325,12 +343,25 @@ ArchGraph::DependencyNode* ArchGraph::getNode(const char* path)
                //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;
@@ -508,6 +539,8 @@ const char* ArchGraph::archName(ArchPair ap)
                                        return "armv7f";
                                case CPU_SUBTYPE_ARM_V7K:
                                        return "armv7k";
+                               case CPU_SUBTYPE_ARM_V7S:
+                                       return "armv7s";
                                default:
                                        return "arm";
                        }
@@ -595,6 +628,82 @@ bool ArchGraph::canBeShared(const MachOLayoutAbstraction* layout, ArchPair ap, c
 }
 
 
+
+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
 {
@@ -602,7 +711,7 @@ public:
                                                        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
@@ -622,18 +731,19 @@ private:
 
        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 {
@@ -695,6 +805,9 @@ private:
        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;
@@ -718,6 +831,7 @@ private:
        uint32_t                                                        fOffsetOfDataInCodeInCombinedLinkedit;
        uint32_t                                                        fSizeOfDataInCodeInCombinedLinkedit;
        uint32_t                                                        fLinkEditsTotalOptimizedSize;
+       uint32_t                                                        fUnmappedLocalSymbolsSize;
 };
 
 
@@ -814,21 +928,21 @@ template <>        cpu_type_t     SharedCache<x86>::arch()        { return CPU_TYPE_I386; }
 template <>     cpu_type_t     SharedCache<x86_64>::arch()     { return CPU_TYPE_X86_64; }
 template <>     cpu_type_t     SharedCache<arm>::arch()        { return CPU_TYPE_ARM; }
 
-template <>     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"; }
@@ -839,6 +953,12 @@ template <>         const char*    SharedCache<x86>::cacheFileSuffix(bool, const char* arc
 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), 
@@ -851,7 +971,8 @@ SharedCache<A>::SharedCache(ArchGraph* graph, const char* rootPath, const char*
        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());
@@ -950,6 +1071,7 @@ SharedCache<A>::SharedCache(ArchGraph* graph, const char* rootPath, const char*
        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) {
@@ -973,21 +1095,21 @@ SharedCache<A>::SharedCache(ArchGraph* graph, const char* rootPath, const char*
                // 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);
 }
 
 
@@ -1001,131 +1123,80 @@ uint64_t SharedCache<A>::getWritableSegmentNewAddress(uint64_t proposedNewAddres
 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;
@@ -1133,29 +1204,18 @@ void SharedCache<A>::assignNewBaseAddresses(bool verify)
                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;
@@ -1165,7 +1225,7 @@ void SharedCache<A>::assignNewBaseAddresses(bool verify)
        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;
@@ -1322,7 +1382,7 @@ bool SharedCache<A>::notUpToDate(const char* path, unsigned int aliasCount)
        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);
@@ -1348,76 +1408,6 @@ bool SharedCache<A>::notUpToDate(const char* path, unsigned int aliasCount)
        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>
@@ -1431,7 +1421,10 @@ public:
                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);
@@ -1482,6 +1475,8 @@ private:
        uint32_t                                                                        fIndirectSymbolTableOffsetInfoNewLinkEdit;
        uint32_t                                                                        fFunctionStartsOffsetInNewLinkEdit;
        uint32_t                                                                        fDataInCodeOffsetInNewLinkEdit;
+       uint32_t                                                                        fUnmappedLocalSymbolsStartIndexInNewLinkEdit;
+       uint32_t                                                                        fUnmappedLocalSymbolsCountInNewLinkEdit;
 };
 
 
@@ -1500,7 +1495,8 @@ LinkEditOptimizer<A>::LinkEditOptimizer(const MachOLayoutAbstraction& layout, co
        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();
@@ -1609,25 +1605,46 @@ void LinkEditOptimizer<A>::copyExportInfo(uint32_t& offset)
 }
 
 
-
 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());
 }
 
@@ -1870,7 +1887,7 @@ void LinkEditOptimizer<A>::updateLoadCommands(uint64_t newVMAddress, uint64_t si
 
 
 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];
@@ -1916,8 +1933,11 @@ uint8_t* SharedCache<A>::optimizeLINKEDIT(bool keepSignatures)
        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);
        }
@@ -1958,11 +1978,11 @@ uint8_t* SharedCache<A>::optimizeLINKEDIT(bool keepSignatures)
        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) {
@@ -2315,6 +2335,69 @@ static void cleanup(int sig)
 }
 
 
+// <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; }
@@ -2324,7 +2407,7 @@ template <>        bool   SharedCache<x86>::addCacheSlideInfo()   { return false; }
 
 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;
        
@@ -2374,6 +2457,8 @@ bool SharedCache<A>::update(bool force, bool optimize, bool deleteExistingFirst,
                        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>)];
@@ -2479,10 +2564,6 @@ bool SharedCache<A>::update(bool force, bool optimize, bool deleteExistingFirst,
                        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 {
@@ -2542,7 +2623,7 @@ bool SharedCache<A>::update(bool force, bool optimize, bool deleteExistingFirst,
                        // 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;
@@ -2623,7 +2704,7 @@ bool SharedCache<A>::update(bool force, bool optimize, bool deleteExistingFirst,
                                }
                                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
@@ -2644,6 +2725,70 @@ bool SharedCache<A>::update(bool force, bool optimize, bool deleteExistingFirst,
                                memcpy(&inMemoryCache[cacheHeader->slideInfoOffset()], slideInfo, slideInfoPageSize);   
                        }
                        
+                       // make sure after all optimizations, that whole cache file fits into shared region address range
+                       {
+                               dyldCacheHeader<E>* cacheHeader = (dyldCacheHeader<E>*)inMemoryCache;
+                               dyldCacheFileMapping<E>* mappings = (dyldCacheFileMapping<E>*)&inMemoryCache[cacheHeader->mappingOffset()];
+                               for (int i=0; i < cacheHeader->mappingCount(); ++i) {
+                                       uint64_t endAddr = mappings[i].address() + mappings[i].size();
+                                       if ( endAddr > (sharedRegionStartAddress() + sharedRegionSize()) ) {
+                                               throwf("update_dyld_shared_cache[%u] for arch=%s, shared cache will not fit in address space: 0x%llX\n",
+                                                       getpid(), fArchGraph->archName(), endAddr);
+                                       }
+                               }
+                       }
+                       
+                       // append local symbol info in an unmapped region
+                       if ( dontMapLocalSymbols ) {
+                               uint32_t spaceAtEnd = allocatedCacheSize - cacheFileSize;
+                               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
@@ -2758,6 +2903,9 @@ bool SharedCache<A>::update(bool force, bool optimize, bool deleteExistingFirst,
                                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
@@ -2788,7 +2936,7 @@ bool SharedCache<A>::update(bool force, bool optimize, bool deleteExistingFirst,
                                
                                
                                // flush everything to disk to assure rename() gets recorded
-                               ::sync();
+                               sync_volume(fCacheFilePath);
                                didUpdate = true;
                                
                                // restore default signal handlers
@@ -2817,57 +2965,71 @@ bool SharedCache<A>::update(bool force, bool optimize, bool deleteExistingFirst,
                                                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) 
@@ -2967,8 +3129,9 @@ static void parsePathsFile(const char* filePath, std::vector<const char*>& paths
                                        // <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);
@@ -3108,7 +3271,7 @@ static void deleteOrphanTempCacheFiles()
 
 
 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
@@ -3136,19 +3299,19 @@ static bool updateSharedeCacheFile(const char* rootPath, const char* overlayPath
                        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;
                }
@@ -3179,6 +3342,7 @@ int main(int argc, const char* argv[])
        bool verify = false;
        bool keepSignatures = false;
        bool explicitCacheDir = false;
+       bool dontMapLocalSymbols = false;
        const char* cacheDir = NULL;
        
        try {
@@ -3207,8 +3371,12 @@ int main(int argc, const char* argv[])
                                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];
@@ -3249,6 +3417,8 @@ int main(int argc, const char* argv[])
                                                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);
                                }
@@ -3316,8 +3486,23 @@ int main(int argc, const char* argv[])
                        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);
index 58b22829d8b5bb5fe507f715e2d2f96964f7373a..65820ed7b007ef6e498aae63ec1751a35c677a3c 100644 (file)
@@ -24,6 +24,7 @@
 
 #define __STDC_LIMIT_MACROS
 #include <stdint.h>
+#include <stdlib.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <mach/mach.h>
@@ -65,32 +66,24 @@ uintptr_t                                                           ImageLoader::fgNextPIEDylibAddress = 0;
 
 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;
 }
 
@@ -101,12 +94,6 @@ ImageLoader::~ImageLoader()
                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)
@@ -122,27 +109,6 @@ void ImageLoader::setMapped(const LinkContext& context)
        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 ) {
@@ -304,6 +270,16 @@ void ImageLoader::getMappedRegions(MappedRegion*& regions) const
 }
 
 
+
+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)
@@ -375,9 +351,9 @@ void ImageLoader::applyInterposing(const LinkContext& context)
                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);
@@ -399,10 +375,11 @@ void ImageLoader::link(const LinkContext& context, bool forceLazysBound, bool pr
        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);
@@ -434,8 +411,7 @@ void ImageLoader::link(const LinkContext& context, bool forceLazysBound, bool pr
 
 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() );
 }
 
 
@@ -484,6 +460,29 @@ bool ImageLoader::allDependentLibrariesAsWhenPreBound() const
 }
 
 
+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 
@@ -555,10 +554,8 @@ void ImageLoader::recursiveLoadLibraries(const LinkContext& context, bool prefli
                                if ( fNeverUnload )
                                        dependentLib->setNeverUnload();
                                if ( requiredLibInfo.upward ) {
-                                       dependentLib->fIsReferencedUpward = true;
                                }
                                else { 
-                                       dependentLib->fStaticReferenceCount += 1;
                                        dependentLib->fIsReferencedDownward = true;
                                }
                                LibraryInfo actualInfo = dependentLib->doGetLibraryInfo();
@@ -698,7 +695,7 @@ void ImageLoader::recursiveApplyInterposing(const LinkContext& context)
 
 
 
-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:
@@ -713,13 +710,16 @@ void ImageLoader::recursiveBind(const LinkContext& context, bool forceLazysBound
                        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);
                }
@@ -736,6 +736,7 @@ void ImageLoader::weakBind(const LinkContext& context)
 {
        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);
@@ -841,6 +842,9 @@ void ImageLoader::weakBind(const LinkContext& context)
                        imagesNeedingCoalescing[i]->fWeakSymbolsBound = true;
                }
        }
+       uint64_t t2 = mach_absolute_time();
+       fgTotalWeakBindTime += t2  - t1;
+       
        if ( context.verboseWeakBind )
                dyld::log("dyld: weak bind end\n");
 }
@@ -863,6 +867,19 @@ void ImageLoader::recursiveGetDOFSections(const LinkContext& context, std::vecto
        }
 }
 
+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)
 {
@@ -920,7 +937,7 @@ void ImageLoader::recursiveInitialization(const LinkContext& context, mach_port_
                        
                        // initialize this image
                        bool hasInitializers = this->doInitialization(context);
-                       
+
                        // <rdar://problem/10491874> initialize any upward depedencies
                        if ( hasUpwards ) {
                                for(unsigned int i=0; i < libraryCount(); ++i) {
@@ -1074,5 +1091,8 @@ void ImageLoader::addSuffix(const char* path, const char* suffix, char* result)
 }
 
 
+VECTOR_NEVER_DESTRUCTED_IMPL(ImageLoader::InterposeTuple);
+VECTOR_NEVER_DESTRUCTED_IMPL(ImagePair);
+
 
 
index 83bc1fe03788655a1926e970c1025db4727edb83..4e00826c1f334b54fc34500f79b6dc13a78a895c 100644 (file)
 
 #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 {
@@ -108,7 +135,9 @@ 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__
@@ -176,6 +205,11 @@ public:
                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);
@@ -196,6 +230,9 @@ public:
                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
@@ -211,7 +248,9 @@ public:
                const char**    rootPaths;
                PrebindMode             prebindUsage;
                SharedRegionMode sharedRegionMode;
-               bool                    dyldLoadedAtSameAddressNeededBySharedCache; 
+               bool                    dyldLoadedAtSameAddressNeededBySharedCache;
+               bool                    codeSigningEnforced;
+               bool                    mainExecutableCodeSigned;
                bool                    preFetchDisabled;
                bool                    prebinding;
                bool                    bindFlat;
@@ -231,6 +270,7 @@ public:
                bool                    verboseWarnings;
                bool                    verboseRPaths;
                bool                    verboseInterposing;
+               bool                    verboseCodeSignatures;
        };
        
        struct CoalIterator
@@ -269,7 +309,7 @@ public:
        
                                                                                // 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
@@ -464,12 +504,16 @@ public:
        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; }
@@ -483,15 +527,17 @@ public:
        
        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);
@@ -504,7 +550,9 @@ public:
                                                                                // 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);
                                                
@@ -514,15 +562,25 @@ public:
                        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 {
@@ -548,12 +606,6 @@ protected:
        };
 
 
-       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);
        
@@ -565,7 +617,6 @@ protected:
        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);
@@ -573,8 +624,7 @@ protected:
        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&);
@@ -626,10 +676,7 @@ protected:
        
                                                                // 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;
@@ -653,6 +700,7 @@ protected:
        static uint64_t                         fgTotalDOF;
        static uint64_t                         fgTotalInitTime;
        static std::vector<InterposeTuple>      fgInterposingTuples;
+       
        const char*                                     fPath;
        const char*                                     fRealPath;
        dev_t                                           fDevice;
@@ -660,9 +708,6 @@ protected:
        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 {
@@ -691,17 +736,18 @@ private:
                                                                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
index 3a8ad7d17e2096b3266d9ee15df7223e026c2c8c..1f636cb7fa41af46e7f615ab2fd5b3f016a07425 100644 (file)
 #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
@@ -60,12 +64,14 @@ extern "C" long __stack_chk_guard;
 #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  {};  
@@ -114,7 +120,7 @@ ImageLoaderMachO::ImageLoaderMachO(const macho_header* mh, const char* path, uns
 
 // 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;
@@ -122,9 +128,11 @@ void ImageLoaderMachO::sniffLoadCommands(const macho_header* mh, const char* pat
        *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);
@@ -140,16 +148,22 @@ void ImageLoaderMachO::sniffLoadCommands(const macho_header* mh, const char* pat
                                // 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:
@@ -169,11 +183,28 @@ void ImageLoaderMachO::sniffLoadCommands(const macho_header* mh, const char* pat
                }
        }
        
-#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);
@@ -197,12 +228,16 @@ ImageLoader* ImageLoaderMachO::instantiateMainExecutable(const macho_header* mh,
        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
 }
 
 
@@ -225,12 +260,16 @@ ImageLoader* ImageLoaderMachO::instantiateFromFile(const char* path, int fd, con
        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
@@ -241,12 +280,16 @@ ImageLoader* ImageLoaderMachO::instantiateFromCache(const macho_header* mh, cons
        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
@@ -256,15 +299,34 @@ ImageLoader* ImageLoaderMachO::instantiateFromMemory(const char* moduleName, con
        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()
 {
@@ -689,19 +751,57 @@ void ImageLoaderMachO::setSlide(intptr_t slide)
        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
@@ -755,6 +855,24 @@ void ImageLoaderMachO::registerInterposing()
        }
 }
 
+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;
@@ -960,8 +1078,8 @@ void ImageLoaderMachO::getRPaths(const LinkContext& context, std::vector<const c
                                        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);
@@ -1078,8 +1196,10 @@ void ImageLoaderMachO::makeTextSegmentWritable(const LinkContext& context, bool
                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);
        }
 }
@@ -1120,7 +1240,7 @@ uintptr_t ImageLoaderMachO::getExportedSymbolAddress(const Symbol* sym, const Li
 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'
@@ -1526,7 +1646,7 @@ void ImageLoaderMachO::doImageInit(const LinkContext& context)
                                                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;
                        }
@@ -1727,14 +1847,14 @@ uintptr_t ImageLoaderMachO::reserveAnAddressRange(size_t length, const ImageLoad
                 // 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";
        
@@ -1745,7 +1865,7 @@ bool ImageLoaderMachO::reserveAddressRange(uintptr_t start, size_t length)
 {
        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;
@@ -1787,7 +1907,7 @@ void ImageLoaderMachO::mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInF
                                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());
index c3e192bb7ff06b531dfe72c7522c2d906029d56c..6d5c7442c2bab8c3ba6059be5ce9e08f3037ce57 100644 (file)
@@ -100,6 +100,7 @@ public:
        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&);
@@ -120,7 +121,7 @@ protected:
        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;
@@ -154,14 +155,13 @@ protected:
 
                        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);
index 2d0cf1b20904aaafb4247bccd55bc28779529d36..3eed9da87ece924d7c7db70fa5be8dc82d31843e 100644 (file)
@@ -136,11 +136,8 @@ ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateFromFile(const char
                // 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);
@@ -953,7 +950,7 @@ bool ImageLoaderMachOClassic::containsSymbol(const void* addr) const
 }
 
 
-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;
@@ -1058,8 +1055,8 @@ uintptr_t ImageLoaderMachOClassic::resolveUndefined(const LinkContext& context,
                }
                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
@@ -1081,8 +1078,8 @@ uintptr_t ImageLoaderMachOClassic::resolveUndefined(const LinkContext& context,
                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");
@@ -1686,8 +1683,9 @@ void ImageLoaderMachOClassic::updateUsesCoalIterator(CoalIterator& it, uintptr_t
                }
                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;
index 5d766508a0e6ca8a1d833dc0002e7c48bc5a675e..55685a5995021612dda013fa829b64d8a0327f48 100644 (file)
@@ -74,7 +74,7 @@ protected:
        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;
index 2d0cca2446e7b5c99aa47090af30f3a03a50d380..5ba89ec01f14d6714ee99a624975422c238c574c 100644 (file)
@@ -38,6 +38,9 @@
 #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__
@@ -110,7 +113,6 @@ ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateMainExecutabl
        if ( slide != 0 )
                fgNextPIEDylibAddress = (uintptr_t)image->getEnd();
        
-       image->setNeverUnload();
        image->instantiateFinish(context);
        image->setMapped(context);
        
@@ -140,15 +142,15 @@ ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromFile(cons
                // 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);
                
@@ -628,7 +630,7 @@ bool ImageLoaderMachOCompressed::containsSymbol(const void* addr) const
 }
 
 
-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;
@@ -637,37 +639,41 @@ uintptr_t ImageLoaderMachOCompressed::exportedSymbolAddress(const LinkContext& c
                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
@@ -719,8 +725,8 @@ uintptr_t ImageLoaderMachOCompressed::resolveFlat(const LinkContext& context, co
 {
        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
@@ -1070,7 +1076,7 @@ void ImageLoaderMachOCompressed::eachLazyBind(const LinkContext& context, bind_h
                                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:
@@ -1336,7 +1342,7 @@ bool ImageLoaderMachOCompressed::incrementCoalIterator(CoalIterator& it)
                                }
                                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...
@@ -1430,9 +1436,10 @@ void ImageLoaderMachOCompressed::updateUsesCoalIterator(CoalIterator& it, uintpt
                        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*, 
@@ -1551,7 +1558,7 @@ void ImageLoaderMachOCompressed::resetPreboundLazyPointers(const LinkContext& co
 
 
 #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;
@@ -1571,8 +1578,17 @@ void ImageLoaderMachOCompressed::updateAlternateLazyPointer(uint8_t* stub, void*
 
    // 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
@@ -1635,7 +1651,7 @@ void ImageLoaderMachOCompressed::updateOptimizedLazyPointers(const LinkContext&
         // 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
index 99c55294d0be209d058374f6070aa12e88b11ce1..6d8c5b773908723b939b17ce3b4323e8d29f95c7 100644 (file)
@@ -76,7 +76,7 @@ protected:
        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;
@@ -130,7 +130,7 @@ private:
                                                                                                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;
 };
index 6854ef51f92ec64e809ef04a361c0112b0672774..d143bc9238e869fee7f48a55089d3c4e84e045f6 100644 (file)
 #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> 
@@ -44,7 +49,8 @@
 #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
@@ -82,6 +88,7 @@
 #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
@@ -134,7 +134,19 @@ extern "C" void* __dso_handle;
 //
 //
 //
+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 {
 
@@ -181,15 +193,17 @@ struct EnvironmentVariables {
                                                        //      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;
@@ -197,7 +211,7 @@ static cpu_subtype_t                                sHostCPUsubtype;
 #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;
@@ -205,8 +219,8 @@ static std::vector<ImageLoader*>    sImageFilesNeedingTermination;
 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 };
@@ -217,7 +231,7 @@ static ImageLoader*                                 sBundleBeingLoaded = NULL;      // hack until OFI is reworked
 static const dyld_cache_header*                sSharedCache = NULL;
 static long                                                    sSharedCacheSlide = 0;
 static bool                                                    sSharedCacheIgnoreInodeAndTimeStamp = false;
-#if __IPHONE_OS_VERSION_MIN_REQUIRED   
+#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;
@@ -232,6 +246,13 @@ const struct LibSystemHelpers*             gLibSystemHelpers = NULL;
 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.
@@ -348,8 +369,9 @@ void throwf(const char* format, ...)
 
 
 //#define ALTERNATIVE_LOGFILE "/dev/console"
-
+#if !TARGET_IPHONE_SIMULATOR
 static int sLogfile = STDERR_FILENO;
+#endif
 
 #if LOG_BINDINGS
 static int sBindingsLogfile = -1;
@@ -377,27 +399,96 @@ void logBindings(const char* format, ...)
                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;
@@ -434,7 +525,7 @@ private:
 FileOpener::FileOpener(const char* path)
  : fd(-1)
 {
-       fd = open(path, O_RDONLY, 0);
+       fd = my_open(path, O_RDONLY, 0);
 }
 
 FileOpener::~FileOpener()
@@ -476,7 +567,7 @@ static void registerDOFs(const std::vector<ImageLoader::DOFInfo>& dofs)
                                        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);
                                        }
                                }
@@ -529,34 +620,33 @@ static const char* updateAllImages(enum dyld_image_states state, uint32_t infoCo
 }
 
 
-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());
@@ -592,8 +682,8 @@ static void notifySingle(dyld_image_states state, const ImageLoader* image)
                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);
                        }
@@ -611,7 +701,7 @@ static void notifySingle(dyld_image_states state, const ImageLoader* 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()
@@ -624,8 +714,8 @@ 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 ) {
@@ -721,8 +811,8 @@ static void notifyBatchPartial(dyld_image_states state, bool orLater, dyld_image
                                        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();
@@ -794,6 +884,29 @@ static void setRunInitialzersOldWay()
 }
 #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
@@ -831,17 +944,23 @@ static void addImage(ImageLoader* image)
        
 }
 
+//
+// 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() ) {
@@ -865,10 +984,6 @@ void removeImage(ImageLoader* image)
        // 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);
 
@@ -882,6 +997,9 @@ void removeImage(ImageLoader* 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;
@@ -904,6 +1022,28 @@ void removeImage(ImageLoader* image)
 }
 
 
+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);
@@ -917,10 +1057,6 @@ const char* getExecutablePath()
 
 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;
 
@@ -1007,7 +1143,11 @@ static void checkDylibOverride(const char* dylibFile)
                                                        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;
                                                        }
                                                }
@@ -1016,7 +1156,11 @@ static void checkDylibOverride(const char* dylibFile)
                                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);
                                }
@@ -1362,6 +1506,9 @@ void processDyldEnvironmentVariable(const char* key, const char* value, const ch
        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;
@@ -1460,6 +1607,20 @@ static void checkLoadCommandEnvironmentVariables()
 }
 #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()
@@ -1500,6 +1661,8 @@ static void pruneEnvironmentVariables(const char* envp[], const char*** applep)
                }
        }
        *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) {
@@ -1516,7 +1679,7 @@ static void pruneEnvironmentVariables(const char* envp[], const char*** applep)
                                break;
                }
        }
-       
+#endif
        // slide apple parameters
        if ( removedCount > 0 ) {
                *applep = d;
@@ -1583,6 +1746,12 @@ static void checkEnvironmentVariables(const char* envp[], bool ignoreEnviron)
                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 
@@ -1800,6 +1969,9 @@ static const cpu_subtype_t kARM[kARM_RowCount][9] = {
        // 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 },
        
@@ -2015,7 +2187,7 @@ static bool findInSharedCacheImage(const char* path, const struct stat* stat_buf
                // 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;
                }
@@ -2045,7 +2217,7 @@ static bool findInSharedCacheImage(const char* path, const struct stat* stat_buf
                                        // 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 ) {
@@ -2227,7 +2399,7 @@ static ImageLoader* loadPhase5load(const char* path, const char* orgPath, const
 
        // 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));
@@ -2268,7 +2440,7 @@ static ImageLoader* loadPhase5stat(const char* path, const LoadContext& context,
        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 ) {
@@ -2566,7 +2738,9 @@ static ImageLoader* loadPhase2(const char* path, const char* orgPath, const Load
                        }
                }
        }
-       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) {
@@ -2685,7 +2859,7 @@ ImageLoader* load(const char* path, const LoadContext& context)
                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 ) {
@@ -2732,11 +2906,6 @@ ImageLoader* load(const char* path, const LoadContext& context)
 #elif __x86_64__
        #define ARCH_NAME                       "x86_64"
        #define ARCH_CACHE_MAGIC        "dyld_v1  x86_64"
-       #define 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"
@@ -2746,27 +2915,15 @@ ImageLoader* load(const char* path, const LoadContext& context)
 #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
 
 
@@ -2778,10 +2935,9 @@ static int __attribute__((noinline)) _shared_region_check_np(uint64_t* start_add
 }
 
 
-static int __attribute__((noinline)) _shared_region_map_and_slide_np(int fd, uint32_t count, const shared_file_mapping_np mappings[], 
+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;
@@ -2789,10 +2945,11 @@ static int __attribute__((noinline)) _shared_region_map_and_slide_np(int fd, uin
                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);
        }
@@ -2801,7 +2958,7 @@ static int __attribute__((noinline)) _shared_region_map_and_slide_np(int fd, uin
        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;
@@ -2833,7 +2990,6 @@ static int __attribute__((noinline)) _shared_region_map_and_slide_np(int fd, uin
                }
        }
 
-#if SLIDEABLE_CACHE_SUPPORT
        // update all __DATA pages with slide info
        if ( slide != 0 ) {
                const uintptr_t dataPagesStart = mappings[1].sfm_address;
@@ -2860,7 +3016,6 @@ static int __attribute__((noinline)) _shared_region_map_and_slide_np(int fd, uin
                        }
                }
        }
-#endif // SLIDEABLE_CACHE_SUPPORT
 
        // succesfully mapped shared cache for just this process
        gLinkContext.sharedRegionMode = ImageLoader::kUsePrivateSharedRegion;
@@ -2876,54 +3031,64 @@ const void*     imMemorySharedCacheHeader()
 
 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
@@ -2933,31 +3098,36 @@ static long pickCacheSlide(uint32_t mappingsCount, shared_file_mapping_np mappin
        
        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__
@@ -2970,7 +3140,7 @@ static void mapSharedCache()
                        // 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) ) {
@@ -2996,6 +3166,8 @@ static void mapSharedCache()
                                        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;
@@ -3014,8 +3186,13 @@ static void mapSharedCache()
                                                                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
@@ -3030,13 +3207,12 @@ static void mapSharedCache()
                                                        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) {
@@ -3052,12 +3228,19 @@ static void mapSharedCache()
                                                        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)
@@ -3066,20 +3249,23 @@ static void mapSharedCache()
                                                        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 ) 
@@ -3150,7 +3336,6 @@ static void mapSharedCache()
                        }
                #endif
                }
-#if __IPHONE_OS_VERSION_MIN_REQUIRED   
                if ( gLinkContext.verboseMapping ) {
                        // list the code blob
                        dyld_cache_header* header = (dyld_cache_header*)sSharedCache;
@@ -3158,7 +3343,7 @@ static void mapSharedCache()
                        // 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 ) {
@@ -3167,9 +3352,10 @@ static void mapSharedCache()
                                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 
        }
 }
@@ -3293,10 +3479,10 @@ void halt(const char* message)
 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;
 }
 
 
@@ -3583,6 +3769,8 @@ static void setContext(const macho_header* mainExecutableMH, int argc, const cha
 #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;
@@ -3717,13 +3905,13 @@ static void printAllImages()
        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() )
@@ -3735,7 +3923,7 @@ void link(ImageLoader* image, bool forceLazysBound, const ImageLoader::RPathChai
        
        // process images
        try {
-               image->link(gLinkContext, forceLazysBound, false, loaderRPaths);
+               image->link(gLinkContext, forceLazysBound, false, neverUnload, loaderRPaths);
        }
        catch (const char* msg) {
                garbageCollectImages();
@@ -3752,36 +3940,100 @@ void runInitializers(ImageLoader* image)
        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();
+
 }
 
 
@@ -3801,7 +4053,7 @@ void preflight(ImageLoader* image, const ImageLoader::RPathChain& loaderRPaths)
        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);
@@ -3827,46 +4079,53 @@ static void loadInsertedDylib(const char* path)
                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
@@ -3891,6 +4150,166 @@ static void addDyldImageToUUIDList()
        }
 }
 
+#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
 
 
 //
@@ -3903,8 +4322,27 @@ uintptr_t
 _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);
@@ -3936,6 +4374,11 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide,
        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] != '/' ) {
@@ -3950,7 +4393,12 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide,
                        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
@@ -3983,18 +4431,22 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide,
        
 #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
@@ -4012,8 +4464,8 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide,
 
                // 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;
@@ -4025,11 +4477,20 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide,
                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
@@ -4052,7 +4513,7 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide,
                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) {
@@ -4077,8 +4538,7 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide,
 
 
 
-
-}; // namespace
+} // namespace
 
 
 
index 19b4431c14d4c1406ac051afa7f136bd288ea3ac..9c55ecdd2a465670416ff0af5bcd78bf54c58c2e 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #include <stdint.h>
+#include <sys/stat.h>
 
 #include "ImageLoader.h"
 #include "mach-o/dyld_priv.h"
@@ -58,8 +59,11 @@ namespace dyld {
 
 
        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;
@@ -69,9 +73,10 @@ namespace dyld {
        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);
@@ -89,7 +94,7 @@ namespace dyld {
        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();
@@ -103,9 +108,14 @@ namespace dyld {
        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);
+}
 
index d00118448979ebf78a5f29f40c18910f38131eb7..b99ea46728ac3cb636b3d3e7546dacbcb4647fdc 100644 (file)
@@ -147,6 +147,7 @@ static struct dyld_func dyld_funcs[] = {
 #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
@@ -239,6 +240,9 @@ struct __NSObjectFileImage
        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;
 
 
@@ -542,7 +546,7 @@ const struct mach_header* addImage(void* callerAddress, const char* path, bool s
                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(); 
@@ -972,6 +976,9 @@ NSModule NSLinkModule(NSObjectFileImage objectFileImage, const char* moduleName,
        
        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() ) {
@@ -998,7 +1005,7 @@ NSModule NSLinkModule(NSObjectFileImage objectFileImage, const char* moduleName,
                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();
@@ -1044,7 +1051,7 @@ static NSModule _dyld_link_module(NSObjectFileImage object_addr, size_t object_s
                        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 )
@@ -1107,6 +1114,7 @@ bool NSUnLinkModule(NSModule module, uint32_t options)
        ImageLoader* image = NSModuleToImageLoader(module);
        if ( image == NULL ) 
                return false;
+       dyld::runImageTerminators(image);
        dyld::removeImage(image);
        
        if ( (options & NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED) != 0 )
@@ -1182,9 +1190,9 @@ void _dyld_fork_child()
        // 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);
@@ -1262,7 +1270,7 @@ static void registerThreadHelpers(const dyld::LibSystemHelpers* helpers)
        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 )  {
@@ -1279,6 +1287,13 @@ static void registerThreadHelpers(const dyld::LibSystemHelpers* helpers)
 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';
@@ -1468,7 +1483,7 @@ void* dlopen(const char* path, int mode)
                        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 )
@@ -1514,9 +1529,12 @@ void* dlopen(const char* path, int mode)
                        // 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
@@ -1537,6 +1555,8 @@ void* dlopen(const char* path, int mode)
                CRSetCrashLogMessage(NULL);
                dyld::gLibSystemHelpers->releaseGlobalDyldLock();
        }
+       if ( dyld::gLogAPIs && (result != NULL) )
+               dyld::log("  %s(%s) ==> %p\n", __func__, path, result);
        return result;
 }
 
@@ -1562,7 +1582,8 @@ int dlclose(void* handle)
                        return -1;
                }
                // remove image if reference count went to zero
-               dyld::garbageCollectImages();
+               if ( image->dlopenCount() == 0 )
+                       dyld::garbageCollectImages();
                return 0;
        }
        else {
@@ -1622,6 +1643,12 @@ char* dlerror()
                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
@@ -1741,7 +1768,7 @@ void* dlsym(void* handle, const char* symbolName)
 
 const struct dyld_all_image_infos* _dyld_get_all_image_infos()
 {
-       return &dyld_all_image_infos;
+       return dyld::gProcessInfo;
 }
 
 #if !__arm__
@@ -1787,7 +1814,11 @@ const char* dyld_image_path_containing_address(const void* address)
 #if __IPHONE_OS_VERSION_MIN_REQUIRED   
 bool dyld_shared_cache_some_image_overridden()
 {
+ #if DYLD_SHARED_CACHE_SUPPORT
        return dyld::gSharedCacheOverridden;
+ #else
+    return true;
+ #endif
 }
 #endif
 
index 0417585d684bfd9da642327b3246ac3b6e6f5eaf..314c6588b43e8dba74868df8fdb712db82dd1479 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- 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);
@@ -423,6 +426,8 @@ const char* libraryName)
        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
@@ -435,68 +440,118 @@ const char* libraryName)
  */
 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;
 }
@@ -509,17 +564,23 @@ uint32_t dyld_get_program_sdk_version()
 
 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;
@@ -1192,6 +1253,32 @@ static char* getPerThreadBufferFor_dlerror(uint32_t sizeRequired)
        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()
@@ -1205,10 +1292,9 @@ static void shared_cache_out_of_date()
 }
 #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,
@@ -1220,7 +1306,11 @@ static dyld::LibSystemHelpers sHelpers = { 9, &dyldGlobalLockAcquire, &dyldGloba
                                                                        &malloc_size,
                                                                        &pthread_getspecific,
                                                                        &__cxa_finalize,
-                                                                       &start};
+                                                                       address_of_start,
+                                                                       &hasPerThreadBufferFor_dlerror,
+                                                                       &isLaunchdOwned,
+                                                                       &vm_allocate,
+                                                                       &mmap};
 
 
 //
@@ -1230,9 +1320,7 @@ static dyld::LibSystemHelpers sHelpers = { 9, &dyldGlobalLockAcquire, &dyldGloba
 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);
@@ -1383,6 +1471,19 @@ bool dyld_shared_cache_some_image_overridden()
 #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()
 {
index 2520f8fac505943c64dcc6ef06bfae082b20fe38..b015be520caf36423728f7655a4746433f2e2cf7 100644 (file)
@@ -67,7 +67,7 @@ static char                                                   sPreMainCxaGlobals[2*sizeof(long)];
 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 ) {
@@ -75,7 +75,7 @@ char* __cxa_get_globals()
                // 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);
@@ -87,10 +87,10 @@ char* __cxa_get_globals()
 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); 
 }
 
 
index a1266d7f68cf221e276d40c86aa737911abcd23c..7957c0c26b8ebecd054c702fcc283af44427e190 100644 (file)
@@ -27,6 +27,7 @@
 #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
 
 
 //
@@ -71,8 +81,14 @@ namespace dyld { extern bool isRosetta(); };
 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.
@@ -81,33 +97,11 @@ typedef void (*Initializer)(int argc, const char* argv[], const char* envp[], co
 //
 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 = &sectionsStart[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
 
 
 //
@@ -202,17 +196,7 @@ static void rebaseDyld(const struct macho_header* mh, intptr_t slide)
 
 
 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[]);
 
 
 //
@@ -229,12 +213,6 @@ uintptr_t start(const struct macho_header* appsMachHeader, int argc, const char*
                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();
 
@@ -246,15 +224,55 @@ uintptr_t start(const struct macho_header* appsMachHeader, int argc, const char*
        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
index 0fdda05463285b194576c80ccd81c375c4f0576d..20c6cdfec7e5c49a05153c6b0a6b265a4f168eb6 100644 (file)
 
 #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
 //
@@ -72,4 +78,5 @@ int _dyld_func_lookup(const char* dyld_func_name, void **address)
        return (*myDyldSection.lookup)(dyld_func_name, address);
 }
 
+#endif //! TARGET_IPHONE_SIMULATOR
 
index 9a5fd6085c8e95d4ce5363e769fcca37d1393602..f191f78855ea104026870405e19aeb98b57b03be 100644 (file)
@@ -63,9 +63,16 @@ namespace dyld {
                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
 
 
index dad139054a626d2274a92e91f33c827836e78b2f..18dfe1494f3d388b73902e0efc240a3dbbd71276 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- 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();
@@ -60,12 +47,12 @@ LockHelper::~LockHelper()
 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);
 }
 
index 2f4ec59edeed49978a050ae2469be91fa95c03fe..461012d6841d0d51c27d7b28b031a3ea0b118ae1 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- 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@
  * 
@@ -47,7 +47,6 @@
 //     }
 //
 
-#define DYLD_LOCK_INITIALIZER                  dyldGlobalLockInitialize()
 #define DYLD_LOCK_THIS_BLOCK                   LockHelper _dyld_lock;
 #define DYLD_NO_LOCK_THIS_BLOCK
 
index fe828eecff14edbedf42e559829ea5cbb1219844..bd99cde389be5b172abf0f92b9824e5df4b91c13 100644 (file)
@@ -27,6 +27,7 @@
 #include <stdint.h>
 #include <string.h>
 #include <mach/mach.h>
+#include <sys/mman.h>
 
 extern "C" void* __dso_handle;
 
@@ -40,7 +41,7 @@ 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
@@ -147,3 +148,26 @@ extern "C" int _malloc_lock;
 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);
+       }
+}
+
+
+
index 11c8f1ff123e5a5606aa2e6aebaf11caf70a6686..d340ee8392f6b23d54bb6cfe812ba688b08e52ae 100644 (file)
  */
 
 
-
-       // 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
@@ -99,14 +91,12 @@ _dyld_func_lookup:
        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
@@ -160,7 +150,7 @@ Lapple:     movl    (%ebx),%ecx     # look for NULL ending env[] array
        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:
@@ -171,10 +161,12 @@ L_end:
 
 
 #if __x86_64__
+#if !TARGET_IPHONE_SIMULATOR
        .data
        .align 3
 __dyld_start_static: 
        .quad   __dyld_start
+#endif
 
 # stable entry points into dyld
        .text
@@ -191,13 +183,11 @@ _dyld_func_lookup:
        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
@@ -239,7 +229,8 @@ Lapple: movq        (%rcx),%r8
        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__ */
 
 
@@ -263,11 +254,8 @@ _dyld_func_lookup:
        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
diff --git a/src/dyldSyscallInterface.h b/src/dyldSyscallInterface.h
new file mode 100644 (file)
index 0000000..a9bb0bf
--- /dev/null
@@ -0,0 +1,79 @@
+/* -*- 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
index 2afa79cc9b8562d28c541c9b5492b6bd34b7011a..3f1fa0e117cf34f18badc214f225aedf9c070e44 100644 (file)
@@ -33,6 +33,7 @@
 #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
@@ -51,26 +56,44 @@ void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[])
        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;
 }
 
@@ -79,14 +102,14 @@ const char* notifyGDB(enum dyld_image_states state, uint32_t infoCount, const dy
 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)
@@ -94,7 +117,7 @@ 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++) {
@@ -104,14 +127,14 @@ void removeImageFromAllImages(const struct mach_header* loadAddress)
                        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++) {
@@ -120,50 +143,59 @@ void removeImageFromAllImages(const struct mach_header* loadAddress)
                        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
  
diff --git a/src/dyld_sim.exp b/src/dyld_sim.exp
new file mode 100644 (file)
index 0000000..ccc744a
--- /dev/null
@@ -0,0 +1,31 @@
+#
+#  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
+
index 0636dbd738b01e5d5be441ca77f7e1415155f6ec..9949a879bc0b4355c71c525d965ae642c8bf0c5f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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__
 
@@ -54,7 +60,7 @@ dyld_stub_binder:
        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
@@ -97,16 +103,24 @@ dyld_stub_binder_:
 #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
@@ -126,28 +140,55 @@ dyld_stub_binder:
        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
@@ -189,3 +230,7 @@ dyld_stub_binder:
 
 #endif /* __arm__ */
 
+       
+       
+// simulator does not have full libdyld.dylib - just a small libdyld_sim.dylib
+#endif // ! TARGET_IPHONE_SIMULATOR
index 9ccc656f5e6934277db350a1f0fc5ce1f742d3eb..69b5f2283e596f9e9afab160b9730c61f007e02d 100644 (file)
 #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;
@@ -167,8 +180,9 @@ void __cxa_atexit()
 // 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 ) {
@@ -189,13 +203,15 @@ void __guard_setup(int argc, const char* argv[], const char* envp[], const char*
                                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()
 {
@@ -277,3 +293,175 @@ void* memset(void* b, int c, size_t len)
        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
+
+
diff --git a/src/libdyld_sim.exp b/src/libdyld_sim.exp
new file mode 100644 (file)
index 0000000..be8a4e4
--- /dev/null
@@ -0,0 +1,5 @@
+_dyld_get_sdk_version
+_dyld_get_program_sdk_version
+_dyld_get_min_os_version
+_dyld_get_program_min_os_version
+
diff --git a/src/start_glue.h b/src/start_glue.h
new file mode 100644 (file)
index 0000000..4e21bec
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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__
index 4ccfd39d8cb630ea4707b506f0c840178221c660..b35eb50a2b4e7be57cfa9aaa0fde55d8166b0466 100644 (file)
     .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__ */
 
 
@@ -43,9 +43,9 @@ _start:
     .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
@@ -56,13 +56,17 @@ _start:
 #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
+       
index b5bc9d56d699b2ead0a6a1a80d57bfdb10683486..7830d8db6489bcaf255203d753814075d334111a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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:
@@ -37,7 +43,7 @@ _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)
@@ -46,11 +52,87 @@ LlazyAllocate:
        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
@@ -59,7 +141,7 @@ LlazyAllocate:
        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
@@ -123,4 +205,6 @@ L2: ldr             r1, [r7, #8]                                    // get offset from descriptor
 #endif
 #endif
 
+       .subsections_via_symbols
+       
 
index 2586455ed2f6462b725b73b1a7b5a3011af114f8..b5fcd6d7815505b2d2bbdef34bcf6275b4b6dac0 100644 (file)
        #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;
@@ -165,9 +170,12 @@ __attribute__((visibility("hidden")))
 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;
@@ -360,7 +368,6 @@ void dyld_enumerate_tlv_storage(dyld_tlv_state_change_handler handler)
 // destructor key to come before the deallocation key.
 //
 
-typedef void (*TermFunc)(void*);
 struct TLVTerminatorListEntry
 {
     TermFunc    termFunc;
@@ -411,13 +418,14 @@ void _tlv_atexit(TermFunc func, void* objAddr)
     }
 }
 
-// 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);
         }
@@ -425,6 +433,16 @@ static void tlv_finalize(void* storage)
     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()
@@ -446,9 +464,9 @@ void _tlv_bootstrap()
 }
 
 
-// __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)
@@ -459,13 +477,21 @@ void dyld_enumerate_tlv_storage(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)
 
 
index ba256c883b0b31727dc890e0800dacb5d56f64b2..36b4ed92dcbc55f24acf0ed42d27e8ebe748eb47 100644 (file)
@@ -23,12 +23,19 @@ endif
 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
@@ -66,3 +73,4 @@ ifeq ($(ARCH),thumb2)
 else
   FILEARCH = $(ARCH)
 endif
+
index ceb2106175320b8adf5a54df3f1bd86d91b23c8f..d1df892e859bbf1efaa0d82a2428715ce94de330 100755 (executable)
@@ -8,7 +8,7 @@ CRSTATE=`defaults read com.apple.CrashReporter DialogType`
 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 * * *"
index 5c0374b60e36fa06f432aa008b7cf3d15c85387e..72ca37ba91953ce70e0c577a210285fc002bff71 100644 (file)
@@ -41,16 +41,17 @@ check-ios:
 
 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  
 
index 2815ba1fc4a15c334671077aec18bb5957a04351..a43882fe5f951bfff07cb41a906ff13518185853 100644 (file)
@@ -25,6 +25,7 @@
 #include <dlfcn.h>
 #include <string.h>
 #include <stdlib.h> // for atoi()
+#include <mach-o/dyld.h>
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
@@ -35,6 +36,21 @@ extern int foo();
 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);
diff --git a/unit-tests/test-cases/absolute-symbol/Makefile b/unit-tests/test-cases/absolute-symbol/Makefile
new file mode 100644 (file)
index 0000000..1c06dda
--- /dev/null
@@ -0,0 +1,21 @@
+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
+
diff --git a/unit-tests/test-cases/absolute-symbol/abs.s b/unit-tests/test-cases/absolute-symbol/abs.s
new file mode 100644 (file)
index 0000000..2352520
--- /dev/null
@@ -0,0 +1,12 @@
+
+       .global  _myAbs1
+_myAbs1 = 0
+
+
+
+       .global  _myAbs2
+_myAbs2 = 1
+
+
+
+_myLocalAbs = 3
diff --git a/unit-tests/test-cases/absolute-symbol/foo.c b/unit-tests/test-cases/absolute-symbol/foo.c
new file mode 100644 (file)
index 0000000..8d231e0
--- /dev/null
@@ -0,0 +1,5 @@
+
+
+int var = 5;
+void func() { }
+
diff --git a/unit-tests/test-cases/absolute-symbol/main.c b/unit-tests/test-cases/absolute-symbol/main.c
new file mode 100644 (file)
index 0000000..e6b61f3
--- /dev/null
@@ -0,0 +1,31 @@
+#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;
+}
index 003881fe91f20f90e7ce51735387a60678415312..2c83e2d64051d3d969967786037b243cb3bca0a2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2006-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -48,32 +48,12 @@ void foo(unsigned long long stackSize, char* stackStart)
                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;
 }
 
index e87cda5f81b5ac85327d8ef2ea883ba9d3b005bd..00641d0164f8ab52781bf73aca48a87b21103845 100644 (file)
@@ -23,7 +23,7 @@
 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
 
diff --git a/unit-tests/test-cases/bundle-terminator/Makefile b/unit-tests/test-cases/bundle-terminator/Makefile
new file mode 100644 (file)
index 0000000..8e11cff
--- /dev/null
@@ -0,0 +1,37 @@
+##
+# 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
+
diff --git a/unit-tests/test-cases/bundle-terminator/bundle.cxx b/unit-tests/test-cases/bundle-terminator/bundle.cxx
new file mode 100644 (file)
index 0000000..b94ced2
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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;
+
diff --git a/unit-tests/test-cases/bundle-terminator/main.c b/unit-tests/test-cases/bundle-terminator/main.c
new file mode 100644 (file)
index 0000000..d7fd707
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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
index bc160be597304c3f323ed2db1376709f49910975..73b71acf87b7073ea21d3c73d494aebdde5030ab 100644 (file)
@@ -45,7 +45,7 @@ main: main.c
        ${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
index aab6ce682e8b4b65fb0bf861c6a5ba71839905cf..367730afda802203b88a79fb3f6c7ad9a7f16088 100644 (file)
@@ -42,7 +42,7 @@ main: main.c
        ${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
index a3ac2a460e0040e1938230866335eb7508606011..2e537bd41983c3de20ce3779be4a1ef5adb2e2e3 100644 (file)
@@ -30,7 +30,7 @@ check:
 
 all:
        ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c 
-       strip main
+       ${STRIP} main
        
 
 clean:
diff --git a/unit-tests/test-cases/dlclose-dylib-dynamic-ref/Makefile b/unit-tests/test-cases/dlclose-dylib-dynamic-ref/Makefile
new file mode 100644 (file)
index 0000000..ac4fb27
--- /dev/null
@@ -0,0 +1,40 @@
+##
+# 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
+
diff --git a/unit-tests/test-cases/dlclose-dylib-dynamic-ref/bar.c b/unit-tests/test-cases/dlclose-dylib-dynamic-ref/bar.c
new file mode 100644 (file)
index 0000000..d0fd23c
--- /dev/null
@@ -0,0 +1,8 @@
+__attribute__((weak))
+int mydata;
+
+
+int bar()
+{
+       return mydata;
+}
diff --git a/unit-tests/test-cases/dlclose-dylib-dynamic-ref/baz.c b/unit-tests/test-cases/dlclose-dylib-dynamic-ref/baz.c
new file mode 100644 (file)
index 0000000..a3a1b44
--- /dev/null
@@ -0,0 +1,8 @@
+__attribute__((weak))
+int mydata;
+
+
+int baz()
+{
+       return mydata;
+}
diff --git a/unit-tests/test-cases/dlclose-dylib-dynamic-ref/foo.c b/unit-tests/test-cases/dlclose-dylib-dynamic-ref/foo.c
new file mode 100644 (file)
index 0000000..899bb44
--- /dev/null
@@ -0,0 +1,8 @@
+__attribute__((weak))
+int mydata;
+
+
+int foo()
+{
+       return mydata;
+}
diff --git a/unit-tests/test-cases/dlclose-dylib-dynamic-ref/main.c b/unit-tests/test-cases/dlclose-dylib-dynamic-ref/main.c
new file mode 100644 (file)
index 0000000..9c39733
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * 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;
+}
diff --git a/unit-tests/test-cases/dlclose-dylib-ref-count/Makefile b/unit-tests/test-cases/dlclose-dylib-ref-count/Makefile
new file mode 100644 (file)
index 0000000..63e2f78
--- /dev/null
@@ -0,0 +1,40 @@
+##
+# 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
+
diff --git a/unit-tests/test-cases/dlclose-dylib-ref-count/bar.c b/unit-tests/test-cases/dlclose-dylib-ref-count/bar.c
new file mode 100644 (file)
index 0000000..8312b89
--- /dev/null
@@ -0,0 +1,6 @@
+
+
+int bar()
+{
+       return 10;
+}
diff --git a/unit-tests/test-cases/dlclose-dylib-ref-count/base.c b/unit-tests/test-cases/dlclose-dylib-ref-count/base.c
new file mode 100644 (file)
index 0000000..e7e0d08
--- /dev/null
@@ -0,0 +1 @@
+void base() { }
diff --git a/unit-tests/test-cases/dlclose-dylib-ref-count/foo.c b/unit-tests/test-cases/dlclose-dylib-ref-count/foo.c
new file mode 100644 (file)
index 0000000..8184cd1
--- /dev/null
@@ -0,0 +1,5 @@
+
+int foo()
+{
+       return 10;
+}
diff --git a/unit-tests/test-cases/dlclose-dylib-ref-count/main.c b/unit-tests/test-cases/dlclose-dylib-ref-count/main.c
new file mode 100644 (file)
index 0000000..5902d82
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * 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;
+}
diff --git a/unit-tests/test-cases/dlclose-dylib-terminators/Makefile b/unit-tests/test-cases/dlclose-dylib-terminators/Makefile
new file mode 100644 (file)
index 0000000..e6d0b4c
--- /dev/null
@@ -0,0 +1,43 @@
+##
+# 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
+
diff --git a/unit-tests/test-cases/dlclose-dylib-terminators/bar.cpp b/unit-tests/test-cases/dlclose-dylib-terminators/bar.cpp
new file mode 100644 (file)
index 0000000..2815167
--- /dev/null
@@ -0,0 +1,17 @@
+extern "C" int bazData;
+
+class BazUser {
+public:
+       BazUser() { }
+       ~BazUser() { bazData = 0; }
+};
+
+
+BazUser b;
+
+
+int bar()
+{
+       return bazData;
+}
+
diff --git a/unit-tests/test-cases/dlclose-dylib-terminators/baz.c b/unit-tests/test-cases/dlclose-dylib-terminators/baz.c
new file mode 100644 (file)
index 0000000..b5a740e
--- /dev/null
@@ -0,0 +1,7 @@
+int bazData = 5;
+
+
+int baz()
+{
+       return bazData;
+}
diff --git a/unit-tests/test-cases/dlclose-dylib-terminators/foo.cpp b/unit-tests/test-cases/dlclose-dylib-terminators/foo.cpp
new file mode 100644 (file)
index 0000000..ead0e83
--- /dev/null
@@ -0,0 +1,23 @@
+
+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()
+{
+}
diff --git a/unit-tests/test-cases/dlclose-dylib-terminators/main.c b/unit-tests/test-cases/dlclose-dylib-terminators/main.c
new file mode 100644 (file)
index 0000000..34d2d0d
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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;
+}
index cada146d8b45a3d15d3f127d600c87c88e5fd890..8300a4106d498073fb61ec5426edd372b1651453 100644 (file)
@@ -92,7 +92,7 @@ int main()
                FAIL("dlclose-unload-c++: libfoo should have been unloaded");
                exit(0);
        }
-               
+       
        PASS("dlclose-unload-c++");
        return EXIT_SUCCESS;
 }
diff --git a/unit-tests/test-cases/dlopen-codesign-dynamic/Makefile b/unit-tests/test-cases/dlopen-codesign-dynamic/Makefile
new file mode 100644 (file)
index 0000000..aabd547
--- /dev/null
@@ -0,0 +1,45 @@
+##
+# 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
diff --git a/unit-tests/test-cases/dlopen-codesign-dynamic/foo.c b/unit-tests/test-cases/dlopen-codesign-dynamic/foo.c
new file mode 100644 (file)
index 0000000..3695dc9
--- /dev/null
@@ -0,0 +1,3 @@
+void foo()
+{
+}
diff --git a/unit-tests/test-cases/dlopen-codesign-dynamic/main.c b/unit-tests/test-cases/dlopen-codesign-dynamic/main.c
new file mode 100644 (file)
index 0000000..37dba84
--- /dev/null
@@ -0,0 +1,45 @@
+#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;
+}
diff --git a/unit-tests/test-cases/dlopen-codesign/Makefile b/unit-tests/test-cases/dlopen-codesign/Makefile
new file mode 100644 (file)
index 0000000..9060b25
--- /dev/null
@@ -0,0 +1,43 @@
+##
+# 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
diff --git a/unit-tests/test-cases/dlopen-codesign/foo.c b/unit-tests/test-cases/dlopen-codesign/foo.c
new file mode 100644 (file)
index 0000000..3695dc9
--- /dev/null
@@ -0,0 +1,3 @@
+void foo()
+{
+}
diff --git a/unit-tests/test-cases/dlopen-codesign/main.c b/unit-tests/test-cases/dlopen-codesign/main.c
new file mode 100644 (file)
index 0000000..53fce5f
--- /dev/null
@@ -0,0 +1,27 @@
+#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;
+}
index 1afad6999356feabf8e30b597e225a22903fbea9..83d46ff5aa6bb85093808a5c045b53e037ca4b30 100644 (file)
@@ -42,8 +42,8 @@ all-check: all check
 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"; 
index c7fc150cff44c233d1467a11b53c3589f8c0ad66..ed9840e2d26bd0b2774d8cbbb10cd141ba397120 100644 (file)
@@ -75,8 +75,12 @@ int main()
 
        // 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;
 }
index b3a47a314867b6f414980b69bb6daa59aa86a3f9..a9f14c8491f7aa1552fbf9d21094ccbeadb47601 100644 (file)
@@ -42,8 +42,8 @@ all-check: all check
 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"; 
index 511a1408322697c7f5fbdbaca0770f8e6f400b86..d84b8e2f67b2dc163b2f98ac2b85dffc386c11e2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2013 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -39,10 +39,15 @@ int main()
                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;
 }
index 2a361da47882a0dbf2ed098629436674eaa47334..e62fe0dc35df2ee8130638d894ced19650688bd9 100644 (file)
@@ -42,7 +42,7 @@ all-check: all check
 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"; 
index 7a4f090ef6e61ed5ac0e2dde43bd81321bb0d460..a953bff5a7af2b8b5bb39e4864ef501c78bdf2e7 100644 (file)
@@ -40,8 +40,12 @@ int main()
        
        // 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;
 }
index 9562ac519f0faaabb46809814b083164d5d4249c..f5e572fe1edbda75ebf6a95f18ffd55f937a1615 100644 (file)
@@ -45,7 +45,7 @@ all-check: all check
 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"; 
index a7ffa5911c4ee4a6ab96f0f2e9f08557715ce1b4..4d90de47e7e457f578f584d518a2dbc6b4e1bef4 100644 (file)
@@ -54,8 +54,12 @@ int main()
 
        // 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;
 }
index eff03d83c55cb4922e09e9a1c877a6096fedaa4a..1752c26f72d1bc6ea8fa156577807bd4a2c6d516 100644 (file)
@@ -42,8 +42,8 @@ all-check: all check
 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"; 
index 612e14181d7c6c70c88f9051f704eb3d2fd8a615..3f04f2eb23662402f0d3a78622c7b2cbc3602796 100644 (file)
@@ -38,8 +38,12 @@ int main()
        
        // 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;
 }
diff --git a/unit-tests/test-cases/framework-DYLD_LIBRARY_PATH/Makefile b/unit-tests/test-cases/framework-DYLD_LIBRARY_PATH/Makefile
new file mode 100644 (file)
index 0000000..569d814
--- /dev/null
@@ -0,0 +1,43 @@
+##
+# 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
diff --git a/unit-tests/test-cases/framework-DYLD_LIBRARY_PATH/foo.c b/unit-tests/test-cases/framework-DYLD_LIBRARY_PATH/foo.c
new file mode 100644 (file)
index 0000000..01c576d
--- /dev/null
@@ -0,0 +1,5 @@
+
+int foo()
+{
+       return RESULT;
+}
diff --git a/unit-tests/test-cases/framework-DYLD_LIBRARY_PATH/main.c b/unit-tests/test-cases/framework-DYLD_LIBRARY_PATH/main.c
new file mode 100644 (file)
index 0000000..7e6502e
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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;
+}
+
diff --git a/unit-tests/test-cases/interpose-multiple/Makefile b/unit-tests/test-cases/interpose-multiple/Makefile
new file mode 100644 (file)
index 0000000..99041ca
--- /dev/null
@@ -0,0 +1,54 @@
+##
+# Copyright (c) 2013 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+#
+
+#
+# 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 
+
diff --git a/unit-tests/test-cases/interpose-multiple/base.c b/unit-tests/test-cases/interpose-multiple/base.c
new file mode 100644 (file)
index 0000000..126f99e
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdio.h>
+#include "base.h"
+
+int base1() { return 1; }
+int base2() { return 2; }
+
diff --git a/unit-tests/test-cases/interpose-multiple/base.h b/unit-tests/test-cases/interpose-multiple/base.h
new file mode 100644 (file)
index 0000000..658b8a1
--- /dev/null
@@ -0,0 +1,3 @@
+
+extern int base1();
+extern int base2();
diff --git a/unit-tests/test-cases/interpose-multiple/foo1.c b/unit-tests/test-cases/interpose-multiple/foo1.c
new file mode 100644 (file)
index 0000000..0670559
--- /dev/null
@@ -0,0 +1,26 @@
+#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)
diff --git a/unit-tests/test-cases/interpose-multiple/foo2.c b/unit-tests/test-cases/interpose-multiple/foo2.c
new file mode 100644 (file)
index 0000000..1f2f362
--- /dev/null
@@ -0,0 +1,25 @@
+#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)
diff --git a/unit-tests/test-cases/interpose-multiple/main.c b/unit-tests/test-cases/interpose-multiple/main.c
new file mode 100644 (file)
index 0000000..e0bd1d1
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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;
+}
index 61d36e4a9c0cdf9986295a0a45b283009fbc8fac..981e577e955ec8df85532cd9252c9c90c620d477 100644 (file)
@@ -62,8 +62,8 @@ bar/libbase.dylib : base.c
 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:
index 7e646d1cea5e8735742f218f5b62c1453d671ab0..06eeb2b0c505b5df1a32e23b912e4848617c29d3 100644 (file)
@@ -47,8 +47,8 @@ libfoo2.dylib : foo.c
 
 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
index a22a543f29bf47221e58db79c6e774c85a73f7e4..0d2aa80c8fd95da3c3055f44c53e8a18d40d82ff 100644 (file)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2009 Apple Inc. All rights reserved.
+# Copyright (c) 2009-2013 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -27,8 +27,10 @@ SHELL = bash # use bash shell so we can redirect just stderr
 
 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`
@@ -37,6 +39,7 @@ all-check: all check
 
 check:
        ${RUN_AS_USER} $(PWD)/main-with-env 2>/dev/null
+       ${RUN_AS_ROOT} $(PWD)/main-with-env 2>/dev/null
 
 all: main
 
index c4c0da8ffd629b120ae7a4a32a60d19a8548b2bb..e68d0386d7dff185937255115a15c9c4f4e66668 100644 (file)
@@ -23,6 +23,7 @@
 #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()
 
@@ -58,6 +59,13 @@ int main(int argc, const char* argv[], const char* envp[], const char* apple[])
                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;
 }
index 0bea13aa94b83727601775aca24086cd8fb8f9ab..9d7195a9d869ff65e026f927d564ed1c765aacc0 100644 (file)
@@ -42,8 +42,8 @@ all-check: all check
 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;
index b33ceca8e85b5df70d0f3ffe45bec2955c952de8..993ea2501923586339d7743c839dab6f78308602 100644 (file)
@@ -40,8 +40,11 @@ int main()
        
        // 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;
 }
index a85ee6a1a0542462a7ec8e731d4332aa2e17e7df..62123312be2e465ab3f65b2752d6d4a08e7e8403 100644 (file)
@@ -4,6 +4,7 @@
 
 int myfoo()
 {
+       foo();
        return 20;
 }
 
diff --git a/unit-tests/test-cases/symbol-resolver-lazy-prebound/Makefile b/unit-tests/test-cases/symbol-resolver-lazy-prebound/Makefile
new file mode 100644 (file)
index 0000000..dc1021c
--- /dev/null
@@ -0,0 +1,56 @@
+##
+# 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
+
diff --git a/unit-tests/test-cases/symbol-resolver-lazy-prebound/bar.c b/unit-tests/test-cases/symbol-resolver-lazy-prebound/bar.c
new file mode 100644 (file)
index 0000000..870c431
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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;
+}
+
diff --git a/unit-tests/test-cases/symbol-resolver-lazy-prebound/foo.c b/unit-tests/test-cases/symbol-resolver-lazy-prebound/foo.c
new file mode 100644 (file)
index 0000000..bb9054c
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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();
+}
+
diff --git a/unit-tests/test-cases/symbol-resolver-lazy-prebound/main.c b/unit-tests/test-cases/symbol-resolver-lazy-prebound/main.c
new file mode 100644 (file)
index 0000000..212d02f
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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;
+}
diff --git a/unit-tests/test-cases/weak-coalesce-inserted/Makefile b/unit-tests/test-cases/weak-coalesce-inserted/Makefile
new file mode 100644 (file)
index 0000000..2c3f872
--- /dev/null
@@ -0,0 +1,42 @@
+##
+# 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
+
diff --git a/unit-tests/test-cases/weak-coalesce-inserted/base.c b/unit-tests/test-cases/weak-coalesce-inserted/base.c
new file mode 100644 (file)
index 0000000..a2d200b
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * 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");
+}
+
diff --git a/unit-tests/test-cases/weak-coalesce-inserted/base.h b/unit-tests/test-cases/weak-coalesce-inserted/base.h
new file mode 100644 (file)
index 0000000..482b832
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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);
diff --git a/unit-tests/test-cases/weak-coalesce-inserted/foo1.c b/unit-tests/test-cases/weak-coalesce-inserted/foo1.c
new file mode 100644 (file)
index 0000000..0707e0d
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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);
+}
+
+
diff --git a/unit-tests/test-cases/weak-coalesce-inserted/foo2.c b/unit-tests/test-cases/weak-coalesce-inserted/foo2.c
new file mode 100644 (file)
index 0000000..13e8b07
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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);
+}
diff --git a/unit-tests/test-cases/weak-coalesce-inserted/main.c b/unit-tests/test-cases/weak-coalesce-inserted/main.c
new file mode 100644 (file)
index 0000000..bf38e29
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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;
+}
+
+
index 03cb1077d89162b0bab50003c319af8a501a11fa..d55a5c50a3c8bc571f0f9fef1c85c30ca28086e0 100644 (file)
@@ -12,7 +12,7 @@ all:
        $(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