]> git.saurik.com Git - apple/dyld.git/commitdiff
dyld-195.5.tar.gz mac-os-x-107 mac-os-x-1071 mac-os-x-1072 v195.5
authorApple <opensource@apple.com>
Wed, 13 Jul 2011 00:07:10 +0000 (00:07 +0000)
committerApple <opensource@apple.com>
Wed, 13 Jul 2011 00:07:10 +0000 (00:07 +0000)
241 files changed:
bin/set-alt-dyld [new file with mode: 0755]
doc/man/man1/dyld.1
doc/man/man1/update_dyld_shared_cache.1
doc/man/man3/dyld.3
dyld.xcodeproj/project.pbxproj
include/mach-o/dyld.h
include/mach-o/dyld_images.h
include/mach-o/dyld_priv.h
launch-cache/CacheFileAbstraction.hpp
launch-cache/FileAbstraction.hpp
launch-cache/MachOBinder.hpp
launch-cache/MachOFileAbstraction.hpp
launch-cache/MachOLayout.hpp
launch-cache/MachORebaser.hpp
launch-cache/MachOTrie.hpp
launch-cache/ObjCLegacyAbstraction.hpp
launch-cache/ObjCModernAbstraction.hpp
launch-cache/dsc_extractor.cpp [new file with mode: 0644]
launch-cache/dsc_extractor.h [new file with mode: 0644]
launch-cache/dsc_iterator.cpp
launch-cache/dsc_iterator.h
launch-cache/dsc_slider.cpp [new file with mode: 0644]
launch-cache/dsc_slider.h [new file with mode: 0644]
launch-cache/dyld_cache_format.h
launch-cache/dyld_shared_cache_util.cpp [new file with mode: 0644]
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/dyld.order [new file with mode: 0644]
src/dyldAPIs.cpp
src/dyldAPIsInLibSystem.cpp
src/dyldExceptions.c
src/dyldInitialization.cpp
src/dyldLibSystemGlue.c
src/dyldLibSystemInterface.h
src/dyldStartup.s
src/dyld_debug.c
src/dyld_gdb.cpp
src/dyld_stub_binder.s
src/glue.c
src/threadLocalHelpers.s [new file with mode: 0644]
src/threadLocalVariables.c [new file with mode: 0644]
unit-tests/bin/build-results-filter.pl [new file with mode: 0755]
unit-tests/bin/exit-non-zero-pass.pl
unit-tests/bin/exit-zero-pass.pl
unit-tests/build-and-run-iPhoneOS-unit-tests [new file with mode: 0755]
unit-tests/build-iPhoneOS-unit-tests [new file with mode: 0755]
unit-tests/include/common.makefile
unit-tests/run-all-unit-tests
unit-tests/test-cases/DYLD_LIBRARY_PATH-dyld_env/Makefile [new file with mode: 0644]
unit-tests/test-cases/DYLD_LIBRARY_PATH-dyld_env/foo.c [new file with mode: 0644]
unit-tests/test-cases/DYLD_LIBRARY_PATH-dyld_env/main.c [new file with mode: 0644]
unit-tests/test-cases/DYLD_VERSIONED_FRAMEWORK_PATH-basic/Makefile [new file with mode: 0644]
unit-tests/test-cases/DYLD_VERSIONED_FRAMEWORK_PATH-basic/foo.c [new file with mode: 0644]
unit-tests/test-cases/DYLD_VERSIONED_FRAMEWORK_PATH-basic/main.c [new file with mode: 0644]
unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-basic/Makefile [new file with mode: 0644]
unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-basic/foo.c [new file with mode: 0644]
unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-basic/main.c [new file with mode: 0644]
unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env-restrict/Makefile [new file with mode: 0644]
unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env-restrict/foo.c [new file with mode: 0644]
unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env-restrict/main.c [new file with mode: 0644]
unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env/Makefile [new file with mode: 0644]
unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env/foo.c [new file with mode: 0644]
unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env/main.c [new file with mode: 0644]
unit-tests/test-cases/NSAddImage-MATCH_BY_INSTALLNAME/main.c
unit-tests/test-cases/NSAddImage-RETURN_ONLY_IF_LOADED/main.c
unit-tests/test-cases/NSAddImage-leafname/main.c
unit-tests/test-cases/NSAddressOfSymbol-NULL/main.c
unit-tests/test-cases/addend/main.c
unit-tests/test-cases/all_image_infos-cache-slide/Makefile [new file with mode: 0644]
unit-tests/test-cases/all_image_infos-cache-slide/main.c [new file with mode: 0644]
unit-tests/test-cases/all_image_infos-duplicate/Makefile [new file with mode: 0644]
unit-tests/test-cases/all_image_infos-duplicate/foo.c [new file with mode: 0644]
unit-tests/test-cases/all_image_infos-duplicate/main.c [new file with mode: 0644]
unit-tests/test-cases/all_image_infos-paths/Makefile [new file with mode: 0644]
unit-tests/test-cases/all_image_infos-paths/foo.c [new file with mode: 0644]
unit-tests/test-cases/all_image_infos-paths/main.c [new file with mode: 0644]
unit-tests/test-cases/all_image_infos/main.c
unit-tests/test-cases/always-libSystem/Makefile
unit-tests/test-cases/big-stack/Makefile
unit-tests/test-cases/branch-islands/Makefile [new file with mode: 0644]
unit-tests/test-cases/branch-islands/extra.c [new file with mode: 0644]
unit-tests/test-cases/branch-islands/main.c [new file with mode: 0644]
unit-tests/test-cases/branch-islands/space.s [new file with mode: 0644]
unit-tests/test-cases/bundle-basic/main.c
unit-tests/test-cases/bundle-dont-gc/main.c
unit-tests/test-cases/bundle-memory-load-all-infos/Makefile [new file with mode: 0644]
unit-tests/test-cases/bundle-memory-load-all-infos/bundle.c [new file with mode: 0644]
unit-tests/test-cases/bundle-memory-load-all-infos/main.c [new file with mode: 0644]
unit-tests/test-cases/bundle-memory-load-bad/main.c
unit-tests/test-cases/bundle-memory-load-fat/main.c
unit-tests/test-cases/bundle-memory-load-malloc/main.c
unit-tests/test-cases/bundle-memory-load/main.c
unit-tests/test-cases/bundle-multi-link/main.c
unit-tests/test-cases/bundle-multi-load/main.c
unit-tests/test-cases/bundle-name-ownership/main.c
unit-tests/test-cases/bundle-private/main.c
unit-tests/test-cases/bundle-reload/main.c
unit-tests/test-cases/bundle-unlinkable/main.c
unit-tests/test-cases/bundle-unload-keep-mapped/main.c
unit-tests/test-cases/bundle-v-dylib/main.c
unit-tests/test-cases/coreSymbolication-notify/Makefile [new file with mode: 0644]
unit-tests/test-cases/coreSymbolication-notify/bar.c [new file with mode: 0644]
unit-tests/test-cases/coreSymbolication-notify/foo.c [new file with mode: 0644]
unit-tests/test-cases/coreSymbolication-notify/main.c [new file with mode: 0644]
unit-tests/test-cases/crt-apple/Makefile
unit-tests/test-cases/crt-apple/main.c
unit-tests/test-cases/crt-argv-NULL/Makefile
unit-tests/test-cases/crt-custom/Makefile
unit-tests/test-cases/crt-custom/main.c
unit-tests/test-cases/crt-custom/mystart.s
unit-tests/test-cases/crt-libSystem/Makefile
unit-tests/test-cases/crt-result/Makefile
unit-tests/test-cases/cxa_finalize/foo.cxx
unit-tests/test-cases/deadlock/main.c
unit-tests/test-cases/dladdr/Makefile
unit-tests/test-cases/dladdr/main.c
unit-tests/test-cases/dlopen-error/Makefile
unit-tests/test-cases/dlopen-executable/Makefile
unit-tests/test-cases/dlopen-from-anonymous-code/main.c
unit-tests/test-cases/dlopen-leak/bar.c
unit-tests/test-cases/dlopen-non-canonical-path/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen-non-canonical-path/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-notify-bind/Makefile
unit-tests/test-cases/dlopen-notify-bind/main.c
unit-tests/test-cases/dlopen-search-leak/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen-search-leak/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-search-leak/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen_preflight-shared-cache/Makefile [deleted file]
unit-tests/test-cases/dlopen_preflight-shared-cache/bar.c [deleted file]
unit-tests/test-cases/dlopen_preflight-shared-cache/main.c [deleted file]
unit-tests/test-cases/dtrace-static-probes/Makefile
unit-tests/test-cases/dyld-func-lookup/Makefile
unit-tests/test-cases/dyld-func-lookup/foo.c
unit-tests/test-cases/dyld-func-lookup/main.c
unit-tests/test-cases/dyld-launched-prebound/main.c
unit-tests/test-cases/dyld-slide/Makefile
unit-tests/test-cases/dyld-slide/main.c
unit-tests/test-cases/fallback-with-suid/Makefile
unit-tests/test-cases/flat-prebound/Makefile
unit-tests/test-cases/framework-fallback/main.c
unit-tests/test-cases/image-count/Makefile [new file with mode: 0644]
unit-tests/test-cases/image-count/foo.c [new file with mode: 0644]
unit-tests/test-cases/image-count/main.c [new file with mode: 0644]
unit-tests/test-cases/image-state-deny-OFI/main.c
unit-tests/test-cases/image-suffix/main.c
unit-tests/test-cases/initializer-bounds-check/Makefile [new file with mode: 0644]
unit-tests/test-cases/initializer-bounds-check/bar.c [new file with mode: 0644]
unit-tests/test-cases/initializer-bounds-check/foo1.c [new file with mode: 0644]
unit-tests/test-cases/initializer-bounds-check/foo2.c [new file with mode: 0644]
unit-tests/test-cases/initializer-bounds-check/main.c [new file with mode: 0644]
unit-tests/test-cases/insert-libraries-with-suid/Makefile
unit-tests/test-cases/loader_path/main.c
unit-tests/test-cases/partial-library-load/main.c
unit-tests/test-cases/pie-DYLD_NO_PIE/Makefile [deleted file]
unit-tests/test-cases/pie-DYLD_NO_PIE/main.c [deleted file]
unit-tests/test-cases/pie-basic/Makefile
unit-tests/test-cases/pie-big/Makefile
unit-tests/test-cases/pie-big/main.c
unit-tests/test-cases/pie-custom-stack/Makefile
unit-tests/test-cases/pie-text-reloc/Makefile
unit-tests/test-cases/prebased-performance/Makefile
unit-tests/test-cases/re-export-dylib/Makefile
unit-tests/test-cases/re-export-framework/Makefile
unit-tests/test-cases/re-export-sub-framework/Makefile
unit-tests/test-cases/re-export-symbol/Makefile [new file with mode: 0644]
unit-tests/test-cases/re-export-symbol/bar.c [new file with mode: 0644]
unit-tests/test-cases/re-export-symbol/foo.c [new file with mode: 0644]
unit-tests/test-cases/re-export-symbol/foo.exp [new file with mode: 0644]
unit-tests/test-cases/re-export-symbol/foo2.exp [new file with mode: 0644]
unit-tests/test-cases/re-export-symbol/main1.c [new file with mode: 0644]
unit-tests/test-cases/re-export-symbol/main2.c [new file with mode: 0644]
unit-tests/test-cases/read-only-import-shared-cache-override/Makefile [deleted file]
unit-tests/test-cases/read-only-import-shared-cache-override/foo.c [deleted file]
unit-tests/test-cases/read-only-import-shared-cache-override/main.c [deleted file]
unit-tests/test-cases/read-only-stubs/foo.c
unit-tests/test-cases/read-only-stubs/main.c
unit-tests/test-cases/restrict-environ/Makefile
unit-tests/test-cases/restrict-executable_path/Makefile
unit-tests/test-cases/rpath-dlopen-rm-executable/Makefile [new file with mode: 0644]
unit-tests/test-cases/rpath-dlopen-rm-executable/foo.c [new file with mode: 0644]
unit-tests/test-cases/rpath-dlopen-rm-executable/main.c [new file with mode: 0644]
unit-tests/test-cases/rpath-indirect-suid/Makefile
unit-tests/test-cases/rpath-install-name/Makefile [new file with mode: 0644]
unit-tests/test-cases/rpath-install-name/bar.c [new file with mode: 0644]
unit-tests/test-cases/rpath-install-name/main.c [new file with mode: 0644]
unit-tests/test-cases/rpath-install-name/stuff.c [new file with mode: 0644]
unit-tests/test-cases/shared-cache-symlink/main.c
unit-tests/test-cases/shared-region-overlap/Makefile [new file with mode: 0644]
unit-tests/test-cases/shared-region-overlap/main.c [new file with mode: 0644]
unit-tests/test-cases/suid-environ/Makefile
unit-tests/test-cases/suid-executable_path/Makefile
unit-tests/test-cases/symbol-resolver-basic/Makefile [new file with mode: 0644]
unit-tests/test-cases/symbol-resolver-basic/foo.c [new file with mode: 0644]
unit-tests/test-cases/symbol-resolver-basic/foo2.c [new file with mode: 0644]
unit-tests/test-cases/symbol-resolver-basic/main.c [new file with mode: 0644]
unit-tests/test-cases/symbol-resolver-pointer/Makefile [new file with mode: 0644]
unit-tests/test-cases/symbol-resolver-pointer/foo.c [new file with mode: 0644]
unit-tests/test-cases/symbol-resolver-pointer/main.c [new file with mode: 0644]
unit-tests/test-cases/text-relocs-perms/Makefile [new file with mode: 0644]
unit-tests/test-cases/text-relocs-perms/foo.c [new file with mode: 0644]
unit-tests/test-cases/text-relocs-perms/main.c [new file with mode: 0644]
unit-tests/test-cases/text-relocs/Makefile
unit-tests/test-cases/text-relocs/bar.c
unit-tests/test-cases/text-relocs/bind.c [new file with mode: 0644]
unit-tests/test-cases/text-relocs/space.s [new file with mode: 0644]
unit-tests/test-cases/threaded-flat-lookup/Makefile [new file with mode: 0644]
unit-tests/test-cases/threaded-flat-lookup/client.c [new file with mode: 0644]
unit-tests/test-cases/threaded-flat-lookup/foo.c [new file with mode: 0644]
unit-tests/test-cases/threaded-flat-lookup/main.c [new file with mode: 0644]
unit-tests/test-cases/tlv-basic/Makefile [new file with mode: 0644]
unit-tests/test-cases/tlv-basic/main.c [new file with mode: 0644]
unit-tests/test-cases/tlv-dylib/Makefile [new file with mode: 0644]
unit-tests/test-cases/tlv-dylib/foo.c [new file with mode: 0644]
unit-tests/test-cases/tlv-dylib/main.c [new file with mode: 0644]
unit-tests/test-cases/tlv-initializer/Makefile [new file with mode: 0644]
unit-tests/test-cases/tlv-initializer/get.s [new file with mode: 0644]
unit-tests/test-cases/tlv-initializer/main.c [new file with mode: 0644]
unit-tests/test-cases/tlv-terminators/Makefile [new file with mode: 0644]
unit-tests/test-cases/tlv-terminators/init.s [new file with mode: 0644]
unit-tests/test-cases/tlv-terminators/main.c [new file with mode: 0644]
unit-tests/test-cases/trie-symbol-overrun/main.c
unit-tests/test-cases/unloadable-library-residue/main.c
unit-tests/test-cases/upward-dylib/Makefile [new file with mode: 0644]
unit-tests/test-cases/upward-dylib/down.c [new file with mode: 0644]
unit-tests/test-cases/upward-dylib/down.h [new file with mode: 0644]
unit-tests/test-cases/upward-dylib/main.c [new file with mode: 0644]
unit-tests/test-cases/upward-dylib/up.c [new file with mode: 0644]
unit-tests/test-cases/upward-dylib/up.h [new file with mode: 0644]
unit-tests/test-cases/weak-coalesce-stubs/Makefile [new file with mode: 0644]
unit-tests/test-cases/weak-coalesce-stubs/bar.c [new file with mode: 0644]
unit-tests/test-cases/weak-coalesce-stubs/foo.c [new file with mode: 0644]
unit-tests/test-cases/weak-coalesce-stubs/main.c [new file with mode: 0644]

diff --git a/bin/set-alt-dyld b/bin/set-alt-dyld
new file mode 100755 (executable)
index 0000000..032bcf9
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/perl -w
+
+use strict;
+undef $/;
+
+if(@ARGV == 0)
+{
+    print "Usage: $0 <macho-executable> [<macho-executable> ...]\n";
+    exit 1;
+}
+
+my $arg;
+foreach $arg (@ARGV)
+{
+    open IN, "<$arg" or die $!;
+    my $in = <IN>;
+    close IN or die $!;
+
+    if($in =~ s{/usr/lib/dyld}{/usr/lib/dyle})
+    {
+       open OUT, ">$arg" or die $!;
+       print OUT $in;
+       close OUT or die $!;
+    }
+    else
+    {
+       print STDERR "ERROR: $arg\n";
+       exit 1;
+    }
+}
index 8570d9aba762930e6b0a8835640eae97a23b1a19..b89239d43c78ea8f15e457937bc659da2a43c68c 100644 (file)
@@ -1,4 +1,4 @@
-.TH DYLD 1 "November 25, 2008" "Apple Inc."
+.TH DYLD 1 "December 14, 2009" "Apple Inc."
 .SH NAME
 dyld \- the dynamic link editor
 .SH SYNOPSIS
 .SH NAME
 dyld \- the dynamic link editor
 .SH SYNOPSIS
@@ -6,10 +6,14 @@ DYLD_FRAMEWORK_PATH
 .br
 DYLD_FALLBACK_FRAMEWORK_PATH
 .br
 .br
 DYLD_FALLBACK_FRAMEWORK_PATH
 .br
+DYLD_VERSIONED_FRAMEWORK_PATH
+.br
 DYLD_LIBRARY_PATH
 .br
 DYLD_FALLBACK_LIBRARY_PATH
 .br
 DYLD_LIBRARY_PATH
 .br
 DYLD_FALLBACK_LIBRARY_PATH
 .br
+DYLD_VERSIONED_LIBRARY_PATH
+.br
 DYLD_ROOT_PATH
 .br
 DYLD_SHARED_REGION
 DYLD_ROOT_PATH
 .br
 DYLD_SHARED_REGION
@@ -48,7 +52,7 @@ DYLD_PRINT_STATISTICS
 .br
 DYLD_PRINT_DOFS
 .br
 .br
 DYLD_PRINT_DOFS
 .br
-DYLD_NO_PIE
+DYLD_PRINT_RPATHS
 .br
 DYLD_SHARED_CACHE_DIR
 .br
 .br
 DYLD_SHARED_CACHE_DIR
 .br
@@ -93,6 +97,17 @@ path.
 By default, it is set to
 /Library/Frameworks:/Network/Library/Frameworks:/System/Library/Frameworks
 .TP
 By default, it is set to
 /Library/Frameworks:/Network/Library/Frameworks:/System/Library/Frameworks
 .TP
+.B DYLD_VERSIONED_FRAMEWORK_PATH
+This is a colon separated list of directories that contain potential override frameworks. 
+The dynamic linker searches these directories for frameworks.  For
+each framework found dyld looks at its LC_ID_DYLIB and gets the current_version 
+and install name.  Dyld then looks for the framework at the install name path.
+Whichever has the larger current_version value will be used in the process whenever
+a framework with that install name is required.  This is similar to DYLD_FRAMEWORK_PATH
+except instead of always overriding, it only overrides is the supplied framework is newer.
+Note: dyld does not check the framework's Info.plist to find its version.  Dyld only
+checks the -currrent_version number supplied when the framework was created.
+.TP
 .B DYLD_LIBRARY_PATH
 This is a colon separated list of directories that contain libraries. The
 dynamic linker searches these directories before it searches the default
 .B DYLD_LIBRARY_PATH
 This is a colon separated list of directories that contain libraries. The
 dynamic linker searches these directories before it searches the default
@@ -122,6 +137,15 @@ path.
 By default, it is set
 to $(HOME)/lib:/usr/local/lib:/lib:/usr/lib.
 .TP
 By default, it is set
 to $(HOME)/lib:/usr/local/lib:/lib:/usr/lib.
 .TP
+.B DYLD_VERSIONED_LIBRARY_PATH
+This is a colon separated list of directories that contain potential override libraries. 
+The dynamic linker searches these directories for dynamic libraries.  For
+each library found dyld looks at its LC_ID_DYLIB and gets the current_version 
+and install name.  Dyld then looks for the library at the install name path.
+Whichever has the larger current_version value will be used in the process whenever
+a dylib with that install name is required.  This is similar to DYLD_LIBRARY_PATH
+except instead of always overriding, it only overrides is the supplied library is newer.
+.TP
 .B DYLD_ROOT_PATH
 This is a colon separated list of directories.  The dynamic linker will prepend each of
 this directory paths to every image access until a file is found.    
 .B DYLD_ROOT_PATH
 This is a colon separated list of directories.  The dynamic linker will prepend each of
 this directory paths to every image access until a file is found.    
@@ -216,10 +240,9 @@ Causes dyld to print a line each time a symbolic name is bound.
 .B DYLD_PRINT_DOFS 
 Causes dyld to print out information about dtrace static probes registered with the kernel. 
 .TP
 .B DYLD_PRINT_DOFS 
 Causes dyld to print out information about dtrace static probes registered with the kernel. 
 .TP
-.B DYLD_NO_PIE
-Causes dyld to not randomize the load addresses of images in a process where the main 
-executable was built position independent.  This can be helpful when trying to reproduce
-and debug a problem in a PIE.
+.B DYLD_PRINT_RPATHS
+Cause dyld  to print a line each time it expands an @rpath variable and whether
+that expansion was successful or not.
 .TP
 .B DYLD_SHARED_CACHE_DIR
 This is a directory containing dyld shared cache files.  This variable can be used in
 .TP
 .B DYLD_SHARED_CACHE_DIR
 This is a directory containing dyld shared cache files.  This variable can be used in
@@ -230,6 +253,7 @@ to run a process with an alternate shared cache.
 Causes dyld to not check that the inode and mod-time of files in the shared cache match
 the requested dylib on disk. Thus a program can be made to run with the dylib in the
 shared cache even though the real dylib has been updated on disk.
 Causes dyld to not check that the inode and mod-time of files in the shared cache match
 the requested dylib on disk. Thus a program can be made to run with the dylib in the
 shared cache even though the real dylib has been updated on disk.
+.TP
 .SH DYNAMIC LIBRARY LOADING
 Unlike many other operating systems, Darwin does not locate dependent dynamic libraries
 via their leaf file name.  Instead the full path to each dylib is used (e.g. /usr/lib/libSystem.B.dylib).
 .SH DYNAMIC LIBRARY LOADING
 Unlike many other operating systems, Darwin does not locate dependent dynamic libraries
 via their leaf file name.  Instead the full path to each dylib is used (e.g. /usr/lib/libSystem.B.dylib).
@@ -240,17 +264,25 @@ substitutes a dynamically generated path for the @xxx/ prefix.
 .TP
 .B @executable_path/
 This variable is replaced with the path to the directory containing the main executable for 
 .TP
 .B @executable_path/
 This variable is replaced with the path to the directory containing the main executable for 
-the process.  This is useful for .app directories where the main executable is in a well
-known location inside the .app directory.  A typical load path for an embedded framework would 
-look like @executable_path/../Frameworks/Foo.framework/Versions/A/Foo.
+the process.  This is useful for loading dylibs/frameworks embedded in a .app directory. 
+If the main executable file is at /some/path/My.app/Contents/MacOS/My and a framework dylib 
+file is at /some/path/My.app/Contents/Frameworks/Foo.framework/Versions/A/Foo, then 
+the framework load path could be encoded as 
+@executable_path/../Frameworks/Foo.framework/Versions/A/Foo and the .app directory could be
+moved around in the file system and dyld will still be able to load the embedded framework.
 .TP
 .B @loader_path/
 This variable is replaced with the path to the directory containing the mach-o binary which
 .TP
 .B @loader_path/
 This variable is replaced with the path to the directory containing the mach-o binary which
-contains the load path. This is useful for a plug-in that has an embedded framework.  @executable_path/
-is not helpful because you may not know where the plugin-in will be installed relative to the
-main executable, or there may be multiple applications that load the plug-in.  
-A typical load path for an embedded framework for reference a sibling framework would 
-look like @loader_path/../../../Frameworks/Foo.framework/Versions/A/Foo.
+contains the load command using @loader_path. Thus, in every binary, @loader_path resolves to
+a different path, whereas @executable_path always resolves to the same path. @loader_path is
+useful as the load path for a framework/dylib embedded in a plug-in, if the final file 
+system location of the plugin-in unknown (so absolute paths cannot be used) or if the plug-in 
+is used by multiple applications (so @executable_path cannot be used). If the plug-in mach-o
+file is at /some/path/Myfilter.plugin/Contents/MacOS/Myfilter and a framework dylib 
+file is at /some/path/Myfilter.plugin/Contents/Frameworks/Foo.framework/Versions/A/Foo, then 
+the framework load path could be encoded as 
+@loader_path/../Frameworks/Foo.framework/Versions/A/Foo and the Myfilter.plugin directory could 
+be moved around in the file system and dyld will still be able to load the embedded framework.
 .TP
 .B @rpath/
 Dyld maintains a current stack of paths called the run path list.  When @rpath is encountered
 .TP
 .B @rpath/
 Dyld maintains a current stack of paths called the run path list.  When @rpath is encountered
index f5baa1b6da825e625b1f03320abe3dee591e17d4..9d524ad0d0499fe2a1ae58b233a1b12da8b017bd 100644 (file)
@@ -15,6 +15,8 @@
 .Op Fl universal_boot 
 .Op Fl verify
 .Op Fl dylib_list Ar file
 .Op Fl universal_boot 
 .Op Fl verify
 .Op Fl dylib_list Ar file
+.Op Fl iPhone
+.Op Fl cache_dir Ar dir
 .Sh DESCRIPTION
 .Nm update_dyld_shared_cache
 ensures that dyld's shared cache is up-to-date.  This tool is normally
 .Sh DESCRIPTION
 .Nm update_dyld_shared_cache
 ensures that dyld's shared cache is up-to-date.  This tool is normally
@@ -93,6 +95,11 @@ a list of the dylibs to use when building the shared cache file.
 Will regenerate a shared cache in-memory that matches the randomization of the existing shared 
 cache file.  Then instead of writing the cache file, it compares the in-memory cache file to
 the on disk version and reports any differences.  
 Will regenerate a shared cache in-memory that matches the randomization of the existing shared 
 cache file.  Then instead of writing the cache file, it compares the in-memory cache file to
 the on disk version and reports any differences.  
+.It Fl iPhone
+indicates that cache is not for the current Mac OS X, but for rather for an iPhone
+.It Fl cache_dir Ar directory
+This option specifies the directory in which to create the cache file(s).  If not specified,
+the cache file(s) are created in the standard location (e.g. var/db/dyld/) of the root partition.
 .El
 .Sh FILES
 .Tp
 .El
 .Sh FILES
 .Tp
index 285a70c88c3306c2abac50a4c12c6322135dcda8..cb9f6e4baf36a5a8e5e294ce2295b2a369202ad0 100644 (file)
@@ -1,4 +1,4 @@
-.Dd February 12, 2009
+.Dd November 29, 2010
 .Dt dyld 3
 .Sh NAME
 .Nm _dyld_image_count,
 .Dt dyld 3
 .Sh NAME
 .Nm _dyld_image_count,
@@ -107,7 +107,10 @@ copies the path of the main executable into the buffer
 .Fa buf .
 The 
 .Fa bufsize
 .Fa buf .
 The 
 .Fa bufsize
-parameter should initially be the size of the buffer.  This function returns 0 if the path was successfully copied.
+parameter should initially be the size of the buffer.  This function returns 0 if the path was successfully copied,
+and  *
+.Fa bufsize
+is left unchanged. 
 It returns -1 if the buffer is not large enough, and *
 .Fa bufsize
 is set to the size required. 
 It returns -1 if the buffer is not large enough, and *
 .Fa bufsize
 is set to the size required. 
index 75cd83f4e06314c98d004fa0b0d21fe45c9ff295..21650208c07feb210f1dadfbf2232bdaeb094063 100644 (file)
@@ -3,10 +3,27 @@
        archiveVersion = 1;
        classes = {
        };
        archiveVersion = 1;
        classes = {
        };
-       objectVersion = 46;
+       objectVersion = 45;
        objects = {
 
 /* Begin PBXAggregateTarget section */
        objects = {
 
 /* Begin PBXAggregateTarget section */
+               F908134211D3ED0B00626CC1 /* libdyld */ = {
+                       isa = PBXAggregateTarget;
+                       buildConfigurationList = F908135211D3ED9000626CC1 /* Build configuration list for PBXAggregateTarget "libdyld" */;
+                       buildPhases = (
+                               F908135111D3ED9000626CC1 /* usr|include|mach-o */,
+                               F908137011D3FB5000626CC1 /* usr|include */,
+                               F908137111D3FB5000626CC1 /* usr|local|include|mach-o */,
+                               F908137211D3FB5000626CC1 /* usr|share|man|man1 */,
+                               F908137311D3FB5000626CC1 /* usr|share|man|man3 */,
+                       );
+                       dependencies = (
+                               F9B4D78012AD9736000605A6 /* PBXTargetDependency */,
+                               F908134811D3ED1A00626CC1 /* PBXTargetDependency */,
+                       );
+                       name = libdyld;
+                       productName = libdyld;
+               };
                F9ED4C920630A73900DF4E74 /* all */ = {
                        isa = PBXAggregateTarget;
                        buildConfigurationList = F9D8C7E5087B087300E93EFB /* Build configuration list for PBXAggregateTarget "all" */;
                F9ED4C920630A73900DF4E74 /* all */ = {
                        isa = PBXAggregateTarget;
                        buildConfigurationList = F9D8C7E5087B087300E93EFB /* Build configuration list for PBXAggregateTarget "all" */;
 /* End PBXAggregateTarget section */
 
 /* Begin PBXBuildFile section */
 /* End PBXAggregateTarget section */
 
 /* Begin PBXBuildFile section */
-               EF79A010070D293E00F78484 /* dyld.1 in usr|share|man|man1 */ = {isa = PBXBuildFile; fileRef = EF799FE9070D27BB00F78484 /* dyld.1 */; };
-               EF79A011070D295200F78484 /* dladdr.3 in usr|share|man|man3 */ = {isa = PBXBuildFile; fileRef = EF799FEB070D27BB00F78484 /* dladdr.3 */; };
-               EF79A012070D295200F78484 /* dlclose.3 in usr|share|man|man3 */ = {isa = PBXBuildFile; fileRef = EF799FEC070D27BB00F78484 /* dlclose.3 */; };
-               EF79A013070D295200F78484 /* dlerror.3 in usr|share|man|man3 */ = {isa = PBXBuildFile; fileRef = EF799FED070D27BB00F78484 /* dlerror.3 */; };
-               EF79A014070D295200F78484 /* dlopen.3 in usr|share|man|man3 */ = {isa = PBXBuildFile; fileRef = EF799FEE070D27BB00F78484 /* dlopen.3 */; };
-               EF79A015070D295200F78484 /* dlsym.3 in usr|share|man|man3 */ = {isa = PBXBuildFile; fileRef = EF799FEF070D27BB00F78484 /* dlsym.3 */; };
-               EF79A016070D295200F78484 /* dyld.3 in usr|share|man|man3 */ = {isa = PBXBuildFile; fileRef = EF799FF0070D27BB00F78484 /* dyld.3 */; };
                F906E2240639E96400B13DB2 /* dyld_debug.c in Sources */ = {isa = PBXBuildFile; fileRef = F906E2230639E96400B13DB2 /* dyld_debug.c */; };
                F906E2240639E96400B13DB2 /* dyld_debug.c in Sources */ = {isa = PBXBuildFile; fileRef = F906E2230639E96400B13DB2 /* dyld_debug.c */; };
+               F908134C11D3ED6200626CC1 /* dyld.h in usr|include|mach-o */ = {isa = PBXBuildFile; fileRef = F9ED4CEA0630A80600DF4E74 /* dyld.h */; };
+               F908134D11D3ED6200626CC1 /* dyld_images.h in usr|include|mach-o */ = {isa = PBXBuildFile; fileRef = F98D274C0AA79D7400416316 /* dyld_images.h */; };
+               F908135911D3FA8700626CC1 /* dlfcn.h in usr|include */ = {isa = PBXBuildFile; fileRef = F99EE6AE06B48D4200BF1992 /* dlfcn.h */; };
+               F908135D11D3FACD00626CC1 /* dyld-interposing.h in usr|local|include|mach-o */ = {isa = PBXBuildFile; fileRef = F918691408B16D2500E0F9DB /* dyld-interposing.h */; };
+               F908135E11D3FACD00626CC1 /* dyld_cache_format.h in usr|local|include|mach-o */ = {isa = PBXBuildFile; fileRef = F93937400A94FC4700070A07 /* dyld_cache_format.h */; };
+               F908135F11D3FACD00626CC1 /* dyld_gdb.h in usr|local|include|mach-o */ = {isa = PBXBuildFile; fileRef = F9ED4CE80630A80600DF4E74 /* dyld_gdb.h */; };
+               F908136011D3FACD00626CC1 /* dyld_priv.h in usr|local|include|mach-o */ = {isa = PBXBuildFile; fileRef = F9ED4CE90630A80600DF4E74 /* dyld_priv.h */; };
+               F908136411D3FB0300626CC1 /* dyld.1 in usr|share|man|man1 */ = {isa = PBXBuildFile; fileRef = EF799FE9070D27BB00F78484 /* dyld.1 */; };
+               F908136811D3FB3A00626CC1 /* dladdr.3 in usr|share|man|man3 */ = {isa = PBXBuildFile; fileRef = EF799FEB070D27BB00F78484 /* dladdr.3 */; };
+               F908136911D3FB3A00626CC1 /* dlclose.3 in usr|share|man|man3 */ = {isa = PBXBuildFile; fileRef = EF799FEC070D27BB00F78484 /* dlclose.3 */; };
+               F908136A11D3FB3A00626CC1 /* dlerror.3 in usr|share|man|man3 */ = {isa = PBXBuildFile; fileRef = EF799FED070D27BB00F78484 /* dlerror.3 */; };
+               F908136B11D3FB3A00626CC1 /* dlopen.3 in usr|share|man|man3 */ = {isa = PBXBuildFile; fileRef = EF799FEE070D27BB00F78484 /* dlopen.3 */; };
+               F908136C11D3FB3A00626CC1 /* dlsym.3 in usr|share|man|man3 */ = {isa = PBXBuildFile; fileRef = EF799FEF070D27BB00F78484 /* dlsym.3 */; };
+               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 */; };
                F913FADA0630A8AE00B7AE9D /* dyldAPIsInLibSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F913FAD90630A8AE00B7AE9D /* dyldAPIsInLibSystem.cpp */; };
-               F918691608B16D3500E0F9DB /* dyld-interposing.h in usr|local|include|mach-o */ = {isa = PBXBuildFile; fileRef = F918691408B16D2500E0F9DB /* dyld-interposing.h */; };
                F93937470A94FC4700070A07 /* update_dyld_shared_cache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F93937460A94FC4700070A07 /* update_dyld_shared_cache.cpp */; };
                F93937470A94FC4700070A07 /* update_dyld_shared_cache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F93937460A94FC4700070A07 /* update_dyld_shared_cache.cpp */; };
-               F93AA9A30630AE1E00301D9F /* dyld_gdb.h in usr|local|include|mach-o */ = {isa = PBXBuildFile; fileRef = F9ED4CE80630A80600DF4E74 /* dyld_gdb.h */; };
-               F93AA9A40630AE1E00301D9F /* dyld_priv.h in usr|local|include|mach-o */ = {isa = PBXBuildFile; fileRef = F9ED4CE90630A80600DF4E74 /* dyld_priv.h */; };
-               F93AA9A50630AE1E00301D9F /* dyld.h in usr|include|mach-o */ = {isa = PBXBuildFile; fileRef = F9ED4CEA0630A80600DF4E74 /* dyld.h */; };
                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"; }; };
                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"; }; };
-               F9574CB306C95C1B00142BFA /* dlfcn.h in usr|include */ = {isa = PBXBuildFile; fileRef = F99EE6AE06B48D4200BF1992 /* dlfcn.h */; };
                F98C78F00F7C02E8006257D2 /* dsc_iterator.h in usr|local|include|mach-o */ = {isa = PBXBuildFile; fileRef = F9F2A56F0F7AEEE300B7C9EB /* dsc_iterator.h */; };
                F98C78F00F7C02E8006257D2 /* dsc_iterator.h in usr|local|include|mach-o */ = {isa = PBXBuildFile; fileRef = F9F2A56F0F7AEEE300B7C9EB /* dsc_iterator.h */; };
-               F98D274D0AA79D7400416316 /* dyld_images.h in usr|include|mach-o */ = {isa = PBXBuildFile; fileRef = F98D274C0AA79D7400416316 /* dyld_images.h */; };
-               F99EFC0E0EAD60E8001032B8 /* dyld_stub_binder.s in Sources */ = {isa = PBXBuildFile; fileRef = F99EFC0D0EAD60E8001032B8 /* dyld_stub_binder.s */; };
+               F99B8E630FEC11B400701838 /* dyld_shared_cache_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F99B8E620FEC11B400701838 /* dyld_shared_cache_util.cpp */; };
+               F99B8EA30FEC1C4200701838 /* dsc_iterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9F2A56E0F7AEEE300B7C9EB /* dsc_iterator.cpp */; };
                F9A221E70F3A6D7C00D15F73 /* dyldLibSystemGlue.c in Sources */ = {isa = PBXBuildFile; fileRef = F9A221E60F3A6D7C00D15F73 /* dyldLibSystemGlue.c */; };
                F9A221E70F3A6D7C00D15F73 /* dyldLibSystemGlue.c in Sources */ = {isa = PBXBuildFile; fileRef = F9A221E60F3A6D7C00D15F73 /* dyldLibSystemGlue.c */; };
-               F9AC7E940B7BB67700FEB38B /* version.c in Sources */ = {isa = PBXBuildFile; fileRef = F9AC7E930B7BB67700FEB38B /* version.c */; };
+               F9A6D6E4116F9DF20051CC16 /* threadLocalVariables.c in Sources */ = {isa = PBXBuildFile; fileRef = F9A6D6E2116F9DF20051CC16 /* threadLocalVariables.c */; };
+               F9A6D70C116FBBD10051CC16 /* threadLocalHelpers.s in Sources */ = {isa = PBXBuildFile; fileRef = F9A6D70B116FBBD10051CC16 /* threadLocalHelpers.s */; };
+               F9B0912911F11D3400096D49 /* dsc_slider.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9B0912811F11D3400096D49 /* dsc_slider.cpp */; };
+               F9B0913911F11DD300096D49 /* dsc_slider.h in usr|local|include|mach-o */ = {isa = PBXBuildFile; fileRef = F9B0913811F11DAB00096D49 /* dsc_slider.h */; };
                F9BA514B0ECE4F4200D1D62E /* dyld_stub_binder.s in Sources */ = {isa = PBXBuildFile; fileRef = F99EFC0D0EAD60E8001032B8 /* dyld_stub_binder.s */; };
                F9BA514B0ECE4F4200D1D62E /* dyld_stub_binder.s in Sources */ = {isa = PBXBuildFile; fileRef = F99EFC0D0EAD60E8001032B8 /* dyld_stub_binder.s */; };
+               F9CE307A1208F1B50098B590 /* dsc_extractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9CE30781208F1B50098B590 /* dsc_extractor.cpp */; };
+               F9CE307B1208F1C60098B590 /* dsc_extractor.h in usr|local|include|mach-o */ = {isa = PBXBuildFile; fileRef = F9CE30791208F1B50098B590 /* dsc_extractor.h */; };
                F9D238DB0A9E2FD0002B55C7 /* update_dyld_shared_cache.1 in usr|share|man|man1 */ = {isa = PBXBuildFile; fileRef = F9D238D90A9E19A0002B55C7 /* update_dyld_shared_cache.1 */; };
                F9D238DB0A9E2FD0002B55C7 /* update_dyld_shared_cache.1 in usr|share|man|man1 */ = {isa = PBXBuildFile; fileRef = F9D238D90A9E19A0002B55C7 /* update_dyld_shared_cache.1 */; };
-               F9E572020A66EF4A007D9BE9 /* dlopen_preflight.3 in usr|share|man|man3 */ = {isa = PBXBuildFile; fileRef = F9E572000A66EF41007D9BE9 /* dlopen_preflight.3 */; };
                F9ED4CD60630A7F100DF4E74 /* dyld_gdb.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9ED4CC60630A7F100DF4E74 /* dyld_gdb.cpp */; };
                F9ED4CD70630A7F100DF4E74 /* dyld.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9ED4CC70630A7F100DF4E74 /* dyld.cpp */; };
                F9ED4CD90630A7F100DF4E74 /* dyldAPIs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9ED4CC90630A7F100DF4E74 /* dyldAPIs.cpp */; };
                F9ED4CD60630A7F100DF4E74 /* dyld_gdb.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9ED4CC60630A7F100DF4E74 /* dyld_gdb.cpp */; };
                F9ED4CD70630A7F100DF4E74 /* dyld.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9ED4CC70630A7F100DF4E74 /* dyld.cpp */; };
                F9ED4CD90630A7F100DF4E74 /* dyldAPIs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9ED4CC90630A7F100DF4E74 /* dyldAPIs.cpp */; };
 /* End PBXBuildRule section */
 
 /* Begin PBXContainerItemProxy section */
 /* End PBXBuildRule section */
 
 /* Begin PBXContainerItemProxy section */
+               F908134711D3ED1A00626CC1 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = F9ED4C8B0630A72300DF4E74 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = F9ED4C9E0630A76B00DF4E74;
+                       remoteInfo = libdyld.dylib;
+               };
                F93937370A94FB6A00070A07 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = F9ED4C8B0630A72300DF4E74 /* Project object */;
                F93937370A94FB6A00070A07 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = F9ED4C8B0630A72300DF4E74 /* Project object */;
                        remoteGlobalIDString = F93937310A94FAF700070A07;
                        remoteInfo = update_dyld_shared_cache;
                };
                        remoteGlobalIDString = F93937310A94FAF700070A07;
                        remoteInfo = update_dyld_shared_cache;
                };
-               F98C78D90F7C017F006257D2 /* PBXContainerItemProxy */ = {
+               F99B8E9F0FEC195800701838 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = F9ED4C8B0630A72300DF4E74 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = F99B8E550FEC10F600701838;
+                       remoteInfo = dyld_shared_cache_util;
+               };
+               F99B8EB10FEC220C00701838 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = F9ED4C8B0630A72300DF4E74 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = F99B8E550FEC10F600701838;
+                       remoteInfo = dyld_shared_cache_util;
+               };
+               F9B4D77F12AD9736000605A6 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = F9ED4C8B0630A72300DF4E74 /* Project object */;
                        proxyType = 1;
                        remoteGlobalIDString = F9F2A5580F7AEE9800B7C9EB;
                        isa = PBXContainerItemProxy;
                        containerPortal = F9ED4C8B0630A72300DF4E74 /* Project object */;
                        proxyType = 1;
                        remoteGlobalIDString = F9F2A5580F7AEE9800B7C9EB;
-                       remoteInfo = dsc;
+                       remoteInfo = libdsc;
+               };
+               F9CE330A120F40EA0098B590 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = F9ED4C8B0630A72300DF4E74 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = F9F2A5580F7AEE9800B7C9EB;
+                       remoteInfo = libdsc;
                };
                F9ED4CA60630A78A00DF4E74 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                };
                F9ED4CA60630A78A00DF4E74 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXCopyFilesBuildPhase section */
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXCopyFilesBuildPhase section */
-               F90CF2950E71D1FB000BF0F1 /* usr|local|include */ = {
+               F908135111D3ED9000626CC1 /* usr|include|mach-o */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = /usr/local/include;
+                       dstPath = "/usr/include/mach-o";
                        dstSubfolderSpec = 0;
                        files = (
                        dstSubfolderSpec = 0;
                        files = (
+                               F908134C11D3ED6200626CC1 /* dyld.h in usr|include|mach-o */,
+                               F908134D11D3ED6200626CC1 /* dyld_images.h in usr|include|mach-o */,
                        );
                        );
-                       name = "usr|local|include";
+                       name = "usr|include|mach-o";
                        runOnlyForDeploymentPostprocessing = 1;
                };
                        runOnlyForDeploymentPostprocessing = 1;
                };
-               F93AA9B30630AE8200301D9F /* usr|include|mach-o */ = {
+               F908137011D3FB5000626CC1 /* usr|include */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = "/usr/include/mach-o";
+                       dstPath = /usr/include;
                        dstSubfolderSpec = 0;
                        files = (
                        dstSubfolderSpec = 0;
                        files = (
-                               F93AA9A50630AE1E00301D9F /* dyld.h in usr|include|mach-o */,
-                               F98D274D0AA79D7400416316 /* dyld_images.h in usr|include|mach-o */,
+                               F908135911D3FA8700626CC1 /* dlfcn.h in usr|include */,
                        );
                        );
-                       name = "usr|include|mach-o";
+                       name = "usr|include";
                        runOnlyForDeploymentPostprocessing = 1;
                };
                        runOnlyForDeploymentPostprocessing = 1;
                };
-               F93AA9B60630AEB100301D9F /* usr|local|include|mach-o */ = {
+               F908137111D3FB5000626CC1 /* usr|local|include|mach-o */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                        dstPath = "/usr/local/include/mach-o";
                        dstSubfolderSpec = 0;
                        files = (
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                        dstPath = "/usr/local/include/mach-o";
                        dstSubfolderSpec = 0;
                        files = (
-                               F918691608B16D3500E0F9DB /* dyld-interposing.h in usr|local|include|mach-o */,
-                               F93AA9A30630AE1E00301D9F /* dyld_gdb.h in usr|local|include|mach-o */,
-                               F93AA9A40630AE1E00301D9F /* dyld_priv.h in usr|local|include|mach-o */,
+                               F908135D11D3FACD00626CC1 /* dyld-interposing.h in usr|local|include|mach-o */,
+                               F908135E11D3FACD00626CC1 /* dyld_cache_format.h in usr|local|include|mach-o */,
+                               F908135F11D3FACD00626CC1 /* dyld_gdb.h in usr|local|include|mach-o */,
+                               F908136011D3FACD00626CC1 /* dyld_priv.h in usr|local|include|mach-o */,
                        );
                        name = "usr|local|include|mach-o";
                        runOnlyForDeploymentPostprocessing = 1;
                };
                        );
                        name = "usr|local|include|mach-o";
                        runOnlyForDeploymentPostprocessing = 1;
                };
-               F93AA9C20630AF0700301D9F /* usr|share|man|man1 */ = {
+               F908137211D3FB5000626CC1 /* usr|share|man|man1 */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                        dstPath = /usr/share/man/man1;
                        dstSubfolderSpec = 0;
                        files = (
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                        dstPath = /usr/share/man/man1;
                        dstSubfolderSpec = 0;
                        files = (
-                               EF79A010070D293E00F78484 /* dyld.1 in usr|share|man|man1 */,
+                               F908136411D3FB0300626CC1 /* dyld.1 in usr|share|man|man1 */,
                        );
                        name = "usr|share|man|man1";
                        runOnlyForDeploymentPostprocessing = 1;
                };
                        );
                        name = "usr|share|man|man1";
                        runOnlyForDeploymentPostprocessing = 1;
                };
-               F93AA9C60630AF1F00301D9F /* usr|share|man|man3 */ = {
+               F908137311D3FB5000626CC1 /* usr|share|man|man3 */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                        dstPath = /usr/share/man/man3;
                        dstSubfolderSpec = 0;
                        files = (
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                        dstPath = /usr/share/man/man3;
                        dstSubfolderSpec = 0;
                        files = (
-                               EF79A011070D295200F78484 /* dladdr.3 in usr|share|man|man3 */,
-                               EF79A012070D295200F78484 /* dlclose.3 in usr|share|man|man3 */,
-                               EF79A013070D295200F78484 /* dlerror.3 in usr|share|man|man3 */,
-                               EF79A014070D295200F78484 /* dlopen.3 in usr|share|man|man3 */,
-                               EF79A015070D295200F78484 /* dlsym.3 in usr|share|man|man3 */,
-                               EF79A016070D295200F78484 /* dyld.3 in usr|share|man|man3 */,
-                               F9E572020A66EF4A007D9BE9 /* dlopen_preflight.3 in usr|share|man|man3 */,
+                               F908136811D3FB3A00626CC1 /* dladdr.3 in usr|share|man|man3 */,
+                               F908136911D3FB3A00626CC1 /* dlclose.3 in usr|share|man|man3 */,
+                               F908136A11D3FB3A00626CC1 /* dlerror.3 in usr|share|man|man3 */,
+                               F908136B11D3FB3A00626CC1 /* dlopen.3 in usr|share|man|man3 */,
+                               F908136C11D3FB3A00626CC1 /* dlsym.3 in usr|share|man|man3 */,
+                               F908136D11D3FB3A00626CC1 /* dyld.3 in usr|share|man|man3 */,
+                               F908136E11D3FB3A00626CC1 /* dlopen_preflight.3 in usr|share|man|man3 */,
                        );
                        name = "usr|share|man|man3";
                        runOnlyForDeploymentPostprocessing = 1;
                };
                        );
                        name = "usr|share|man|man3";
                        runOnlyForDeploymentPostprocessing = 1;
                };
-               F9574CB206C95C0D00142BFA /* usr|include */ = {
+               F98C78D10F7C00EA006257D2 /* usr|local|include|mach-o */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = /usr/include;
+                       dstPath = "$(INSTALL_LOCATION)/usr/local/include/mach-o";
                        dstSubfolderSpec = 0;
                        files = (
                        dstSubfolderSpec = 0;
                        files = (
-                               F9574CB306C95C1B00142BFA /* dlfcn.h in usr|include */,
+                               F98C78F00F7C02E8006257D2 /* dsc_iterator.h in usr|local|include|mach-o */,
+                               F9CE307B1208F1C60098B590 /* dsc_extractor.h in usr|local|include|mach-o */,
                        );
                        );
-                       name = "usr|include";
+                       name = "usr|local|include|mach-o";
                        runOnlyForDeploymentPostprocessing = 1;
                };
                        runOnlyForDeploymentPostprocessing = 1;
                };
-               F98C78D10F7C00EA006257D2 /* usr|local|include|mach-o */ = {
+               F9B0913511F11D8B00096D49 /* usr|local|include|mach-o */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = "/usr/local/include/mach-o";
+                       dstPath = "usr/local/include/mach-o";
                        dstSubfolderSpec = 0;
                        files = (
                        dstSubfolderSpec = 0;
                        files = (
-                               F98C78F00F7C02E8006257D2 /* dsc_iterator.h in usr|local|include|mach-o */,
+                               F9B0913911F11DD300096D49 /* dsc_slider.h in usr|local|include|mach-o */,
                        );
                        name = "usr|local|include|mach-o";
                        runOnlyForDeploymentPostprocessing = 1;
                        );
                        name = "usr|local|include|mach-o";
                        runOnlyForDeploymentPostprocessing = 1;
                F9D238DD0A9E2FEE002B55C7 /* usr|share|man|man1 */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                F9D238DD0A9E2FEE002B55C7 /* usr|share|man|man1 */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = /usr/share/man/man1;
+                       dstPath = "$(INSTALL_LOCATION)/usr/$(LOCAL)/share/man/man1";
                        dstSubfolderSpec = 0;
                        files = (
                                F9D238DB0A9E2FD0002B55C7 /* update_dyld_shared_cache.1 in usr|share|man|man1 */,
                        dstSubfolderSpec = 0;
                        files = (
                                F9D238DB0A9E2FD0002B55C7 /* update_dyld_shared_cache.1 in usr|share|man|man1 */,
                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>"; };
                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>"; };
                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>"; };
                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>"; };
+               F99B8E620FEC11B400701838 /* dyld_shared_cache_util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dyld_shared_cache_util.cpp; sourceTree = "<group>"; };
+               F99B8E670FEC121100701838 /* dyld_shared_cache_util */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dyld_shared_cache_util; sourceTree = BUILT_PRODUCTS_DIR; };
                F99EE6AE06B48D4200BF1992 /* dlfcn.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dlfcn.h; path = include/dlfcn.h; sourceTree = "<group>"; };
                F99EFC0D0EAD60E8001032B8 /* dyld_stub_binder.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = dyld_stub_binder.s; path = src/dyld_stub_binder.s; sourceTree = "<group>"; };
                F9A221E60F3A6D7C00D15F73 /* dyldLibSystemGlue.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dyldLibSystemGlue.c; path = src/dyldLibSystemGlue.c; sourceTree = "<group>"; };
                F99EE6AE06B48D4200BF1992 /* dlfcn.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dlfcn.h; path = include/dlfcn.h; sourceTree = "<group>"; };
                F99EFC0D0EAD60E8001032B8 /* dyld_stub_binder.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = dyld_stub_binder.s; path = src/dyld_stub_binder.s; sourceTree = "<group>"; };
                F9A221E60F3A6D7C00D15F73 /* dyldLibSystemGlue.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dyldLibSystemGlue.c; path = src/dyldLibSystemGlue.c; sourceTree = "<group>"; };
+               F9A6D6E2116F9DF20051CC16 /* threadLocalVariables.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = threadLocalVariables.c; path = src/threadLocalVariables.c; 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; };
                F9B01E3D0739ABDE00CF981B /* dyld.exp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.exports; name = dyld.exp; path = src/dyld.exp; sourceTree = SOURCE_ROOT; };
                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; };
                F9B01E3D0739ABDE00CF981B /* dyld.exp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.exports; name = dyld.exp; path = src/dyld.exp; sourceTree = SOURCE_ROOT; };
+               F9B0912311F11D1600096D49 /* libdsc_slider.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdsc_slider.a; sourceTree = BUILT_PRODUCTS_DIR; };
+               F9B0912811F11D3400096D49 /* dsc_slider.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dsc_slider.cpp; sourceTree = "<group>"; };
+               F9B0913811F11DAB00096D49 /* dsc_slider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dsc_slider.h; sourceTree = "<group>"; };
+               F9CE30781208F1B50098B590 /* dsc_extractor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dsc_extractor.cpp; sourceTree = "<group>"; };
+               F9CE30791208F1B50098B590 /* dsc_extractor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dsc_extractor.h; sourceTree = "<group>"; };
                F9D238D90A9E19A0002B55C7 /* update_dyld_shared_cache.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; path = update_dyld_shared_cache.1; sourceTree = "<group>"; };
                F9E572000A66EF41007D9BE9 /* dlopen_preflight.3 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = dlopen_preflight.3; sourceTree = "<group>"; };
                F9ED4C980630A76000DF4E74 /* dyld */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dyld; sourceTree = BUILT_PRODUCTS_DIR; };
                F9D238D90A9E19A0002B55C7 /* update_dyld_shared_cache.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; path = update_dyld_shared_cache.1; sourceTree = "<group>"; };
                F9E572000A66EF41007D9BE9 /* dlopen_preflight.3 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = dlopen_preflight.3; sourceTree = "<group>"; };
                F9ED4C980630A76000DF4E74 /* dyld */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dyld; sourceTree = BUILT_PRODUCTS_DIR; };
-               F9ED4C9F0630A76B00DF4E74 /* libdyldapis.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdyldapis.a; sourceTree = BUILT_PRODUCTS_DIR; };
+               F9ED4C9F0630A76B00DF4E74 /* libdyld.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libdyld.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
                F9ED4CC60630A7F100DF4E74 /* dyld_gdb.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = dyld_gdb.cpp; path = src/dyld_gdb.cpp; sourceTree = SOURCE_ROOT; };
                F9ED4CC70630A7F100DF4E74 /* dyld.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = dyld.cpp; path = src/dyld.cpp; sourceTree = SOURCE_ROOT; };
                F9ED4CC80630A7F100DF4E74 /* dyld.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dyld.h; path = src/dyld.h; sourceTree = SOURCE_ROOT; };
                F9ED4CC60630A7F100DF4E74 /* dyld_gdb.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = dyld_gdb.cpp; path = src/dyld_gdb.cpp; sourceTree = SOURCE_ROOT; };
                F9ED4CC70630A7F100DF4E74 /* dyld.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = dyld.cpp; path = src/dyld.cpp; sourceTree = SOURCE_ROOT; };
                F9ED4CC80630A7F100DF4E74 /* dyld.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dyld.h; path = src/dyld.h; sourceTree = SOURCE_ROOT; };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               F99B8E540FEC10F600701838 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                F9F2A5570F7AEE9800B7C9EB /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                F9F2A5570F7AEE9800B7C9EB /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                                F93937460A94FC4700070A07 /* update_dyld_shared_cache.cpp */,
                                F9F2A56E0F7AEEE300B7C9EB /* dsc_iterator.cpp */,
                                F9F2A56F0F7AEEE300B7C9EB /* dsc_iterator.h */,
                                F93937460A94FC4700070A07 /* update_dyld_shared_cache.cpp */,
                                F9F2A56E0F7AEEE300B7C9EB /* dsc_iterator.cpp */,
                                F9F2A56F0F7AEEE300B7C9EB /* dsc_iterator.h */,
+                               F9B0912811F11D3400096D49 /* dsc_slider.cpp */,
+                               F9B0913811F11DAB00096D49 /* dsc_slider.h */,
+                               F9CE30781208F1B50098B590 /* dsc_extractor.cpp */,
+                               F9CE30791208F1B50098B590 /* dsc_extractor.h */,
+                               F99B8E620FEC11B400701838 /* dyld_shared_cache_util.cpp */,
                        );
                        path = "launch-cache";
                        sourceTree = "<group>";
                        );
                        path = "launch-cache";
                        sourceTree = "<group>";
                        isa = PBXGroup;
                        children = (
                                F9ED4C980630A76000DF4E74 /* dyld */,
                        isa = PBXGroup;
                        children = (
                                F9ED4C980630A76000DF4E74 /* dyld */,
-                               F9ED4C9F0630A76B00DF4E74 /* libdyldapis.a */,
+                               F9ED4C9F0630A76B00DF4E74 /* libdyld.dylib */,
                                F93937320A94FAF700070A07 /* update_dyld_shared_cache */,
                                F9F2A5590F7AEE9800B7C9EB /* libdsc.a */,
                                F93937320A94FAF700070A07 /* update_dyld_shared_cache */,
                                F9F2A5590F7AEE9800B7C9EB /* libdsc.a */,
+                               F99B8E670FEC121100701838 /* dyld_shared_cache_util */,
+                               F9B0912311F11D1600096D49 /* libdsc_slider.a */,
                        );
                        name = Products;
                        sourceTree = "<group>";
                        );
                        name = Products;
                        sourceTree = "<group>";
                                F94DB9030F0A9B1700323715 /* ImageLoaderMachOCompressed.h */,
                                F9ED4CD50630A7F100DF4E74 /* stub_binding_helper.s */,
                                F9B01E3D0739ABDE00CF981B /* dyld.exp */,
                                F94DB9030F0A9B1700323715 /* ImageLoaderMachOCompressed.h */,
                                F9ED4CD50630A7F100DF4E74 /* stub_binding_helper.s */,
                                F9B01E3D0739ABDE00CF981B /* dyld.exp */,
+                               F976F548127B90F8004BA2A5 /* dyld.order */,
                                F9AC7E930B7BB67700FEB38B /* version.c */,
                                F918691408B16D2500E0F9DB /* dyld-interposing.h */,
                                F9A221E60F3A6D7C00D15F73 /* dyldLibSystemGlue.c */,
                                F906E2230639E96400B13DB2 /* dyld_debug.c */,
                                F9AC7E930B7BB67700FEB38B /* version.c */,
                                F918691408B16D2500E0F9DB /* dyld-interposing.h */,
                                F9A221E60F3A6D7C00D15F73 /* dyldLibSystemGlue.c */,
                                F906E2230639E96400B13DB2 /* dyld_debug.c */,
+                               F9A6D6E2116F9DF20051CC16 /* threadLocalVariables.c */,
+                               F9A6D70B116FBBD10051CC16 /* threadLocalHelpers.s */,
                        );
                        name = src;
                        sourceTree = "<group>";
                        );
                        name = src;
                        sourceTree = "<group>";
                                F939372F0A94FAF700070A07 /* Sources */,
                                F93937300A94FAF700070A07 /* Frameworks */,
                                F9D238DD0A9E2FEE002B55C7 /* usr|share|man|man1 */,
                                F939372F0A94FAF700070A07 /* Sources */,
                                F93937300A94FAF700070A07 /* Frameworks */,
                                F9D238DD0A9E2FEE002B55C7 /* usr|share|man|man1 */,
+                               F991E3030FF1A4EC0082CCC9 /* do not install duplicates */,
                        );
                        buildRules = (
                        );
                        dependencies = (
                        );
                        buildRules = (
                        );
                        dependencies = (
-                               F98C78DA0F7C017F006257D2 /* PBXTargetDependency */,
+                               F99B8EA00FEC195800701838 /* PBXTargetDependency */,
+                               F9CE330B120F40EA0098B590 /* PBXTargetDependency */,
                        );
                        name = update_dyld_shared_cache;
                        productName = update_dyld_shared_cache;
                        productReference = F93937320A94FAF700070A07 /* update_dyld_shared_cache */;
                        productType = "com.apple.product-type.tool";
                };
                        );
                        name = update_dyld_shared_cache;
                        productName = update_dyld_shared_cache;
                        productReference = F93937320A94FAF700070A07 /* update_dyld_shared_cache */;
                        productType = "com.apple.product-type.tool";
                };
+               F99B8E550FEC10F600701838 /* dyld_shared_cache_util */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = F99B8E5D0FEC10F800701838 /* Build configuration list for PBXNativeTarget "dyld_shared_cache_util" */;
+                       buildPhases = (
+                               F99B8E530FEC10F600701838 /* Sources */,
+                               F99B8E540FEC10F600701838 /* Frameworks */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = dyld_shared_cache_util;
+                       productName = dscutil;
+                       productReference = F99B8E670FEC121100701838 /* dyld_shared_cache_util */;
+                       productType = "com.apple.product-type.tool";
+               };
+               F9B0912211F11D1600096D49 /* libdsc_slider */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = F9B0912A11F11D3400096D49 /* Build configuration list for PBXNativeTarget "libdsc_slider" */;
+                       buildPhases = (
+                               F9B0912011F11D1600096D49 /* Sources */,
+                               F9B0913511F11D8B00096D49 /* usr|local|include|mach-o */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = libdsc_slider;
+                       productName = libdsc_slider;
+                       productReference = F9B0912311F11D1600096D49 /* libdsc_slider.a */;
+                       productType = "com.apple.product-type.library.static";
+               };
                F9ED4C970630A76000DF4E74 /* dyld */ = {
                        isa = PBXNativeTarget;
                        buildConfigurationList = F9D8C7DD087B087300E93EFB /* Build configuration list for PBXNativeTarget "dyld" */;
                        buildPhases = (
                F9ED4C970630A76000DF4E74 /* dyld */ = {
                        isa = PBXNativeTarget;
                        buildConfigurationList = F9D8C7DD087B087300E93EFB /* Build configuration list for PBXNativeTarget "dyld" */;
                        buildPhases = (
+                               F9D050C811DD701A00FB0A29 /* configure archives */,
                                F9ED4C950630A76000DF4E74 /* Sources */,
                                F9ED4C950630A76000DF4E74 /* Sources */,
+                               F907E2490FA6469000BFEDBD /* install iPhone file */,
+                               F99B8EB60FEC236500701838 /* suppress macosx dyld_shared_cache_util */,
                        );
                        buildRules = (
                                F921D318070376B0000D1056 /* PBXBuildRule */,
                        );
                        buildRules = (
                                F921D318070376B0000D1056 /* PBXBuildRule */,
                                F921D3160703769A000D1056 /* PBXBuildRule */,
                        );
                        dependencies = (
                                F921D3160703769A000D1056 /* PBXBuildRule */,
                        );
                        dependencies = (
+                               F99B8EB20FEC220C00701838 /* PBXTargetDependency */,
                        );
                        name = dyld;
                        productName = dyld;
                        productReference = F9ED4C980630A76000DF4E74 /* dyld */;
                        productType = "com.apple.product-type.tool";
                };
                        );
                        name = dyld;
                        productName = dyld;
                        productReference = F9ED4C980630A76000DF4E74 /* dyld */;
                        productType = "com.apple.product-type.tool";
                };
-               F9ED4C9E0630A76B00DF4E74 /* libdyld */ = {
+               F9ED4C9E0630A76B00DF4E74 /* libdyld.dylib */ = {
                        isa = PBXNativeTarget;
                        isa = PBXNativeTarget;
-                       buildConfigurationList = F9D8C7E1087B087300E93EFB /* Build configuration list for PBXNativeTarget "libdyld" */;
+                       buildConfigurationList = F9D8C7E1087B087300E93EFB /* Build configuration list for PBXNativeTarget "libdyld.dylib" */;
                        buildPhases = (
                        buildPhases = (
-                               F9AC7E7E0B7BB3D300FEB38B /* create version.c */,
                                F9ED4C9C0630A76B00DF4E74 /* Sources */,
                                F9ED4C9C0630A76B00DF4E74 /* Sources */,
-                               F93AA9B30630AE8200301D9F /* usr|include|mach-o */,
-                               F9574CB206C95C0D00142BFA /* usr|include */,
-                               F90CF2950E71D1FB000BF0F1 /* usr|local|include */,
-                               F93AA9B60630AEB100301D9F /* usr|local|include|mach-o */,
-                               F93AA9C20630AF0700301D9F /* usr|share|man|man1 */,
-                               F93AA9C60630AF1F00301D9F /* usr|share|man|man3 */,
-                               F918692408B16F6900E0F9DB /* install symlinks */,
                        );
                        buildRules = (
                                F921D31E070376F1000D1056 /* PBXBuildRule */,
                        );
                        buildRules = (
                                F921D31E070376F1000D1056 /* PBXBuildRule */,
                        );
                        dependencies = (
                        );
                        );
                        dependencies = (
                        );
-                       name = libdyld;
+                       name = libdyld.dylib;
                        productName = libdyld;
                        productName = libdyld;
-                       productReference = F9ED4C9F0630A76B00DF4E74 /* libdyldapis.a */;
-                       productType = "com.apple.product-type.library.static";
+                       productReference = F9ED4C9F0630A76B00DF4E74 /* libdyld.dylib */;
+                       productType = "com.apple.product-type.library.dynamic";
                };
                };
-               F9F2A5580F7AEE9800B7C9EB /* dsc */ = {
+               F9F2A5580F7AEE9800B7C9EB /* libdsc */ = {
                        isa = PBXNativeTarget;
                        isa = PBXNativeTarget;
-                       buildConfigurationList = F9F2A56B0F7AEEB100B7C9EB /* Build configuration list for PBXNativeTarget "dsc" */;
+                       buildConfigurationList = F9F2A56B0F7AEEB100B7C9EB /* Build configuration list for PBXNativeTarget "libdsc" */;
                        buildPhases = (
                                F9F2A5560F7AEE9800B7C9EB /* Sources */,
                                F9F2A5570F7AEE9800B7C9EB /* Frameworks */,
                        buildPhases = (
                                F9F2A5560F7AEE9800B7C9EB /* Sources */,
                                F9F2A5570F7AEE9800B7C9EB /* Frameworks */,
                        );
                        dependencies = (
                        );
                        );
                        dependencies = (
                        );
-                       name = dsc;
+                       name = libdsc;
                        productName = dsc;
                        productReference = F9F2A5590F7AEE9800B7C9EB /* libdsc.a */;
                        productType = "com.apple.product-type.library.static";
                        productName = dsc;
                        productReference = F9F2A5590F7AEE9800B7C9EB /* libdsc.a */;
                        productType = "com.apple.product-type.library.static";
                F9ED4C8B0630A72300DF4E74 /* Project object */ = {
                        isa = PBXProject;
                        buildConfigurationList = F9D8C7E9087B087300E93EFB /* Build configuration list for PBXProject "dyld" */;
                F9ED4C8B0630A72300DF4E74 /* Project object */ = {
                        isa = PBXProject;
                        buildConfigurationList = F9D8C7E9087B087300E93EFB /* Build configuration list for PBXProject "dyld" */;
-                       compatibilityVersion = "Xcode 2.4";
+                       compatibilityVersion = "Xcode 3.1";
+                       developmentRegion = English;
                        hasScannedForEncodings = 1;
                        hasScannedForEncodings = 1;
+                       knownRegions = (
+                               English,
+                               Japanese,
+                               French,
+                               German,
+                       );
                        mainGroup = F9ED4C870630A72200DF4E74;
                        productRefGroup = F9ED4C990630A76000DF4E74 /* Products */;
                        projectDirPath = "";
                        mainGroup = F9ED4C870630A72200DF4E74;
                        productRefGroup = F9ED4C990630A76000DF4E74 /* Products */;
                        projectDirPath = "";
                        targets = (
                                F9ED4C920630A73900DF4E74 /* all */,
                                F9ED4C970630A76000DF4E74 /* dyld */,
                        targets = (
                                F9ED4C920630A73900DF4E74 /* all */,
                                F9ED4C970630A76000DF4E74 /* dyld */,
-                               F9ED4C9E0630A76B00DF4E74 /* libdyld */,
+                               F908134211D3ED0B00626CC1 /* libdyld */,
+                               F9ED4C9E0630A76B00DF4E74 /* libdyld.dylib */,
                                F93937310A94FAF700070A07 /* update_dyld_shared_cache */,
                                F93937310A94FAF700070A07 /* update_dyld_shared_cache */,
-                               F9F2A5580F7AEE9800B7C9EB /* dsc */,
+                               F9F2A5580F7AEE9800B7C9EB /* libdsc */,
+                               F99B8E550FEC10F600701838 /* dyld_shared_cache_util */,
+                               F9B0912211F11D1600096D49 /* libdsc_slider */,
                        );
                };
 /* End PBXProject section */
 
 /* Begin PBXShellScriptBuildPhase section */
                        );
                };
 /* End PBXProject section */
 
 /* Begin PBXShellScriptBuildPhase section */
-               F918692408B16F6900E0F9DB /* install symlinks */ = {
+               F907E2490FA6469000BFEDBD /* install iPhone file */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 8;
                        files = (
                        );
                        inputPaths = (
                        );
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 8;
                        files = (
                        );
                        inputPaths = (
                        );
-                       name = "install symlinks";
+                       name = "install iPhone file";
                        outputPaths = (
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                        shellPath = /bin/sh;
                        outputPaths = (
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                        shellPath = /bin/sh;
-                       shellScript = "cd ${DSTROOT}/usr/local/lib/system\nln -sf libdyldapis.a libdyldapis_profile.a\nln -sf libdyldapis.a libdyldapis_debug.a\n";
+                       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;
                };
                        showEnvVarsInLog = 0;
                };
-               F9AC7E7E0B7BB3D300FEB38B /* create version.c */ = {
+               F991E3030FF1A4EC0082CCC9 /* do not install duplicates */ = {
                        isa = PBXShellScriptBuildPhase;
                        isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
+                       buildActionMask = 8;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       name = "do not install duplicates";
+                       outputPaths = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+                       shellPath = /bin/sh;
+                       shellScript = "if [ \"${INSTALL_LOCATION}\" = \"\" ] \nthen\n     # on iOS, libdyld builds arm libdsc.a and u_d_s_c builds intel libdsc.a\n     # on MacOSX, to avoid collision, u_d_s_c does not install libdsc.a\n\trm -rf ${DSTROOT}/usr/local/include\n\trm -rf ${DSTROOT}/usr/local/lib\nfi\n";
+                       showEnvVarsInLog = 0;
+               };
+               F99B8EB60FEC236500701838 /* suppress macosx dyld_shared_cache_util */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 8;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       name = "suppress macosx dyld_shared_cache_util";
+                       outputPaths = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+                       shellPath = /bin/sh;
+                       shellScript = "# iPhone wants a copy of dyld_shared_cache_util on the device\n# MacOSX does not need a copy because update_dyld_shared_cache target already installed a copy\nif [ \"${PLATFORM_NAME}\" = \"macosx\" ] \nthen\n\trm -rf ${DSTROOT}/usr/local\nfi\n";
+                       showEnvVarsInLog = 0;
+               };
+               F9D050C811DD701A00FB0A29 /* configure archives */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 12;
                        files = (
                        );
                        inputPaths = (
                        );
                        files = (
                        );
                        inputPaths = (
                        );
-                       name = "create version.c";
+                       name = "configure archives";
                        outputPaths = (
                        outputPaths = (
-                               "$(BUILT_PRODUCTS_DIR)/version.c",
+                               "$(DERIVED_SOURCES_DIR)/archives.txt",
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/sh;
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/sh;
-                       shellScript = "/Developer/Makefiles/bin/version.pl ${ProjectName} > ${BUILT_PRODUCTS_DIR}/version.c\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";
                        showEnvVarsInLog = 0;
                };
 /* End PBXShellScriptBuildPhase section */
                        showEnvVarsInLog = 0;
                };
 /* End PBXShellScriptBuildPhase section */
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               F99B8E530FEC10F600701838 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               F99B8EA30FEC1C4200701838 /* dsc_iterator.cpp in Sources */,
+                               F99B8E630FEC11B400701838 /* dyld_shared_cache_util.cpp in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               F9B0912011F11D1600096D49 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               F9B0912911F11D3400096D49 /* dsc_slider.cpp in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                F9ED4C950630A76000DF4E74 /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                F9ED4C950630A76000DF4E74 /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                                F9ED4CE30630A7F100DF4E74 /* ImageLoaderMachO.cpp in Sources */,
                                F9ED4CE50630A7F100DF4E74 /* stub_binding_helper.s in Sources */,
                                F9ED4CDE0630A7F100DF4E74 /* dyldNew.cpp in Sources */,
                                F9ED4CE30630A7F100DF4E74 /* ImageLoaderMachO.cpp in Sources */,
                                F9ED4CE50630A7F100DF4E74 /* stub_binding_helper.s in Sources */,
                                F9ED4CDE0630A7F100DF4E74 /* dyldNew.cpp in Sources */,
-                               F99EFC0E0EAD60E8001032B8 /* dyld_stub_binder.s in Sources */,
                                F94DB9040F0A9B1700323715 /* ImageLoaderMachOClassic.cpp in Sources */,
                                F94DB9050F0A9B1700323715 /* ImageLoaderMachOCompressed.cpp in Sources */,
                        );
                                F94DB9040F0A9B1700323715 /* ImageLoaderMachOClassic.cpp in Sources */,
                                F94DB9050F0A9B1700323715 /* ImageLoaderMachOCompressed.cpp in Sources */,
                        );
                        buildActionMask = 2147483647;
                        files = (
                                F9F256360639DBCC00A7427D /* dyldLock.cpp in Sources */,
                        buildActionMask = 2147483647;
                        files = (
                                F9F256360639DBCC00A7427D /* dyldLock.cpp in Sources */,
-                               F913FADA0630A8AE00B7AE9D /* dyldAPIsInLibSystem.cpp in Sources */,
-                               F906E2240639E96400B13DB2 /* dyld_debug.c in Sources */,
                                F9BA514B0ECE4F4200D1D62E /* dyld_stub_binder.s in Sources */,
                                F9BA514B0ECE4F4200D1D62E /* dyld_stub_binder.s in Sources */,
-                               F9AC7E940B7BB67700FEB38B /* version.c in Sources */,
                                F9A221E70F3A6D7C00D15F73 /* dyldLibSystemGlue.c in Sources */,
                                F9A221E70F3A6D7C00D15F73 /* dyldLibSystemGlue.c in Sources */,
+                               F913FADA0630A8AE00B7AE9D /* dyldAPIsInLibSystem.cpp in Sources */,
+                               F906E2240639E96400B13DB2 /* dyld_debug.c in Sources */,
+                               F9A6D6E4116F9DF20051CC16 /* threadLocalVariables.c in Sources */,
+                               F9A6D70C116FBBD10051CC16 /* threadLocalHelpers.s in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        buildActionMask = 2147483647;
                        files = (
                                F9F2A5700F7AEEE300B7C9EB /* dsc_iterator.cpp in Sources */,
                        buildActionMask = 2147483647;
                        files = (
                                F9F2A5700F7AEEE300B7C9EB /* dsc_iterator.cpp in Sources */,
+                               F9CE307A1208F1B50098B590 /* dsc_extractor.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
 /* End PBXSourcesBuildPhase section */
 
 /* Begin PBXTargetDependency section */
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
 /* End PBXSourcesBuildPhase section */
 
 /* Begin PBXTargetDependency section */
+               F908134811D3ED1A00626CC1 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = F9ED4C9E0630A76B00DF4E74 /* libdyld.dylib */;
+                       targetProxy = F908134711D3ED1A00626CC1 /* PBXContainerItemProxy */;
+               };
                F93937380A94FB6A00070A07 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = F93937310A94FAF700070A07 /* update_dyld_shared_cache */;
                        targetProxy = F93937370A94FB6A00070A07 /* PBXContainerItemProxy */;
                };
                F93937380A94FB6A00070A07 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = F93937310A94FAF700070A07 /* update_dyld_shared_cache */;
                        targetProxy = F93937370A94FB6A00070A07 /* PBXContainerItemProxy */;
                };
-               F98C78DA0F7C017F006257D2 /* PBXTargetDependency */ = {
+               F99B8EA00FEC195800701838 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = F99B8E550FEC10F600701838 /* dyld_shared_cache_util */;
+                       targetProxy = F99B8E9F0FEC195800701838 /* PBXContainerItemProxy */;
+               };
+               F99B8EB20FEC220C00701838 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = F99B8E550FEC10F600701838 /* dyld_shared_cache_util */;
+                       targetProxy = F99B8EB10FEC220C00701838 /* PBXContainerItemProxy */;
+               };
+               F9B4D78012AD9736000605A6 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = F9F2A5580F7AEE9800B7C9EB /* libdsc */;
+                       targetProxy = F9B4D77F12AD9736000605A6 /* PBXContainerItemProxy */;
+               };
+               F9CE330B120F40EA0098B590 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        isa = PBXTargetDependency;
-                       target = F9F2A5580F7AEE9800B7C9EB /* dsc */;
-                       targetProxy = F98C78D90F7C017F006257D2 /* PBXContainerItemProxy */;
+                       target = F9F2A5580F7AEE9800B7C9EB /* libdsc */;
+                       targetProxy = F9CE330A120F40EA0098B590 /* PBXContainerItemProxy */;
                };
                F9ED4CA70630A78A00DF4E74 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                };
                F9ED4CA70630A78A00DF4E74 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                };
                F9ED4CA90630A78A00DF4E74 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                };
                F9ED4CA90630A78A00DF4E74 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = F9ED4C9E0630A76B00DF4E74 /* libdyld */;
+                       target = F9ED4C9E0630A76B00DF4E74 /* libdyld.dylib */;
                        targetProxy = F9ED4CA80630A78A00DF4E74 /* PBXContainerItemProxy */;
                };
 /* End PBXTargetDependency section */
 
 /* Begin XCBuildConfiguration section */
                        targetProxy = F9ED4CA80630A78A00DF4E74 /* PBXContainerItemProxy */;
                };
 /* End PBXTargetDependency section */
 
 /* Begin XCBuildConfiguration section */
+               F908134311D3ED0C00626CC1 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               INSTALLHDRS_COPY_PHASE = YES;
+                               PRODUCT_NAME = libdyld;
+                       };
+                       name = Debug;
+               };
+               F908134411D3ED0C00626CC1 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               INSTALLHDRS_COPY_PHASE = YES;
+                               PRODUCT_NAME = libdyld;
+                               ZERO_LINK = NO;
+                       };
+                       name = Release;
+               };
                F93937350A94FB2900070A07 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                F93937350A94FB2900070A07 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                GCC_WARN_UNUSED_VARIABLE = YES;
                                PREBINDING = NO;
                                PRODUCT_NAME = update_dyld_shared_cache;
                                GCC_WARN_UNUSED_VARIABLE = YES;
                                PREBINDING = NO;
                                PRODUCT_NAME = update_dyld_shared_cache;
-                               VALID_ARCHS = "ppc i386";
+                               VALID_ARCHS = "x86_64 i386";
                        };
                        name = Debug;
                };
                F93937360A94FB2900070A07 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                        };
                        name = Debug;
                };
                F93937360A94FB2900070A07 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               ARCHS = x86_64;
                                COPY_PHASE_STRIP = NO;
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                COPY_PHASE_STRIP = NO;
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               GCC_OPTIMIZATION_LEVEL = 3;
+                               GCC_OPTIMIZATION_LEVEL = s;
                                GCC_THREADSAFE_STATICS = NO;
                                GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
                                GCC_THREADSAFE_STATICS = NO;
                                GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
-                               INSTALL_PATH = /usr/bin;
+                               INSTALL_PATH = "$(INSTALL_LOCATION)/usr/$(LOCAL)/bin";
+                               LOCAL = "$(LOCAL_$(RC_TARGET_CONFIG))";
+                               LOCAL_iPhone = local;
                                PREBINDING = NO;
                                PRODUCT_NAME = update_dyld_shared_cache;
                                STRIP_INSTALLED_PRODUCT = YES;
                                PREBINDING = NO;
                                PRODUCT_NAME = update_dyld_shared_cache;
                                STRIP_INSTALLED_PRODUCT = YES;
                        };
                        name = Release;
                };
                        };
                        name = Release;
                };
+               F99B8E580FEC10F600701838 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               COPY_PHASE_STRIP = NO;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
+                               INSTALL_PATH = "$(INSTALL_LOCATION)/usr/local/bin";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = dyld_shared_cache_util;
+                       };
+                       name = Debug;
+               };
+               F99B8E590FEC10F600701838 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               COPY_PHASE_STRIP = YES;
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
+                               INSTALL_PATH = "$(INSTALL_LOCATION)/usr/local/bin";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = dyld_shared_cache_util;
+                               SKIP_INSTALL = NO;
+                       };
+                       name = Release;
+               };
+               F9B0912411F11D1700096D49 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               COPY_PHASE_STRIP = NO;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               INSTALL_PATH = /usr/local/lib;
+                               PREBINDING = NO;
+                               PRODUCT_NAME = libdsc_slider;
+                       };
+                       name = Debug;
+               };
+               F9B0912511F11D1700096D49 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               COPY_PHASE_STRIP = NO;
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               INSTALLHDRS_COPY_PHASE = YES;
+                               INSTALL_PATH = /usr/local/lib;
+                               PRODUCT_NAME = dsc_slider;
+                               ZERO_LINK = NO;
+                       };
+                       name = Release;
+               };
                F9D8C7DE087B087300E93EFB /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                ARCHS = (
                F9D8C7DE087B087300E93EFB /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                ARCHS = (
-                                       ppc,
                                        i386,
                                        x86_64,
                                );
                                        i386,
                                        x86_64,
                                );
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                DEAD_CODE_STRIPPING = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                DEAD_CODE_STRIPPING = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
-                               EXCEPTION_LIB_armv6 = "-lgcc_eh";
-                               EXCEPTION_LIB_armv7 = "-lgcc_eh";
-                               EXCEPTION_LIB_i386 = /usr/local/lib/dyld/libunwind.a;
-                               EXCEPTION_LIB_ppc = /usr/local/lib/dyld/libunwind.a;
-                               EXCEPTION_LIB_x86_64 = /usr/local/lib/dyld/libunwind.a;
                                EXPORTED_SYMBOLS_FILE = "$(SRCROOT)/src/dyld.exp";
                                GCC_C_LANGUAGE_STANDARD = c99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                EXPORTED_SYMBOLS_FILE = "$(SRCROOT)/src/dyld.exp";
                                GCC_C_LANGUAGE_STANDARD = c99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                        "./launch-cache",
                                );
                                INSTALL_PATH = /usr/lib;
                                        "./launch-cache",
                                );
                                INSTALL_PATH = /usr/lib;
-                               LIBC_OVERRIDES_iphoneos = "";
-                               LIBC_OVERRIDES_macosx = "/usr/local/lib/system/libc-dyld.a";
                                OTHER_CFLAGS = "";
                                OTHER_LDFLAGS = (
                                        "-seg1addr",
                                        "$(BASE_ADDRESS_$(CURRENT_ARCH))",
                                OTHER_CFLAGS = "";
                                OTHER_LDFLAGS = (
                                        "-seg1addr",
                                        "$(BASE_ADDRESS_$(CURRENT_ARCH))",
-                                       "-lstdc++-static",
-                                       "$(LIBC_OVERRIDES_$(PLATFORM_NAME))",
+                                       "@$(DERIVED_SOURCES_DIR)/archives.txt",
                                        "-nostdlib",
                                        "-nostdlib",
-                                       /usr/local/lib/system/libc.a,
-                                       /usr/local/lib/libCoreSymbolicationSharedWithDyld.a,
-                                       "$(EXCEPTION_LIB_$(CURRENT_ARCH))",
                                        "-lgcc",
                                        "-Wl,-e,__dyld_start",
                                        "-Wl,-dylinker",
                                        "-Wl,-dylinker_install_name,/usr/lib/dyld",
                                );
                                        "-lgcc",
                                        "-Wl,-e,__dyld_start",
                                        "-Wl,-dylinker",
                                        "-Wl,-dylinker_install_name,/usr/lib/dyld",
                                );
-                               PER_ARCH_CFLAGS_ppc = "";
                                PREBINDING = NO;
                                PRODUCT_NAME = dyld;
                                STRIPFLAGS = "-S";
                                PREBINDING = NO;
                                PRODUCT_NAME = dyld;
                                STRIPFLAGS = "-S";
                F9D8C7E0087B087300E93EFB /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                F9D8C7E0087B087300E93EFB /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+                               ARCHS = (
+                                       x86_64,
+                                       i386,
+                               );
                                BASE_ADDRESS_armv4t = 0x2fe00000;
                                BASE_ADDRESS_armv5 = 0x2fe00000;
                                BASE_ADDRESS_armv6 = 0x2fe00000;
                                BASE_ADDRESS_armv4t = 0x2fe00000;
                                BASE_ADDRESS_armv5 = 0x2fe00000;
                                BASE_ADDRESS_armv6 = 0x2fe00000;
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                DEAD_CODE_STRIPPING = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                DEAD_CODE_STRIPPING = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               EXCEPTION_LIB_armv6 = "-lgcc_eh";
-                               EXCEPTION_LIB_armv7 = "-lgcc_eh";
-                               EXCEPTION_LIB_i386 = /usr/local/lib/dyld/libunwind.a;
-                               EXCEPTION_LIB_ppc = /usr/local/lib/dyld/libunwind.a;
-                               EXCEPTION_LIB_x86_64 = /usr/local/lib/dyld/libunwind.a;
                                EXPORTED_SYMBOLS_FILE = "$(SRCROOT)/src/dyld.exp";
                                GCC_C_LANGUAGE_STANDARD = c99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                EXPORTED_SYMBOLS_FILE = "$(SRCROOT)/src/dyld.exp";
                                GCC_C_LANGUAGE_STANDARD = c99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                        "./launch-cache",
                                );
                                INSTALL_PATH = /usr/lib;
                                        "./launch-cache",
                                );
                                INSTALL_PATH = /usr/lib;
-                               LIBC_OVERRIDES_iphoneos = "";
-                               LIBC_OVERRIDES_macosx = "/usr/local/lib/system/libc-dyld.a";
-                               OTHER_CFLAGS = "";
+                               ORDER_FILE = "$(SRCROOT)/src/dyld.order";
+                               "OTHER_CFLAGS[arch=armv6]" = "-mthumb";
                                OTHER_LDFLAGS = (
                                        "-seg1addr",
                                        "$(BASE_ADDRESS_$(CURRENT_ARCH))",
                                OTHER_LDFLAGS = (
                                        "-seg1addr",
                                        "$(BASE_ADDRESS_$(CURRENT_ARCH))",
-                                       "-lstdc++-static",
-                                       "$(LIBC_OVERRIDES_$(PLATFORM_NAME))",
+                                       "@$(DERIVED_SOURCES_DIR)/archives.txt",
                                        "-nostdlib",
                                        "-nostdlib",
-                                       /usr/local/lib/system/libc.a,
-                                       /usr/local/lib/libCoreSymbolicationSharedWithDyld.a,
-                                       "$(EXCEPTION_LIB_$(CURRENT_ARCH))",
                                        "-lgcc",
                                        "-Wl,-e,__dyld_start",
                                        "-Wl,-dylinker",
                                        "-Wl,-dylinker_install_name,/usr/lib/dyld",
                                );
                                        "-lgcc",
                                        "-Wl,-e,__dyld_start",
                                        "-Wl,-dylinker",
                                        "-Wl,-dylinker_install_name,/usr/lib/dyld",
                                );
-                               PER_ARCH_CFLAGS_ppc = "";
                                PREBINDING = NO;
                                PRODUCT_NAME = dyld;
                                STRIPFLAGS = "-S";
                                PREBINDING = NO;
                                PRODUCT_NAME = dyld;
                                STRIPFLAGS = "-S";
                F9D8C7E2087B087300E93EFB /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                F9D8C7E2087B087300E93EFB /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ARCHS = "$(NATIVE_ARCH_ACTUAL)";
+                               ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+                               EXECUTABLE_PREFIX = lib;
+                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_ENABLE_CPP_EXCEPTIONS = NO;
                                GCC_ENABLE_CPP_RTTI = NO;
                                GCC_OPTIMIZATION_LEVEL = 0;
                                GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
                                GCC_ENABLE_CPP_EXCEPTIONS = NO;
                                GCC_ENABLE_CPP_RTTI = NO;
                                GCC_OPTIMIZATION_LEVEL = 0;
                                GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
-                               HEADER_SEARCH_PATHS = ./include;
-                               INSTALL_PATH = /usr/local/lib/system;
-                               LIBRARY_STYLE = STATIC;
-                               PRODUCT_NAME = dyldapis;
+                               HEADER_SEARCH_PATHS = "$(SRCROOT)/include";
+                               INSTALL_PATH = /usr/lib/system;
+                               PREBINDING = NO;
+                               PRODUCT_NAME = dyld;
                                WARNING_CFLAGS = (
                                        "-Wmost",
                                        "-Wno-four-char-constants",
                                WARNING_CFLAGS = (
                                        "-Wmost",
                                        "-Wno-four-char-constants",
                F9D8C7E4087B087300E93EFB /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                F9D8C7E4087B087300E93EFB /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               COPY_PHASE_STRIP = NO;
+                               ARCHS = (
+                                       x86_64,
+                                       i386,
+                               );
+                               COPY_PHASE_STRIP = YES;
+                               CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               DYLIB_CURRENT_VERSION = "$(RC_ProjectSourceVersion)";
+                               EXECUTABLE_PREFIX = lib;
+                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_ENABLE_CPP_EXCEPTIONS = NO;
                                GCC_ENABLE_CPP_RTTI = NO;
                                GCC_ENABLE_CPP_EXCEPTIONS = NO;
                                GCC_ENABLE_CPP_RTTI = NO;
-                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
                                GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
-                               HEADER_SEARCH_PATHS = ./include;
-                               INSTALL_PATH = /usr/local/lib/system;
-                               LIBRARY_STYLE = STATIC;
-                               PRODUCT_NAME = dyldapis;
+                               HEADER_SEARCH_PATHS = "$(SRCROOT)/include";
+                               INSTALLHDRS_COPY_PHASE = YES;
+                               INSTALL_PATH = /usr/lib/system;
+                               OTHER_LDFLAGS = (
+                                       "-nodefaultlibs",
+                                       "-lSystem",
+                                       "-umbrella",
+                                       System,
+                               );
+                               PREBINDING = NO;
+                               PRODUCT_NAME = dyld;
+                               SEPARATE_STRIP = YES;
+                               STRIP_INSTALLED_PRODUCT = YES;
+                               VERSIONING_SYSTEM = "apple-generic";
                                WARNING_CFLAGS = (
                                        "-Wmost",
                                        "-Wno-four-char-constants",
                                WARNING_CFLAGS = (
                                        "-Wmost",
                                        "-Wno-four-char-constants",
                                COPY_PHASE_STRIP = NO;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_ENABLE_FIX_AND_CONTINUE = YES;
                                COPY_PHASE_STRIP = NO;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
                                GCC_MODEL_TUNING = G5;
                                GCC_OPTIMIZATION_LEVEL = 0;
                                GCC_MODEL_TUNING = G5;
                                GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_SYMBOLS_PRIVATE_EXTERN = YES;
                                INSTALL_PATH = /usr/local/lib;
                                PREBINDING = NO;
                                PRODUCT_NAME = dsc;
                                INSTALL_PATH = /usr/local/lib;
                                PREBINDING = NO;
                                PRODUCT_NAME = dsc;
                F9F2A55B0F7AEE9900B7C9EB /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                F9F2A55B0F7AEE9900B7C9EB /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
-                               COPY_PHASE_STRIP = YES;
-                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               COPY_PHASE_STRIP = NO;
                                GCC_ENABLE_CPP_EXCEPTIONS = NO;
                                GCC_ENABLE_CPP_RTTI = NO;
                                GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                GCC_ENABLE_OBJC_EXCEPTIONS = NO;
                                GCC_ENABLE_CPP_EXCEPTIONS = NO;
                                GCC_ENABLE_CPP_RTTI = NO;
                                GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                GCC_ENABLE_OBJC_EXCEPTIONS = NO;
+                               GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
                                GCC_MODEL_TUNING = G5;
                                GCC_SYMBOLS_PRIVATE_EXTERN = YES;
                                GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES;
                                GCC_MODEL_TUNING = G5;
                                GCC_SYMBOLS_PRIVATE_EXTERN = YES;
                                GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES;
-                               GCC_WARN_PEDANTIC = YES;
-                               GCC_WARN_SHADOW = YES;
+                               GCC_WARN_PEDANTIC = NO;
+                               GCC_WARN_SHADOW = NO;
                                GCC_WARN_SIGN_COMPARE = YES;
                                GCC_WARN_UNINITIALIZED_AUTOS = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
                                GCC_WARN_SIGN_COMPARE = YES;
                                GCC_WARN_UNINITIALIZED_AUTOS = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
-                               INSTALL_PATH = /usr/local/lib;
-                               PREBINDING = NO;
+                               INSTALLHDRS_COPY_PHASE = YES;
+                               INSTALL_PATH = "$(INSTALL_LOCATION)/usr/local/lib";
                                PRODUCT_NAME = dsc;
                                ZERO_LINK = NO;
                        };
                                PRODUCT_NAME = dsc;
                                ZERO_LINK = NO;
                        };
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
+               F908135211D3ED9000626CC1 /* Build configuration list for PBXAggregateTarget "libdyld" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               F908134311D3ED0C00626CC1 /* Debug */,
+                               F908134411D3ED0C00626CC1 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
                F93937340A94FB2900070A07 /* Build configuration list for PBXNativeTarget "update_dyld_shared_cache" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                F93937340A94FB2900070A07 /* Build configuration list for PBXNativeTarget "update_dyld_shared_cache" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
+               F99B8E5D0FEC10F800701838 /* Build configuration list for PBXNativeTarget "dyld_shared_cache_util" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               F99B8E580FEC10F600701838 /* Debug */,
+                               F99B8E590FEC10F600701838 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               F9B0912A11F11D3400096D49 /* Build configuration list for PBXNativeTarget "libdsc_slider" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               F9B0912411F11D1700096D49 /* Debug */,
+                               F9B0912511F11D1700096D49 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
                F9D8C7DD087B087300E93EFB /* Build configuration list for PBXNativeTarget "dyld" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                F9D8C7DD087B087300E93EFB /* Build configuration list for PBXNativeTarget "dyld" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               F9D8C7E1087B087300E93EFB /* Build configuration list for PBXNativeTarget "libdyld" */ = {
+               F9D8C7E1087B087300E93EFB /* Build configuration list for PBXNativeTarget "libdyld.dylib" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                F9D8C7E2087B087300E93EFB /* Debug */,
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                F9D8C7E2087B087300E93EFB /* Debug */,
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               F9F2A56B0F7AEEB100B7C9EB /* Build configuration list for PBXNativeTarget "dsc" */ = {
+               F9F2A56B0F7AEEB100B7C9EB /* Build configuration list for PBXNativeTarget "libdsc" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                F9F2A55A0F7AEE9900B7C9EB /* Debug */,
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                F9F2A55A0F7AEE9900B7C9EB /* Debug */,
index 0f9828d00f567864d99a26c6f176aba5fd9f7cb4..3f579ef1ea3a968cdb887fe4e0c8c457db1ff4f2 100644 (file)
@@ -81,8 +81,9 @@ extern int32_t NSVersionOfLinkTimeLibrary(const char* libraryName)           __O
 
 /*
  * _NSGetExecutablePath() copies the path of the main executable into the buffer. The bufsize parameter
 
 /*
  * _NSGetExecutablePath() copies the path of the main executable into the buffer. The bufsize parameter
- * should initially be the size of the buffer.  The function returns 0 if the path was successfully copied.
- * It returns -1 if the buffer is not large enough, and *bufsize is set to the size required. 
+ * should initially be the size of the buffer.  The function returns 0 if the path was successfully copied,
+ * and *bufsize is left unchanged. It returns -1 if the buffer is not large enough, and *bufsize is set 
+ * to the size required. 
  * 
  * Note that _NSGetExecutablePath will return "a path" to the executable not a "real path" to the executable. 
  * That is the path may be a symbolic link and not the real file. With deep directories the total bufsize 
  * 
  * Note that _NSGetExecutablePath will return "a path" to the executable not a "real path" to the executable. 
  * That is the path may be a symbolic link and not the real file. With deep directories the total bufsize 
@@ -93,11 +94,9 @@ extern int _NSGetExecutablePath(char* buf, uint32_t* bufsize)                 __
 
 
 /*
 
 
 /*
- * _dyld_moninit() and _dyld_func_lookup() are private interface between 
- * dyld and libSystem.
-*/
+ * _dyld_moninit() is a private interface between dyld and libSystem.
+ */
 extern void _dyld_moninit(void (*monaddition)(char *lowpc, char *highpc))    __OSX_AVAILABLE_STARTING(__MAC_10_1, __IPHONE_2_0);
 extern void _dyld_moninit(void (*monaddition)(char *lowpc, char *highpc))    __OSX_AVAILABLE_STARTING(__MAC_10_1, __IPHONE_2_0);
-extern int _dyld_func_lookup(const char* dyld_func_name, void **address)     __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_6,__IPHONE_NA,__IPHONE_NA);
 
 
 
 
 
 
index 8423f2f97075cab2c6a375ed3be18382e7ad4124..ed710ef342d46892ff42e1a92c03b269a633d166 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2006-2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -24,6 +24,7 @@
 #define _DYLD_IMAGES_
 
 #include <stdbool.h>
 #define _DYLD_IMAGES_
 
 #include <stdbool.h>
+#include <unistd.h>
 #include <mach/mach.h>
 
 #ifdef __cplusplus
 #include <mach/mach.h>
 
 #ifdef __cplusplus
@@ -55,6 +56,11 @@ extern "C" {
  * be set to point to a C string message buffer containing the reason dyld terminate the process.
  * The low bit of the terminationFlags will be set if dyld terminated the process before any user
  * code ran, in which case there is no need for the crash log to contain the backtrace.
  * be set to point to a C string message buffer containing the reason dyld terminate the process.
  * The low bit of the terminationFlags will be set if dyld terminated the process before any user
  * code ran, in which case there is no need for the crash log to contain the backtrace.
+ *
+ * When dyld terminates a process because some required dylib or symbol cannot be bound, in 
+ * addition to the errorMessage field, it now sets the errorKind field and the corresponding
+ * fields: errorClientOfDylibPath, errorTargetDylibPath, errorSymbol.
+ *
  */
 
 enum dyld_image_mode { dyld_image_adding=0, dyld_image_removing=1 };
  */
 
 enum dyld_image_mode { dyld_image_adding=0, dyld_image_removing=1 };
@@ -67,8 +73,22 @@ struct dyld_image_info {
                                                                                                        /* then file has been modified since dyld loaded it */
 };
 
                                                                                                        /* then file has been modified since dyld loaded it */
 };
 
+struct dyld_uuid_info {
+       const struct mach_header*       imageLoadAddress;       /* base address image is mapped into */
+       uuid_t                                          imageUUID;                      /* UUID of image */
+};
+
 typedef void (*dyld_image_notifier)(enum dyld_image_mode mode, uint32_t infoCount, const struct dyld_image_info info[]);
 
 typedef void (*dyld_image_notifier)(enum dyld_image_mode mode, uint32_t infoCount, const struct dyld_image_info info[]);
 
+/* for use in dyld_all_image_infos.errorKind field */
+enum { dyld_error_kind_none=0, 
+               dyld_error_kind_dylib_missing=1, 
+               dyld_error_kind_dylib_wrong_arch=2,
+               dyld_error_kind_dylib_version=3,
+               dyld_error_kind_symbol_missing=4
+       };
+
+
 struct dyld_all_image_infos {
        uint32_t                                                version;                /* 1 in Mac OS X 10.4 and 10.5 */
        uint32_t                                                infoArrayCount;
 struct dyld_all_image_infos {
        uint32_t                                                version;                /* 1 in Mac OS X 10.4 and 10.5 */
        uint32_t                                                infoArrayCount;
@@ -78,20 +98,33 @@ struct dyld_all_image_infos {
        /* the following fields are only in version 2 (Mac OS X 10.6, iPhoneOS 2.0) and later */
        bool                                                    libSystemInitialized;
        const struct mach_header*               dyldImageLoadAddress;
        /* the following fields are only in version 2 (Mac OS X 10.6, iPhoneOS 2.0) and later */
        bool                                                    libSystemInitialized;
        const struct mach_header*               dyldImageLoadAddress;
-       /* the following field is only in version 3 (Mac OS X 10.6) and later */
+       /* the following field is only in version 3 (Mac OS X 10.6, iPhoneOS 3.0) and later */
        void*                                                   jitInfo;
        void*                                                   jitInfo;
-       /* the following fields are only in version 5 (Mac OS X 10.6) and later */
+       /* the following fields are only in version 5 (Mac OS X 10.6, iPhoneOS 3.0) and later */
        const char*                                             dyldVersion;
        const char*                                             errorMessage;
        uintptr_t                                               terminationFlags;
        const char*                                             dyldVersion;
        const char*                                             errorMessage;
        uintptr_t                                               terminationFlags;
-       /* the following field is only in version 6 (Mac OS X 10.6) and later */
+       /* the following field is only in version 6 (Mac OS X 10.6, iPhoneOS 3.1) and later */
        void*                                                   coreSymbolicationShmPage;
        void*                                                   coreSymbolicationShmPage;
-       /* the following field is only in version 7 (Mac OS X 10.6) and later */
+       /* the following field is only in version 7 (Mac OS X 10.6, iPhoneOS 3.1) and later */
        uintptr_t                                               systemOrderFlag;
        uintptr_t                                               systemOrderFlag;
+       /* the following field is only in version 8 (Mac OS X 10.7, iPhoneOS 3.1) and later */
+       uintptr_t                                               uuidArrayCount;
+       const struct dyld_uuid_info*    uuidArray;              /* only images not in dyld shared cache */
+       /* the following field is only in version 9 (Mac OS X 10.7, iOS 4.0) and later */
+       struct dyld_all_image_infos*    dyldAllImageInfosAddress;
+       /* the following field is only in version 10 (Mac OS X 10.7, iOS 4.2) and later */
+       uintptr_t                                               initialImageCount;
+       /* the following field is only in version 11 (Mac OS X 10.7, iOS 4.2) and later */
+       uintptr_t                                               errorKind;
+       const char*                                             errorClientOfDylibPath;
+       const char*                                             errorTargetDylibPath;
+       const char*                                             errorSymbol;
+       /* the following field is only in version 12 (Mac OS X 10.7, iOS 4.3) and later */
+       uintptr_t                                               sharedCacheSlide;
 };
 extern struct dyld_all_image_infos  dyld_all_image_infos;
 
 };
 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
 /*
  * 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
index 07ef16135dc382f0cafb4e6d3a7d0f215bb0334b..b33c23197c2ac77d5b905fa1a4312e8fe6341318 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2003-2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2003-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -24,7 +24,8 @@
 #ifndef _MACH_O_DYLD_PRIV_H_
 #define _MACH_O_DYLD_PRIV_H_
 
 #ifndef _MACH_O_DYLD_PRIV_H_
 #define _MACH_O_DYLD_PRIV_H_
 
-
+#include <stdbool.h>
+#include <Availability.h>
 #include <mach-o/dyld.h>
 #include <mach-o/dyld_images.h>
 
 #include <mach-o/dyld.h>
 #include <mach-o/dyld_images.h>
 
@@ -33,6 +34,24 @@ extern "C" {
 #endif /* __cplusplus */
 
 
 #endif /* __cplusplus */
 
 
+
+//
+// private interface between libSystem.dylib and dyld
+//
+extern int _dyld_func_lookup(const char* dyld_func_name, void **address);
+
+
+//
+// _dyld_moninit() is a private interface between libSystem.dylib and dyld
+//
+extern void _dyld_moninit(void (*monaddition)(char *lowpc, char *highpc));
+
+//
+// private interface between libSystem.dylib and dyld
+//
+extern void _dyld_fork_child();
+
+
 //
 // Possible state changes for which you can register to be notified
 //
 //
 // Possible state changes for which you can register to be notified
 //
@@ -68,6 +87,51 @@ extern void
 dyld_register_image_state_change_handler(enum dyld_image_states state, bool batch, dyld_image_state_change_handler handler);
 
 
 dyld_register_image_state_change_handler(enum dyld_image_states state, bool batch, dyld_image_state_change_handler handler);
 
 
+//
+// Possible thread-local variable state changes for which you can register to be notified
+//
+enum dyld_tlv_states {
+    dyld_tlv_state_allocated = 10,   // TLV range newly allocated
+    dyld_tlv_state_deallocated = 20  // TLV range about to be deallocated
+};
+
+// 
+// Info about thread-local variable storage.
+// 
+typedef struct {
+    size_t info_size;    // sizeof(dyld_tlv_info)
+    void * tlv_addr;     // Base address of TLV storage
+    size_t tlv_size;     // Byte size of TLV storage
+} dyld_tlv_info;
+
+#if __BLOCKS__
+
+// 
+// Callback that notes changes to thread-local variable storage.
+// 
+typedef void (^dyld_tlv_state_change_handler)(enum dyld_tlv_states state, const dyld_tlv_info *info);
+
+//
+// Register a handler to be called when a thread adds or removes storage for thread-local variables.
+// The registered handler will only be called from and on behalf of the thread that owns the storage.
+// The registered handler will NOT be called for any storage that was 
+//   already allocated before dyld_register_tlv_state_change_handler() was 
+//   called. Use dyld_enumerate_tlv_storage() to get that information.
+// Exists in Mac OS X 10.7 and later 
+// 
+extern void 
+dyld_register_tlv_state_change_handler(enum dyld_tlv_states state, dyld_tlv_state_change_handler handler);
+
+// 
+// Enumerate the current thread-local variable storage allocated for the current thread. 
+// Exists in Mac OS X 10.7 and later 
+//
+extern void 
+dyld_enumerate_tlv_storage(dyld_tlv_state_change_handler handler);
+
+#endif
+
+
 //
 // get slide for a given loaded mach_header  
 // Mac OS X 10.6 and later
 //
 // get slide for a given loaded mach_header  
 // Mac OS X 10.6 and later
@@ -114,7 +178,13 @@ extern const char* dyld_image_path_containing_address(const void* addr);
 
 
 
 
 
 
-
+#if __IPHONE_OS_VERSION_MIN_REQUIRED   
+//
+// Returns if any OS dylib has overridden its copy in the shared cache
+//
+// Exists in iPhoneOS 3.1 and later 
+extern bool dyld_shared_cache_some_image_overridden();
+#endif
 
 
 
 
 
 
index cb98ac3da49d2741e2751ef4a314e05db8ff43f0..c2e536c97c7a9aa415669314a888792923d302b3 100644 (file)
@@ -35,9 +35,6 @@ public:
        const char*             magic() const                                                   INLINE { return fields.magic; }
        void                    set_magic(const char* value)                    INLINE { memcpy(fields.magic, value, 16); }
 
        const char*             magic() const                                                   INLINE { return fields.magic; }
        void                    set_magic(const char* value)                    INLINE { memcpy(fields.magic, value, 16); }
 
-       //uint32_t              architecture() const                                    INLINE { return E::get32(fields.architecture); }
-       //void                  set_architecture(uint32_t value)                INLINE { E::set32(fields.architecture, value); }
-
        uint32_t                mappingOffset() const                                   INLINE { return E::get32(fields.mappingOffset); }
        void                    set_mappingOffset(uint32_t value)               INLINE { E::set32(fields.mappingOffset, value); }
 
        uint32_t                mappingOffset() const                                   INLINE { return E::get32(fields.mappingOffset); }
        void                    set_mappingOffset(uint32_t value)               INLINE { E::set32(fields.mappingOffset, value); }
 
@@ -53,11 +50,17 @@ public:
        uint64_t                dyldBaseAddress() const                                 INLINE { return E::get64(fields.dyldBaseAddress); }
        void                    set_dyldBaseAddress(uint64_t value)             INLINE { E::set64(fields.dyldBaseAddress, value); }
 
        uint64_t                dyldBaseAddress() const                                 INLINE { return E::get64(fields.dyldBaseAddress); }
        void                    set_dyldBaseAddress(uint64_t value)             INLINE { E::set64(fields.dyldBaseAddress, value); }
 
-       //uint32_t              dependenciesOffset() const                              INLINE { return E::get32(fields.dependenciesOffset); }
-       //void                  set_dependenciesOffset(uint32_t value)  INLINE { E::set32(fields.dependenciesOffset, value); }
+       uint64_t                codeSignatureOffset() const                             INLINE { return E::get64(fields.codeSignatureOffset); }
+       void                    set_codeSignatureOffset(uint64_t value) INLINE { E::set64(fields.codeSignatureOffset, value); }
+
+       uint64_t                codeSignatureSize() const                               INLINE { return E::get64(fields.codeSignatureSize); }
+       void                    set_codeSignatureSize(uint64_t value)   INLINE { E::set64(fields.codeSignatureSize, value); }
+
+       uint64_t                slideInfoOffset() const                                 INLINE { return E::get64(fields.slideInfoOffset); }
+       void                    set_slideInfoOffset(uint64_t value)             INLINE { E::set64(fields.slideInfoOffset, value); }
 
 
-       //uint32_t              dependenciesCount() const                               INLINE { return E::get32(fields.dependenciesCount); }
-       //void                  set_dependenciesCount(uint32_t value)   INLINE { E::set32(fields.dependenciesCount, value); }
+       uint64_t                slideInfoSize() const                                   INLINE { return E::get64(fields.slideInfoSize); }
+       void                    set_slideInfoSize(uint64_t value)               INLINE { E::set64(fields.slideInfoSize, value); }
 
 private:
        dyld_cache_header                       fields;
 
 private:
        dyld_cache_header                       fields;
@@ -67,23 +70,23 @@ private:
 template <typename E>
 class dyldCacheFileMapping {
 public:                
 template <typename E>
 class dyldCacheFileMapping {
 public:                
-       uint64_t                address() const                                                         INLINE { return E::get64(fields.sfm_address); }
-       void                    set_address(uint64_t value)                                     INLINE { E::set64(fields.sfm_address, value); }
+       uint64_t                address() const                                                         INLINE { return E::get64(fields.address); }
+       void                    set_address(uint64_t value)                                     INLINE { E::set64(fields.address, value); }
 
 
-       uint64_t                size() const                                                            INLINE { return E::get64(fields.sfm_size); }
-       void                    set_size(uint64_t value)                                        INLINE { E::set64(fields.sfm_size, value); }
+       uint64_t                size() const                                                            INLINE { return E::get64(fields.size); }
+       void                    set_size(uint64_t value)                                        INLINE { E::set64(fields.size, value); }
 
 
-       uint64_t                file_offset() const                                                     INLINE { return E::get64(fields.sfm_file_offset); }
-       void                    set_file_offset(uint64_t value)                         INLINE { E::set64(fields.sfm_file_offset, value); }
+       uint64_t                file_offset() const                                                     INLINE { return E::get64(fields.fileOffset); }
+       void                    set_file_offset(uint64_t value)                         INLINE { E::set64(fields.fileOffset, value); }
 
 
-       uint32_t                max_prot() const                                                        INLINE { return E::get32(fields.sfm_max_prot); }
-       void                    set_max_prot(uint32_t value)                            INLINE { E::set32((uint32_t&)fields.sfm_max_prot, value); }
+       uint32_t                max_prot() const                                                        INLINE { return E::get32(fields.maxProt); }
+       void                    set_max_prot(uint32_t value)                            INLINE { E::set32((uint32_t&)fields.maxProt, value); }
 
 
-       uint32_t                init_prot() const                                                       INLINE { return E::get32(fields.sfm_init_prot); }
-       void                    set_init_prot(uint32_t value)                           INLINE { E::set32((uint32_t&)fields.sfm_init_prot, value); }
+       uint32_t                init_prot() const                                                       INLINE { return E::get32(fields.initProt); }
+       void                    set_init_prot(uint32_t value)                           INLINE { E::set32((uint32_t&)fields.initProt, value); }
 
 private:
 
 private:
-       shared_file_mapping_np                  fields;
+       dyld_cache_mapping_info                 fields;
 };
 
 
 };
 
 
@@ -102,13 +105,43 @@ public:
        uint32_t                pathFileOffset() const                                          INLINE { return E::get32(fields.pathFileOffset); }
        void                    set_pathFileOffset(uint32_t value)                      INLINE { E::set32(fields.pathFileOffset, value); fields.pad=0; }
 
        uint32_t                pathFileOffset() const                                          INLINE { return E::get32(fields.pathFileOffset); }
        void                    set_pathFileOffset(uint32_t value)                      INLINE { E::set32(fields.pathFileOffset, value); fields.pad=0; }
 
-       //uint32_t              dependenciesStartOffset() const                         INLINE { return E::get32(fields.dependenciesStartOffset); }
-       //void                  set_dependenciesStartOffset(uint32_t value)     INLINE { E::set32(fields.dependenciesStartOffset, value); }
-
 private:
        dyld_cache_image_info                   fields;
 };
 
 private:
        dyld_cache_image_info                   fields;
 };
 
+template <typename E>
+class dyldCacheSlideInfo {
+public:                
+       uint32_t                version() const                                                         INLINE { return E::get32(fields.version); }
+       void                    set_version(uint32_t value)                                     INLINE { E::set32(fields.version, value); }
+
+       uint32_t                toc_offset() const                                                      INLINE { return E::get32(fields.toc_offset); }
+       void                    set_toc_offset(uint32_t value)                          INLINE { E::set32(fields.toc_offset, value); }
+
+       uint32_t                toc_count() const                                                       INLINE { return E::get32(fields.toc_count); }
+       void                    set_toc_count(uint32_t value)                           INLINE { E::set32(fields.toc_count, value); }
+
+       uint32_t                entries_offset() const                                          INLINE { return E::get32(fields.entries_offset); }
+       void                    set_entries_offset(uint32_t value)                      INLINE { E::set32(fields.entries_offset, value); }
+       
+       uint32_t                entries_count() const                                           INLINE { return E::get32(fields.entries_count); }
+       void                    set_entries_count(uint32_t value)                       INLINE { E::set32(fields.entries_count, value); }
+
+       uint32_t                entries_size() const                                            INLINE { return E::get32(fields.entries_size); }
+       void                    set_entries_size(uint32_t value)                        INLINE { E::set32(fields.entries_size, value); }
+
+       uint16_t                toc(unsigned index) const                                       INLINE { return E::get16(((uint16_t*)(((uint8_t*)this)+E::get16(fields.toc_offset)))[index]); }
+       void                    set_toc(unsigned index, uint16_t value)         INLINE { return E::set16(((uint16_t*)(((uint8_t*)this)+E::get16(fields.toc_offset)))[index], value); }
+
+private:
+       dyld_cache_slide_info                   fields;
+};
+
+
+struct dyldCacheSlideInfoEntry {
+       uint8_t  bits[4096/(8*4)]; // 128-byte bitmap
+};
+
 
 
 #endif // __DYLD_CACHE_ABSTRACTION__
 
 
 #endif // __DYLD_CACHE_ABSTRACTION__
index 8d75311c16d56e01b400c1dffb10a1759cc1f3f4..8786e6adda91d54f49bb0376f52cf93e04347153 100644 (file)
@@ -128,6 +128,12 @@ public:
        
        static uint64_t getP(const uint_t& from)                                INLINE { return _E::get32(from); }
        static void             setP(uint_t& into, uint64_t value)              INLINE { _E::set32(into, value); }
        
        static uint64_t getP(const uint_t& from)                                INLINE { return _E::get32(from); }
        static void             setP(uint_t& into, uint64_t value)              INLINE { _E::set32(into, value); }
+
+    // Round to a P-size boundary
+    template <typename T>
+    static T round_up(T value) { return (value+3) & ~(T)3; }
+    template <typename T>
+    static T round_down(T value) { return value & ~(T)3; }
 };
 
 
 };
 
 
@@ -140,6 +146,12 @@ public:
        
        static uint64_t getP(const uint_t& from)                                INLINE { return _E::get64(from); }
        static void             setP(uint_t& into, uint64_t value)              INLINE { _E::set64(into, value); }
        
        static uint64_t getP(const uint_t& from)                                INLINE { return _E::get64(from); }
        static void             setP(uint_t& into, uint64_t value)              INLINE { _E::set64(into, value); }
+
+    // Round to a P-size boundary
+    template <typename T>
+    static T round_up(T value) { return (value+7) & ~(T)7; }
+    template <typename T>
+    static T round_down(T value) { return value & ~(T)7; }
 };
 
 
 };
 
 
index 5b99dbf7827eeb368d14d809640c57cf9346b8ea..ac882dc357d4a21dacbb5c55a25dd961a5345988 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
- * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2006-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -40,6 +40,8 @@
 
 #include <vector>
 #include <set>
 
 #include <vector>
 #include <set>
+#include <ext/hash_map>
+#include <ext/hash_set>
 
 #include "MachOFileAbstraction.hpp"
 #include "Architectures.hpp"
 
 #include "MachOFileAbstraction.hpp"
 #include "Architectures.hpp"
@@ -47,6 +49,9 @@
 #include "MachORebaser.hpp"
 #include "MachOTrie.hpp"
 
 #include "MachORebaser.hpp"
 #include "MachOTrie.hpp"
 
+#ifndef EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
+       #define EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER 0x10
+#endif
 
 
 
 
 
 
@@ -65,33 +70,52 @@ public:
        
        const char*                                                                     getDylibID() const;
        void                                                                            setDependentBinders(const Map& map);
        
        const char*                                                                     getDylibID() const;
        void                                                                            setDependentBinders(const Map& map);
-       void                                                                            bind();
-
+       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; };
 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_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;
+    struct ClientAndSymbol { Binder<A>* client; const char* symbolName; };
+    struct SymbolAndLazyPointer { const char* symbolName; pint_t lpVMAddr; };
        
        
+       static bool                                                                     isPublicLocation(const char* pth);
        void                                                                            doBindExternalRelocations();
        void                                                                            doBindIndirectSymbols();
        void                                                                            doSetUpDyldSection();
        void                                                                            doSetPreboundUndefines();
        void                                                                            doBindExternalRelocations();
        void                                                                            doBindIndirectSymbols();
        void                                                                            doSetUpDyldSection();
        void                                                                            doSetPreboundUndefines();
-       void                                                                            doBindDyldInfo();
-       void                                                                            doBindDyldLazyInfo();
+       void                                                                            hoistPrivateRexports();
+       int                                                                                     ordinalOfDependentBinder(Binder<A>* dep);
+       void                                                                            doBindDyldInfo(std::vector<void*>& pointersInData);
+       void                                                                            doBindDyldLazyInfo(std::vector<void*>& pointersInData);
        void                                                                            bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uint8_t type, 
        void                                                                            bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uint8_t type, 
-                                                                                                                               int libraryOrdinal, int64_t addend, const char* symbolName);
+                                                                                                                               int libraryOrdinal, int64_t addend, 
+                                                                                                                               const char* symbolName, bool lazyPointer,
+                                                                                                                               std::vector<void*>& pointersInData);
        pint_t                                                                          resolveUndefined(const macho_nlist<P>* undefinedSymbol);
        pint_t                                                                          resolveUndefined(const macho_nlist<P>* undefinedSymbol);
-       bool                                                                            findExportedSymbolAddress(const char* name, pint_t* result);
+       bool                                                                            findExportedSymbolAddress(const char* name, pint_t* result, Binder<A>** foundIn, bool* isResolverSymbol);
        void                                                                            bindStub(uint8_t elementSize, uint8_t* location, pint_t vmlocation, pint_t value);
        const char*                                                                     parentUmbrella();
        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);
+    void                                        optimizeStub(const char* symbolName, pint_t lpVMAddr);
+    void                                        optimizeStub(uint8_t* stubMappedAddress, pint_t stubVMAddress, uint32_t stubSize, pint_t lpVMAddr);
+    pint_t                                      findLazyPointerFor(const char* symbolName);
+
 
        static uint8_t                                                          pointerRelocSize();
        static uint8_t                                                          pointerRelocType();
        
        std::vector<BinderAndReExportFlag>                      fDependentDylibs;
        NameToAddrMap                                                           fHashTable;
 
        static uint8_t                                                          pointerRelocSize();
        static uint8_t                                                          pointerRelocType();
        
        std::vector<BinderAndReExportFlag>                      fDependentDylibs;
        NameToAddrMap                                                           fHashTable;
+       NameSet                                                                         fSymbolResolvers;
+       std::vector<SymbolReExport>                                     fReExportedSymbols;
        uint64_t                                                                        fDyldBaseAddress;
        const macho_nlist<P>*                                           fSymbolTable;
        const char*                                                                     fStrings;
        uint64_t                                                                        fDyldBaseAddress;
        const macho_nlist<P>*                                           fSymbolTable;
        const char*                                                                     fStrings;
@@ -101,15 +125,33 @@ private:
        const macho_dylib_command<P>*                           fParentUmbrella;
        const macho_dyld_info_command<P>*                       fDyldInfo;
        bool                                                                            fOriginallyPrebound;
        const macho_dylib_command<P>*                           fParentUmbrella;
        const macho_dyld_info_command<P>*                       fDyldInfo;
        bool                                                                            fOriginallyPrebound;
+       bool                                                                            fReExportedSymbolsResolved;
+    std::vector<ClientAndSymbol>                fClientAndSymbols;
+    std::vector<SymbolAndLazyPointer>           fSymbolAndLazyPointers;
 };
 
 };
 
+template <> 
+uint32_t Binder<arm>::runtimeAddressFromNList(const macho_nlist<Pointer32<LittleEndian> >* sym) 
+{ 
+       if (sym->n_desc() & N_ARM_THUMB_DEF)
+               return sym->n_value() + 1; 
+       else
+               return sym->n_value(); 
+}
+
+template <typename A> 
+typename A::P::uint_t  Binder<A>::runtimeAddressFromNList(const macho_nlist<P>* sym) 
+{ 
+       return sym->n_value(); 
+}
+
 
 template <typename A>
 Binder<A>::Binder(const MachOLayoutAbstraction& layout, uint64_t dyldBaseAddress)
        : Rebaser<A>(layout), fDyldBaseAddress(dyldBaseAddress),
          fSymbolTable(NULL), fStrings(NULL), fDynamicInfo(NULL),
          fFristWritableSegment(NULL), fDylibID(NULL), fDyldInfo(NULL),
 
 template <typename A>
 Binder<A>::Binder(const MachOLayoutAbstraction& layout, uint64_t dyldBaseAddress)
        : Rebaser<A>(layout), fDyldBaseAddress(dyldBaseAddress),
          fSymbolTable(NULL), fStrings(NULL), fDynamicInfo(NULL),
          fFristWritableSegment(NULL), fDylibID(NULL), fDyldInfo(NULL),
-         fParentUmbrella(NULL)
+         fParentUmbrella(NULL), fReExportedSymbolsResolved(false)
 {
        fOriginallyPrebound = ((this->fHeader->flags() & MH_PREBOUND) != 0);
        // update header flags so the cache looks prebound split-seg (0x80000000 is in-shared-cache bit)
 {
        fOriginallyPrebound = ((this->fHeader->flags() & MH_PREBOUND) != 0);
        // update header flags so the cache looks prebound split-seg (0x80000000 is in-shared-cache bit)
@@ -137,6 +179,7 @@ Binder<A>::Binder(const MachOLayoutAbstraction& layout, uint64_t dyldBaseAddress
                        case LC_LOAD_DYLIB:
                        case LC_LOAD_WEAK_DYLIB:
                        case LC_REEXPORT_DYLIB:
                        case LC_LOAD_DYLIB:
                        case LC_LOAD_WEAK_DYLIB:
                        case LC_REEXPORT_DYLIB:
+                       case LC_LOAD_UPWARD_DYLIB:
                                ((macho_dylib_command<P>*)cmd)->set_timestamp(0);
                                break;
                        case LC_SUB_FRAMEWORK:
                                ((macho_dylib_command<P>*)cmd)->set_timestamp(0);
                                break;
                        case LC_SUB_FRAMEWORK:
@@ -163,12 +206,33 @@ Binder<A>::Binder(const MachOLayoutAbstraction& layout, uint64_t dyldBaseAddress
 //     fprintf(stderr, "exports for %s\n", layout.getFilePath());
        if ( fDyldInfo != NULL ) {
                std::vector<mach_o::trie::Entry> exports;
 //     fprintf(stderr, "exports for %s\n", layout.getFilePath());
        if ( fDyldInfo != NULL ) {
                std::vector<mach_o::trie::Entry> exports;
-               const uint8_t* exportsStart = &this->fLinkEditBase[fDyldInfo->export_off()];
+               const uint8_t* exportsStart = layout.getDyldInfoExports(); 
                const uint8_t* exportsEnd = &exportsStart[fDyldInfo->export_size()];
                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) {
                const uint8_t* exportsEnd = &exportsStart[fDyldInfo->export_size()];
                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) {
-                       fHashTable[it->name] = it->address + baseAddress;
+                       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 {
+                                       fHashTable[it->name] = it->address + baseAddress;
+                               }
+                       }
+                       else {
+                               throwf("non-regular symbol binding not supported for %s in %s", it->name, layout.getFilePath());
+                       }
                        //fprintf(stderr, "0x%08llX %s\n", it->address + baseAddress, it->name);
                }
        }
                        //fprintf(stderr, "0x%08llX %s\n", it->address + baseAddress, it->name);
                }
        }
@@ -179,7 +243,7 @@ Binder<A>::Binder(const MachOLayoutAbstraction& layout, uint64_t dyldBaseAddress
                        fHashTable.resize(fDynamicInfo->nextdefsym()); // set initial bucket count
                        for (const macho_nlist<P>* sym=start; sym < end; ++sym) {
                                const char* name = &fStrings[sym->n_strx()];
                        fHashTable.resize(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] = sym->n_value();
+                               fHashTable[name] = runtimeAddressFromNList(sym);
                                //fprintf(stderr, " 0x%08llX %s\n", sym->n_value(), name);
                        }
                }
                                //fprintf(stderr, " 0x%08llX %s\n", sym->n_value(), name);
                        }
                }
@@ -191,7 +255,7 @@ Binder<A>::Binder(const MachOLayoutAbstraction& layout, uint64_t dyldBaseAddress
                                const uint32_t index = E::get32(toc[i].symbol_index);
                                const macho_nlist<P>* sym = &fSymbolTable[index];
                                const char* name = &fStrings[sym->n_strx()];
                                const uint32_t index = E::get32(toc[i].symbol_index);
                                const macho_nlist<P>* sym = &fSymbolTable[index];
                                const char* name = &fStrings[sym->n_strx()];
-                               fHashTable[name] = sym->n_value();
+                               fHashTable[name] = runtimeAddressFromNList(sym);
                                //fprintf(stderr, "- 0x%08llX %s\n", sym->n_value(), name);
                        }
                }
                                //fprintf(stderr, "- 0x%08llX %s\n", sym->n_value(), name);
                        }
                }
@@ -228,6 +292,30 @@ const char* Binder<A>::parentUmbrella()
 }
 
 
 }
 
 
+template <typename A>
+bool Binder<A>::isPublicLocation(const char* pth)
+{
+       // /usr/lib is a public location
+       if ( (strncmp(pth, "/usr/lib/", 9) == 0) && (strchr(&pth[9], '/') == NULL) )
+               return true;
+
+       // /System/Library/Frameworks/ is a public location
+       if ( strncmp(pth, "/System/Library/Frameworks/", 27) == 0 ) {
+               const char* frameworkDot = strchr(&pth[27], '.');
+               // but only top level framework
+               // /System/Library/Frameworks/Foo.framework/Versions/A/Foo                 ==> true
+               // /System/Library/Frameworks/Foo.framework/Resources/libBar.dylib         ==> false
+               // /System/Library/Frameworks/Foo.framework/Frameworks/Bar.framework/Bar   ==> false
+               // /System/Library/Frameworks/Foo.framework/Frameworks/Xfoo.framework/XFoo ==> false
+               if ( frameworkDot != NULL ) {
+                       int frameworkNameLen = frameworkDot - &pth[27];
+                       if ( strncmp(&pth[strlen(pth)-frameworkNameLen-1], &pth[26], frameworkNameLen+1) == 0 )
+                               return true;
+               }
+       }
+               
+       return false;
+}
 
 template <typename A>
 void Binder<A>::setDependentBinders(const Map& map)
 
 template <typename A>
 void Binder<A>::setDependentBinders(const Map& map)
@@ -241,6 +329,7 @@ void Binder<A>::setDependentBinders(const Map& map)
                        case LC_LOAD_DYLIB:
                        case LC_LOAD_WEAK_DYLIB:
                        case LC_REEXPORT_DYLIB:
                        case LC_LOAD_DYLIB:
                        case LC_LOAD_WEAK_DYLIB:
                        case LC_REEXPORT_DYLIB:
+                       case LC_LOAD_UPWARD_DYLIB:
                                const char* path = ((struct macho_dylib_command<P>*)cmd)->name();
                                typename Map::const_iterator pos = map.find(path);
                                if ( pos != map.end() ) {
                                const char* path = ((struct macho_dylib_command<P>*)cmd)->name();
                                typename Map::const_iterator pos = map.find(path);
                                if ( pos != map.end() ) {
@@ -334,15 +423,77 @@ void Binder<A>::setDependentBinders(const Map& map)
                        }       
                }
        }
                        }       
                }
        }
+       
+}
+
+template <typename A>
+int Binder<A>::ordinalOfDependentBinder(Binder<A>* dep)
+{
+       for (int i=0; i < fDependentDylibs.size(); ++i) {
+               if ( fDependentDylibs[i].binder == dep ) 
+                       return i+1;
+       }
+       throw "dependend dylib not found";
+}
+
+template <typename A>
+void Binder<A>::hoistPrivateRexports()
+{
+       std::vector<Binder<A>*> privateReExportedDylibs;
+       for (typename std::vector<BinderAndReExportFlag>::iterator it = fDependentDylibs.begin(); it != fDependentDylibs.end(); ++it) {
+               if ( it->reExport && ! isPublicLocation(it->binder->getDylibID()) )
+                       privateReExportedDylibs.push_back(it->binder);
+       }
+       if ( privateReExportedDylibs.size() != 0 ) {
+               // parse export info into vector of exports
+               const uint8_t* exportsStart = this->fLayout.getDyldInfoExports(); 
+               const uint8_t* exportsEnd = &exportsStart[fDyldInfo->export_size()];
+               std::vector<mach_o::trie::Entry> exports;
+               mach_o::trie::parseTrie(exportsStart, exportsEnd, exports);
+               //fprintf(stderr, "%s exports %lu symbols from trie of size %u \n", this->fLayout.getFilePath(), exports.size(), fDyldInfo->export_size());
+
+               // add re-exports for each export from an re-exported dylib
+               for(typename std::vector<Binder<A>*>::iterator it = privateReExportedDylibs.begin(); it != privateReExportedDylibs.end(); ++it) {
+                       Binder<A>* binder = *it;
+                       int ordinal = ordinalOfDependentBinder(binder);
+                       const uint8_t* aDylibsExportsStart = binder->fLayout.getDyldInfoExports(); 
+                       const uint8_t* aDylibsExportsEnd = &aDylibsExportsStart[binder->fDyldInfo->export_size()];
+                       std::vector<mach_o::trie::Entry> aDylibsExports;
+                       mach_o::trie::parseTrie(aDylibsExportsStart, aDylibsExportsEnd, aDylibsExports);
+                       //fprintf(stderr, "%s re-exports %lu symbols from %s\n", this->fLayout.getFilePath(), aDylibsExports.size(), binder->getDylibID());
+                       for(std::vector<mach_o::trie::Entry>::iterator eit = aDylibsExports.begin(); eit != aDylibsExports.end(); ++eit) {
+                               mach_o::trie::Entry entry = *eit;
+                               entry.flags |= EXPORT_SYMBOL_FLAGS_REEXPORT;
+                               entry.other = ordinal;
+                               entry.importName = NULL;
+                               exports.push_back(entry);
+                       }
+               }
+               // rebuild new combined trie
+               std::vector<uint8_t> newExportTrieBytes;
+               newExportTrieBytes.reserve(fDyldInfo->export_size());
+               mach_o::trie::makeTrie(exports, newExportTrieBytes);
+               //fprintf(stderr, "%s now exports %lu symbols from trie of size %lu\n", this->fLayout.getFilePath(), exports.size(), newExportTrieBytes.size());
+
+               // allocate new buffer and set export_off to use new buffer instead
+               uint32_t newExportsSize = newExportTrieBytes.size();
+               uint8_t* sideTrie = new uint8_t[newExportsSize];
+               memcpy(sideTrie, &newExportTrieBytes[0], newExportsSize);
+               this->fLayout.setDyldInfoExports(sideTrie);
+               ((macho_dyld_info_command<P>*)fDyldInfo)->set_export_off(0); // invalidate old trie
+               ((macho_dyld_info_command<P>*)fDyldInfo)->set_export_size(newExportsSize);
+       }
 }
 
 }
 
+
 template <typename A>
 template <typename A>
-void Binder<A>::bind()
+void Binder<A>::bind(std::vector<void*>& pointersInData)
 {
        this->doSetUpDyldSection();
        if ( fDyldInfo != NULL ) {
 {
        this->doSetUpDyldSection();
        if ( fDyldInfo != NULL ) {
-               this->doBindDyldInfo();
-               this->doBindDyldLazyInfo();
+               this->doBindDyldInfo(pointersInData);
+               this->doBindDyldLazyInfo(pointersInData);
+               this->hoistPrivateRexports();
                // weak bind info is processed at launch time
        }
        else {
                // weak bind info is processed at launch time
        }
        else {
@@ -382,7 +533,8 @@ void Binder<A>::doSetUpDyldSection()
 }
 
 template <typename A>
 }
 
 template <typename A>
-void Binder<A>::bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uint8_t type, int libraryOrdinal, int64_t addend, const char* symbolName)
+void Binder<A>::bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uint8_t type, int libraryOrdinal, 
+                                                       int64_t addend, const char* symbolName, bool lazyPointer, std::vector<void*>& pointersInData)
 {
        //printf("%d 0x%08llX type=%d, lib=%d, addend=%lld, symbol=%s\n", segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName);
        const std::vector<MachOLayoutAbstraction::Segment>& segments = this->fLayout.getSegments();
 {
        //printf("%d 0x%08llX type=%d, lib=%d, addend=%lld, symbol=%s\n", segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName);
        const std::vector<MachOLayoutAbstraction::Segment>& segments = this->fLayout.getSegments();
@@ -390,7 +542,7 @@ void Binder<A>::bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uin
                throw "bad segment index in rebase info";
                
        if ( libraryOrdinal == BIND_SPECIAL_DYLIB_FLAT_LOOKUP ) 
                throw "bad segment index in rebase info";
                
        if ( libraryOrdinal == BIND_SPECIAL_DYLIB_FLAT_LOOKUP ) 
-               throw "flat_namespace linkage not allowed in dyld shared cache";
+               throw "dynamic lookup linkage not allowed in dyld shared cache";
        
        if ( libraryOrdinal == BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE ) 
                throw "linkage to main executable not allowed in dyld shared cache";
        
        if ( libraryOrdinal == BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE ) 
                throw "linkage to main executable not allowed in dyld shared cache";
@@ -407,8 +559,26 @@ void Binder<A>::bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uin
        else
                binder = fDependentDylibs[libraryOrdinal-1].binder;
        pint_t targetSymbolAddress;
        else
                binder = fDependentDylibs[libraryOrdinal-1].binder;
        pint_t targetSymbolAddress;
-       if ( ! binder->findExportedSymbolAddress(symbolName, &targetSymbolAddress) ) 
-               throwf("could not resolve %s expected in %s", symbolName, binder->getDylibID());
+       bool isResolverSymbol;
+    Binder<A>* foundIn;
+       if ( ! binder->findExportedSymbolAddress(symbolName, &targetSymbolAddress, &foundIn, &isResolverSymbol) ) 
+               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
+            foundIn->addResolverClient(this, symbolName);
+           // fprintf(stderr, "have lazy pointer to resolver %s in %s\n", symbolName, this->getDylibID());
+        }
+               return;
+    }
 
        // do actual update
        const MachOLayoutAbstraction::Segment& seg = segments[segmentIndex];
 
        // do actual update
        const MachOLayoutAbstraction::Segment& seg = segments[segmentIndex];
@@ -433,12 +603,13 @@ void Binder<A>::bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uin
                default:
                        throw "bad bind type";
        }
                default:
                        throw "bad bind type";
        }
+       pointersInData.push_back(mappedAddr);
 }
 
 
 
 template <typename A>
 }
 
 
 
 template <typename A>
-void Binder<A>::doBindDyldLazyInfo()
+void Binder<A>::doBindDyldLazyInfo(std::vector<void*>& pointersInData)
 {
        const uint8_t* p = &this->fLinkEditBase[fDyldInfo->lazy_bind_off()];
        const uint8_t* end = &p[fDyldInfo->lazy_bind_size()];
 {
        const uint8_t* p = &this->fLinkEditBase[fDyldInfo->lazy_bind_off()];
        const uint8_t* end = &p[fDyldInfo->lazy_bind_size()];
@@ -486,7 +657,7 @@ void Binder<A>::doBindDyldLazyInfo()
                                segmentOffset = read_uleb128(p, end);
                                break;
                        case BIND_OPCODE_DO_BIND:
                                segmentOffset = read_uleb128(p, end);
                                break;
                        case BIND_OPCODE_DO_BIND:
-                               bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName);
+                               bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, true, pointersInData);
                                segmentOffset += sizeof(pint_t);
                                break;
                        case BIND_OPCODE_SET_TYPE_IMM:
                                segmentOffset += sizeof(pint_t);
                                break;
                        case BIND_OPCODE_SET_TYPE_IMM:
@@ -503,7 +674,7 @@ void Binder<A>::doBindDyldLazyInfo()
 }
 
 template <typename A>
 }
 
 template <typename A>
-void Binder<A>::doBindDyldInfo()
+void Binder<A>::doBindDyldInfo(std::vector<void*>& pointersInData)
 {
        const uint8_t* p = &this->fLinkEditBase[fDyldInfo->bind_off()];
        const uint8_t* end = &p[fDyldInfo->bind_size()];
 {
        const uint8_t* p = &this->fLinkEditBase[fDyldInfo->bind_off()];
        const uint8_t* end = &p[fDyldInfo->bind_size()];
@@ -560,22 +731,22 @@ void Binder<A>::doBindDyldInfo()
                                segmentOffset += read_uleb128(p, end);
                                break;
                        case BIND_OPCODE_DO_BIND:
                                segmentOffset += read_uleb128(p, end);
                                break;
                        case BIND_OPCODE_DO_BIND:
-                               bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName);
+                               bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, false, pointersInData);
                                segmentOffset += sizeof(pint_t);
                                break;
                        case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
                                segmentOffset += sizeof(pint_t);
                                break;
                        case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
-                               bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName);
+                               bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, false, pointersInData);
                                segmentOffset += read_uleb128(p, end) + sizeof(pint_t);
                                break;
                        case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
                                segmentOffset += read_uleb128(p, end) + sizeof(pint_t);
                                break;
                        case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
-                               bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName);
+                               bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, false, pointersInData);
                                segmentOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
                                break;
                        case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
                                count = read_uleb128(p, end);
                                skip = read_uleb128(p, end);
                                for (uint32_t i=0; i < count; ++i) {
                                segmentOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
                                break;
                        case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
                                count = read_uleb128(p, end);
                                skip = read_uleb128(p, end);
                                for (uint32_t i=0; i < count; ++i) {
-                                       bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName);
+                                       bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, false, pointersInData);
                                        segmentOffset += skip + sizeof(pint_t);
                                }
                                break;
                                        segmentOffset += skip + sizeof(pint_t);
                                }
                                break;
@@ -657,7 +828,7 @@ void Binder<A>::doBindExternalRelocations()
                const macho_nlist<P>* undefinedSymbol = &fSymbolTable[reloc->r_symbolnum()];
                pint_t* location;
                try {
                const macho_nlist<P>* undefinedSymbol = &fSymbolTable[reloc->r_symbolnum()];
                pint_t* location;
                try {
-                       location = mappedAddressForNewAddress(reloc->r_address() + firstWritableSegmentBaseAddress);
+                       location = this->mappedAddressForNewAddress(reloc->r_address() + firstWritableSegmentBaseAddress);
                }
                catch (const char* msg) {
                        throwf("%s processesing external relocation r_address 0x%08X", msg, reloc->r_address());
                }
                catch (const char* msg) {
                        throwf("%s processesing external relocation r_address 0x%08X", msg, reloc->r_address());
@@ -774,11 +945,11 @@ typename A::P::uint_t Binder<A>::resolveUndefined(const macho_nlist<P>* undefine
        if ( (undefinedSymbol->n_type() & N_TYPE) == N_SECT ) {
                if ( (undefinedSymbol->n_type() & N_PEXT) != 0 ) {
                        // is a multi-module private_extern internal reference that the linker did not optimize away
        if ( (undefinedSymbol->n_type() & N_TYPE) == N_SECT ) {
                if ( (undefinedSymbol->n_type() & N_PEXT) != 0 ) {
                        // is a multi-module private_extern internal reference that the linker did not optimize away
-                       return undefinedSymbol->n_value();
+                       return runtimeAddressFromNList(undefinedSymbol);
                }
                if ( (undefinedSymbol->n_desc() & N_WEAK_DEF) != 0 ) {
                        // is a weak definition, we should prebind to this one in the same linkage unit
                }
                if ( (undefinedSymbol->n_desc() & N_WEAK_DEF) != 0 ) {
                        // is a weak definition, we should prebind to this one in the same linkage unit
-                       return undefinedSymbol->n_value();
+                       return runtimeAddressFromNList(undefinedSymbol);
                }
        }
        const char* symbolName = &fStrings[undefinedSymbol->n_strx()];
                }
        }
        const char* symbolName = &fStrings[undefinedSymbol->n_strx()];
@@ -802,26 +973,62 @@ typename A::P::uint_t Binder<A>::resolveUndefined(const macho_nlist<P>* undefine
                                binder = fDependentDylibs[ordinal-1].binder;
                }       
                pint_t addr;
                                binder = fDependentDylibs[ordinal-1].binder;
                }       
                pint_t addr;
-               if ( ! binder->findExportedSymbolAddress(symbolName, &addr) )
-                       throwf("could not resolve %s expected in %s", symbolName, binder->getDylibID());
+               bool isResolver;
+        Binder<A>* foundIn;
+               if ( ! binder->findExportedSymbolAddress(symbolName, &addr, &foundIn, &isResolver) )
+                       throwf("could not resolve undefined symbol %s in %s expected in %s", symbolName, this->getDylibID(), binder->getDylibID());
                return addr;
        }
 }
 
 template <typename A>
                return addr;
        }
 }
 
 template <typename A>
-bool Binder<A>::findExportedSymbolAddress(const char* name, pint_t* result)
+bool Binder<A>::findExportedSymbolAddress(const char* name, pint_t* result, Binder<A>** foundIn, bool* isResolverSymbol)
 {
 {
+    *foundIn = NULL;
+       // since re-export chains can be any length, re-exports cannot be resolved in setDependencies()
+       // instead we lazily, recursively update 
+       if ( !fReExportedSymbolsResolved ) {
+               
+               // update fHashTable with any individual symbol re-exports
+               for (typename std::vector<SymbolReExport>::iterator it=fReExportedSymbols.begin(); it != fReExportedSymbols.end(); ++it) {
+                       pint_t targetSymbolAddress;
+                       bool isResolver;
+
+                       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) ) 
+                               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";
+
+                       fHashTable[it->exportName] = targetSymbolAddress;
+               }
+               // mark as done
+               fReExportedSymbolsResolved = true;
+       }
+
+       *isResolverSymbol = false;
+       if ( !fSymbolResolvers.empty() && fSymbolResolvers.count(name) ) {
+               // lazy pointers should be left unbound, rather than bind to resolver stub
+               *isResolverSymbol = true;
+       }
+       
        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());
        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;
                return true;
        }
 
        // search re-exports
        for (typename std::vector<BinderAndReExportFlag>::iterator it = fDependentDylibs.begin(); it != fDependentDylibs.end(); ++it) {
                if ( it->reExport ) {
                return true;
        }
 
        // search re-exports
        for (typename std::vector<BinderAndReExportFlag>::iterator it = fDependentDylibs.begin(); it != fDependentDylibs.end(); ++it) {
                if ( it->reExport ) {
-                       if ( it->binder->findExportedSymbolAddress(name, result) )
+                       if ( it->binder->findExportedSymbolAddress(name, result, foundIn, isResolverSymbol) )
                                return true;
                }
        }
                                return true;
                }
        }
@@ -829,6 +1036,144 @@ bool Binder<A>::findExportedSymbolAddress(const char* name, pint_t* result)
        return false;
 }
 
        return false;
 }
 
+// record which dylibs will be using this dylibs lazy pointer
+template <typename A>
+void Binder<A>::addResolverClient(Binder<A>* clientDylib, const char* symbolName)
+{
+    ClientAndSymbol x;
+    x.client = clientDylib;
+    x.symbolName = 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;
+    }
+    return 0;
+}
+
+// called after all binding is done to optimize lazy pointers
+template <typename A>
+void Binder<A>::optimize()
+{
+    for (typename std::vector<ClientAndSymbol>::iterator it = fClientAndSymbols.begin(); it != fClientAndSymbols.end(); ++it) {
+        pint_t lpVMAddr = findLazyPointerFor(it->symbolName);
+        if ( lpVMAddr != 0 ) {
+            it->client->optimizeStub(it->symbolName, lpVMAddr);
+        }
+        else {
+            fprintf(stderr, "not able to optimize lazy pointer for %s in %s\n", it->symbolName, it->client->getDylibID());
+        }
+        
+    }
+}
+
+template <>
+void Binder<arm>::optimizeStub(uint8_t* stubMappedAddress, pint_t stubVMAddress, uint32_t stubSize, pint_t lpVMAddr)
+{
+    if ( stubSize != 16 ) {
+        fprintf(stderr, "could not optimize ARM stub to resolver function in %s because it is wrong size\n", this->getDylibID());
+        return;
+    }
+    uint32_t* instructions = (uint32_t*)stubMappedAddress;
+    if (   (E::get32(instructions[0]) != 0xe59fc004)
+        || (E::get32(instructions[1]) != 0xe08fc00c)
+        || (E::get32(instructions[2]) != 0xe59cf000)
+        ) {
+        fprintf(stderr, "could not optimize ARM stub to resolver function in %s because instructions are not as expected\n", this->getDylibID());
+        return;
+    }
+    // last .long in stub is:  lazyPtr - (stub+8)
+    // alter to point to more optimal lazy pointer
+    uint32_t betterOffset = lpVMAddr  - (stubVMAddress + 12);
+    E::set32(instructions[3], betterOffset);
+}
+
+
+template <>
+void Binder<x86_64>::optimizeStub(uint8_t* stubMappedAddress, pint_t stubVMAddress, uint32_t stubSize, pint_t lpVMAddr)
+{
+    if ( stubSize != 6 ) {
+        fprintf(stderr, "could not optimize x86_64 stub to resolver function in %s because it is wrong size\n", this->getDylibID());
+        return;
+    }
+    if ( (stubMappedAddress[0] != 0xFF) || (stubMappedAddress[1] != 0x25) ) {
+        fprintf(stderr, "could not optimize stub to resolver function in %s because instructions are not as expected\n", this->getDylibID());
+        return;
+    }
+    // last four bytes in stub is RIP relative offset to lazy pointer
+    // alter to point to more optimal lazy pointer
+    uint32_t betterOffset = lpVMAddr  - (stubVMAddress + 6);
+    E::set32(*((uint32_t*)(&stubMappedAddress[2])), betterOffset);
+}
+
+template <typename A>
+void Binder<A>::optimizeStub(uint8_t* stubMappedAddress, pint_t stubVMAddress, uint32_t stubSize, pint_t lpVMAddress)
+{
+    // Remaining architectures are not optimized
+    //fprintf(stderr, "optimize stub at %p in %s to use lazyPointer at 0x%llX\n", stubMappedAddress, this->getDylibID(), (uint64_t)lpVMAddress);
+}
+
+// search for stub in this image that call target symbol name and then optimize its lazy pointer
+template <typename A>
+void Binder<A>::optimizeStub(const char* stubName, pint_t lpVMAddr)
+{
+       // find named stub
+       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 ) {
+                       macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
+                       macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)seg + sizeof(macho_segment_command<P>));
+                       macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
+                       for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+                               if ( ((sect->flags() & SECTION_TYPE) == S_SYMBOL_STUBS) && (sect->size() != 0) ) {
+                                       pint_t stubsVMStart = sect->addr();
+                                       uint8_t* stubsMappingStart = (uint8_t*)this->mappedAddressForNewAddress(stubsVMStart);
+                                       const uint32_t indirectTableOffset = sect->reserved1();
+                                       const uint32_t stubSize = sect->reserved2();
+                                       uint32_t elementCount = sect->size() / stubSize;
+                    pint_t stubVMAddr = stubsVMStart;
+                    uint8_t* stubMappedAddr = stubsMappingStart;
+                                       for (uint32_t j=0; j < elementCount; ++j, stubMappedAddr += stubSize, stubVMAddr += stubSize) {
+                                               uint32_t symbolIndex = E::get32(indirectTable[indirectTableOffset + j]); 
+                                               switch ( symbolIndex ) {
+                                                       case INDIRECT_SYMBOL_ABS:
+                                                       case INDIRECT_SYMBOL_LOCAL:
+                                                               break;
+                                                       default:
+                                {
+                                   const macho_nlist<P>* sym = &this->fSymbolTable[symbolIndex];
+                                   const char* symName = &fStrings[sym->n_strx()];
+                                    if ( strcmp(symName, stubName) == 0 ) 
+                                        this->optimizeStub(stubMappedAddr, stubVMAddr, stubSize, lpVMAddr);
+                                }
+                                                               break;
+                                               }
+                                       }
+                               }
+                       }
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }
+}
 
 
 #endif // __MACHO_BINDER__
 
 
 #endif // __MACHO_BINDER__
index cba7f8a591a8c99254d70379c6f9c7ca29451a43..3be3fa2eb0c7d8d7fe052062f889b902a3f79f3d 100644 (file)
@@ -43,6 +43,27 @@ struct uuid_command {
        #define S_16BYTE_LITERALS 0xE
 #endif
 
        #define S_16BYTE_LITERALS 0xE
 #endif
 
+#ifndef CPU_SUBTYPE_ARM_V5TEJ
+       #define CPU_SUBTYPE_ARM_V5TEJ           ((cpu_subtype_t) 7)
+#endif
+#ifndef CPU_SUBTYPE_ARM_XSCALE
+       #define CPU_SUBTYPE_ARM_XSCALE          ((cpu_subtype_t) 8)
+#endif
+#ifndef CPU_SUBTYPE_ARM_V7
+       #define CPU_SUBTYPE_ARM_V7                      ((cpu_subtype_t) 9)
+#endif
+
+#ifndef LC_LOAD_UPWARD_DYLIB
+       #define LC_LOAD_UPWARD_DYLIB (0x23|LC_REQ_DYLD) /* load of dylib whose initializers run later */
+#endif
+
+#ifndef EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
+       #define EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER 0x10
+#endif
+#ifndef EXPORT_SYMBOL_FLAGS_REEXPORT
+       #define EXPORT_SYMBOL_FLAGS_REEXPORT 0x08
+#endif
+
 
 #include "FileAbstraction.hpp"
 #include "Architectures.hpp"
 
 #include "FileAbstraction.hpp"
 #include "Architectures.hpp"
@@ -738,29 +759,28 @@ public:
 
     const macho_segment_command<P>* getSegment(const char *segname) const
     {
 
     const macho_segment_command<P>* getSegment(const char *segname) const
     {
-        const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)this + sizeof(macho_header<P>));
-        const uint32_t cmd_count = this->ncmds();
+        const macho_load_command<P>* cmds = (macho_load_command<P>*)((uint8_t*)this + sizeof(macho_header<P>));
+        uint32_t cmd_count = this->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_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>* segcmd = 
-                    (macho_segment_command<P>*)cmd;
+                const macho_segment_command<P>* segcmd = (macho_segment_command<P>*)cmd;
                 if (0 == strncmp(segname, segcmd->segname(), 16)) {
                     return segcmd;
                 }
             }
                 if (0 == strncmp(segname, segcmd->segname(), 16)) {
                     return segcmd;
                 }
             }
-            cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+            cmd = (macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
         }
         return NULL;
     }
 
     const macho_section<P>* getSection(const char *segname, const char *sectname) const
     {
         }
         return NULL;
     }
 
     const macho_section<P>* getSection(const char *segname, const char *sectname) const
     {
-        const macho_segment_command<P>* const segcmd = getSegment(segname);
+       const  macho_segment_command<P>* segcmd = getSegment(segname);
         if (!segcmd) return NULL;
 
         const macho_section<P>* sectcmd = (macho_section<P>*)(segcmd+1);
         if (!segcmd) return NULL;
 
         const macho_section<P>* sectcmd = (macho_section<P>*)(segcmd+1);
-        const uint32_t section_count = segcmd->nsects();
+        uint32_t section_count = segcmd->nsects();
         for (uint32_t j = 0; j < section_count; ++j) {
             if (0 == ::strncmp(sectcmd[j].sectname(), sectname, 16)) {
                 return sectcmd+j;
         for (uint32_t j = 0; j < section_count; ++j) {
             if (0 == ::strncmp(sectcmd[j].sectname(), sectname, 16)) {
                 return sectcmd+j;
index 945227b727b55054012fbd9994e4d36fcb63b3c9..e23cbac280dfc8214d6532bc2dff39783999b4d1 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
- * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2006-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -27,6 +27,7 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/errno.h>
 #include <sys/mman.h>
 #include <mach/mach.h>
 #include <limits.h>
 #include <sys/mman.h>
 #include <mach/mach.h>
 #include <limits.h>
@@ -124,10 +125,15 @@ public:
        virtual uint32_t                                                        getFileType() const     = 0;
        virtual uint32_t                                                        getFlags() const = 0;
        virtual Library                                                         getID() const = 0;
        virtual uint32_t                                                        getFileType() const     = 0;
        virtual uint32_t                                                        getFlags() const = 0;
        virtual Library                                                         getID() const = 0;
+       virtual bool                                                            isDylib() const = 0;
        virtual bool                                                            isSplitSeg() const = 0;
        virtual bool                                                            hasSplitSegInfo() const = 0;
        virtual bool                                                            isRootOwned() const = 0;
        virtual bool                                                            inSharableLocation() const = 0;
        virtual bool                                                            isSplitSeg() const = 0;
        virtual bool                                                            hasSplitSegInfo() const = 0;
        virtual bool                                                            isRootOwned() const = 0;
        virtual bool                                                            inSharableLocation() const = 0;
+       virtual bool                                                            hasDynamicLookupLinkage() const = 0;
+       virtual bool                                                            hasMainExecutableLookupLinkage() const = 0;
+       virtual bool                                                            isTwoLevelNamespace() const     = 0;
+       virtual bool                                                            hasDyldInfo() const     = 0;
        virtual uint32_t                                                        getNameFileOffset() const = 0;
        virtual time_t                                                          getLastModTime() const = 0;
        virtual ino_t                                                           getInode() const = 0;
        virtual uint32_t                                                        getNameFileOffset() const = 0;
        virtual time_t                                                          getLastModTime() const = 0;
        virtual ino_t                                                           getInode() const = 0;
@@ -142,6 +148,9 @@ public:
        virtual uint64_t                                                        getExecutableVMSize() const = 0;
        virtual uint64_t                                                        getWritableVMSize() const = 0;
        virtual uint64_t                                                        getReadOnlyVMSize() const = 0;
        virtual uint64_t                                                        getExecutableVMSize() const = 0;
        virtual uint64_t                                                        getWritableVMSize() const = 0;
        virtual uint64_t                                                        getReadOnlyVMSize() const = 0;
+       // 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;
 };
 
 
 };
 
 
@@ -161,10 +170,15 @@ public:
        virtual uint32_t                                                        getFileType() const             { return fFileType; }
        virtual uint32_t                                                        getFlags() const                { return fFlags; }
        virtual Library                                                         getID() const                   { return fDylibID; }
        virtual uint32_t                                                        getFileType() const             { return fFileType; }
        virtual uint32_t                                                        getFlags() const                { return fFlags; }
        virtual Library                                                         getID() const                   { return fDylibID; }
+       virtual bool                                                            isDylib() const                 { return fIsDylib; }
        virtual bool                                                            isSplitSeg() const;
        virtual bool                                                            hasSplitSegInfo() const { return fHasSplitSegInfo; }
        virtual bool                                                            isRootOwned() const             { return fRootOwned; }
        virtual bool                                                            inSharableLocation() const { return fShareableLocation; }
        virtual bool                                                            isSplitSeg() const;
        virtual bool                                                            hasSplitSegInfo() const { return fHasSplitSegInfo; }
        virtual bool                                                            isRootOwned() const             { return fRootOwned; }
        virtual bool                                                            inSharableLocation() const { return fShareableLocation; }
+       virtual bool                                                            hasDynamicLookupLinkage() const { return fDynamicLookupLinkage; }
+       virtual bool                                                            hasMainExecutableLookupLinkage() const { return fMainExecutableLookupLinkage; }
+       virtual bool                                                            isTwoLevelNamespace() const     { return (fFlags & MH_TWOLEVEL); }
+       virtual bool                                                            hasDyldInfo() const             { return fHasDyldInfo; }
        virtual uint32_t                                                        getNameFileOffset() const{ return fNameFileOffset; }
        virtual time_t                                                          getLastModTime() const  { return fMTime; }
        virtual ino_t                                                           getInode() const                { return fInode; }
        virtual uint32_t                                                        getNameFileOffset() const{ return fNameFileOffset; }
        virtual time_t                                                          getLastModTime() const  { return fMTime; }
        virtual ino_t                                                           getInode() const                { return fInode; }
@@ -179,6 +193,8 @@ public:
        virtual uint64_t                                                        getExecutableVMSize() const             { return fVMExecutableSize; }
        virtual uint64_t                                                        getWritableVMSize() const               { return fVMWritablSize; }
        virtual uint64_t                                                        getReadOnlyVMSize() const               { return fVMReadOnlySize; }
        virtual uint64_t                                                        getExecutableVMSize() const             { return fVMExecutableSize; }
        virtual uint64_t                                                        getWritableVMSize() const               { return fVMWritablSize; }
        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; }
        
 private:
        typedef typename A::P                                   P;
        
 private:
        typedef typename A::P                                   P;
@@ -209,6 +225,11 @@ private:
        bool                                                                            fHasSplitSegInfo;
        bool                                                                            fRootOwned;
        bool                                                                            fShareableLocation;
        bool                                                                            fHasSplitSegInfo;
        bool                                                                            fRootOwned;
        bool                                                                            fShareableLocation;
+       bool                                                                            fDynamicLookupLinkage;
+       bool                                                                            fMainExecutableLookupLinkage;
+       bool                                                                            fIsDylib;
+       bool                                                                            fHasDyldInfo;
+       mutable const uint8_t*                                          fDyldInfoExports;
 };
 
 
 };
 
 
@@ -229,9 +250,7 @@ private:
        };
        typedef __gnu_cxx::hash_map<const char*, const UniversalMachOLayout*, __gnu_cxx::hash<const char*>, CStringEquals> PathToNode;
 
        };
        typedef __gnu_cxx::hash_map<const char*, const UniversalMachOLayout*, __gnu_cxx::hash<const char*>, CStringEquals> PathToNode;
 
-       static bool                                     compatibleSubtype(const std::set<ArchPair>* onlyArchs, cpu_type_t cpuType, cpu_subtype_t cpuSubType);
-       static bool                                     bestSliceForArch(uint32_t sliceCount, const struct fat_arch* slices, ArchPair ap, uint32_t& bestSliceIndex);
-       static const cpu_subtype_t* getArmSubtypeList(cpu_subtype_t s);
+       static bool                                     requestedSlice(const std::set<ArchPair>* onlyArchs, cpu_type_t cpuType, cpu_subtype_t cpuSubType);
 
        static PathToNode                                                       fgLayoutCache;
        const char*                                                                     fPath;
 
        static PathToNode                                                       fgLayoutCache;
        const char*                                                                     fPath;
@@ -243,80 +262,23 @@ UniversalMachOLayout::PathToNode UniversalMachOLayout::fgLayoutCache;
 
 
 
 
 
 
-// armv7 can run: v7, v6, v5, and v4
-static const cpu_subtype_t kARMV7compatibleSubTypes[] =
-       { CPU_SUBTYPE_ARM_V7, CPU_SUBTYPE_ARM_V6, CPU_SUBTYPE_ARM_V5TEJ, CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, 0 };
-
-// armv6 can run: v6, v5, and v4
-static const cpu_subtype_t kARMV6compatibleSubTypes[] =
-       { CPU_SUBTYPE_ARM_V6, CPU_SUBTYPE_ARM_V5TEJ, CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, 0};
-
-// xscale can run: xscale, v5, and v4
-static const cpu_subtype_t kARMXscaleCompatibleSubTypes[] =
-       { CPU_SUBTYPE_ARM_XSCALE, CPU_SUBTYPE_ARM_V5TEJ, CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, 0};
-
-// armv5 can run: v5 and v4
-static const cpu_subtype_t kARMV5compatibleSubTypes[] =
-       { CPU_SUBTYPE_ARM_V5TEJ, CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, 0};
-
-// armv4 can run: v4
-static const cpu_subtype_t kARMV4compatibleSubTypes[] =
-       { CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, 0 };
-
-const cpu_subtype_t* UniversalMachOLayout::getArmSubtypeList(cpu_subtype_t s)
-{
-       switch ( s ) {
-               case CPU_SUBTYPE_ARM_V7:
-                       return kARMV7compatibleSubTypes;
-               case CPU_SUBTYPE_ARM_V6:
-                       return kARMV6compatibleSubTypes;
-               case CPU_SUBTYPE_ARM_XSCALE:
-                       return kARMXscaleCompatibleSubTypes;
-               case CPU_SUBTYPE_ARM_V5TEJ:
-                       return kARMV5compatibleSubTypes;
-               case CPU_SUBTYPE_ARM_V4T:
-                       return kARMV4compatibleSubTypes;
-       }
-       return NULL;
-}
-
-
-
 const MachOLayoutAbstraction* UniversalMachOLayout::getSlice(ArchPair ap) const
 {
 const MachOLayoutAbstraction* UniversalMachOLayout::getSlice(ArchPair ap) const
 {
-       switch ( ap.arch ) {
-               case CPU_TYPE_POWERPC:
-               case CPU_TYPE_I386:
-               case CPU_TYPE_X86_64:
-                       // use first matching cputype
-                       for(std::vector<MachOLayoutAbstraction*>::const_iterator it=fLayouts.begin(); it != fLayouts.end(); ++it) {
-                               const MachOLayoutAbstraction* layout = *it;
-                               if ( layout->getArchPair().arch == ap.arch ) 
-                                       return layout;
-                       }
-                       break;
-               case CPU_TYPE_ARM:
-                       const cpu_subtype_t* list = getArmSubtypeList(ap.subtype);
-                       if ( list != NULL ) {
-                               // known subtype, find best match
-                               for(const cpu_subtype_t* s=list; *s != 0; ++s) {
-                                       for(std::vector<MachOLayoutAbstraction*>::const_iterator it=fLayouts.begin(); it != fLayouts.end(); ++it) {
-                                               const MachOLayoutAbstraction* layout = *it;
-                                               if ( (layout->getArchPair().arch == ap.arch) && (layout->getArchPair().subtype == *s) ) 
-                                                       return layout;
-                                       }
-                               }
-                       }
-                       else {
-                               // unknown arm sub-type, must have exact match
-                               for(std::vector<MachOLayoutAbstraction*>::const_iterator it=fLayouts.begin(); it != fLayouts.end(); ++it) {
-                                       const MachOLayoutAbstraction* layout = *it;
-                                       if ( (layout->getArchPair().arch == ap.arch) && (layout->getArchPair().subtype == ap.subtype) ) 
-                                               return layout;
-                               }
-                       }
+       // use matching cputype and cpusubtype
+       for(std::vector<MachOLayoutAbstraction*>::const_iterator it=fLayouts.begin(); it != fLayouts.end(); ++it) {
+               const MachOLayoutAbstraction* layout = *it;
+               if ( layout->getArchPair().arch == ap.arch ) {
+            switch ( ap.arch ) {
+                case CPU_TYPE_ARM:
+                    if ( layout->getArchPair().subtype == ap.subtype ) 
+                        return layout;
+                    break;
+                default:
+                    return layout;
+            }
+        }
        }
        }
-       throwf("no compatible slice found in %s", fPath);
+       return NULL;
 }
 
 
 }
 
 
@@ -336,74 +298,24 @@ const UniversalMachOLayout& UniversalMachOLayout::find(const char* path, const s
        return *result;
 }
 
        return *result;
 }
 
-bool UniversalMachOLayout::bestSliceForArch(uint32_t sliceCount, const struct fat_arch* slices, ArchPair ap, uint32_t& bestSliceIndex)
-{
-       switch ( ap.arch ) {
-               case CPU_TYPE_POWERPC:
-               case CPU_TYPE_I386:
-               case CPU_TYPE_X86_64:
-                       // use first matching cputype
-                       for (uint32_t i=0; i < sliceCount; ++i) {
-                               if ( OSSwapBigToHostInt32(slices[i].cputype) == ap.arch ) {
-                                       bestSliceIndex = i;
-                                       return true;
-                               }
-                       }
-                       return false;
-               case CPU_TYPE_ARM:
-                       // find best matching arch
-                       const cpu_subtype_t* list = getArmSubtypeList(ap.subtype);
-                       if ( list != NULL ) {
-                               for(const cpu_subtype_t* s=list; *s != 0; ++s) {
-                                       for (uint32_t i=0; i < sliceCount; ++i) {
-                                               if ( (OSSwapBigToHostInt32(slices[i].cputype) == ap.arch) && (OSSwapBigToHostInt32(slices[i].cpusubtype) == *s) ) {
-                                                       bestSliceIndex = i;
-                                                       return true;
-                                               }
-                                       }
-                               }
-                               return false;
-                       }
-                       // unknown arm sub-type, must have exact match
-                       for (uint32_t i=0; i < sliceCount; ++i) {
-                               if ( (OSSwapBigToHostInt32(slices[i].cputype) == ap.arch) && (OSSwapBigToHostInt32(slices[i].cpusubtype) == ap.subtype) ) {
-                                       bestSliceIndex = i;
-                                       return true;
-                               }
-                       }
-                       return false;
-       }
-       throw "unknown architecture";
-}
 
 
-bool UniversalMachOLayout::compatibleSubtype(const std::set<ArchPair>* onlyArchs, cpu_type_t cpuType, cpu_subtype_t cpuSubType)
+bool UniversalMachOLayout::requestedSlice(const std::set<ArchPair>* onlyArchs, cpu_type_t cpuType, cpu_subtype_t cpuSubType)
 {
 {
+       if ( onlyArchs == NULL )
+               return true;
+       // must match cputype and cpusubtype
        for (std::set<ArchPair>::const_iterator it = onlyArchs->begin(); it != onlyArchs->end(); ++it) {
        for (std::set<ArchPair>::const_iterator it = onlyArchs->begin(); it != onlyArchs->end(); ++it) {
-               if ( cpuType == it->arch ) {
-                       switch ( it->arch ) {
-                               case CPU_TYPE_POWERPC:
-                               case CPU_TYPE_I386:
-                               case CPU_TYPE_X86_64:
-                                       // just match cpu type
-                                       return true;
-                               case CPU_TYPE_ARM:
-                               {
-                                       const cpu_subtype_t* list = getArmSubtypeList(it->subtype);
-                                       if ( list != NULL ) {
-                                               // see if mach-o file is supported by this ArchPair
-                                               for(const cpu_subtype_t* s=list; *s != 0; ++s) {
-                                                       if ( *s == cpuSubType )
-                                                               return true;
-                                               }
-                                       }
-                                       else {
-                                               // unknown arm sub-type, must have exact match
-                                               if ( it->subtype == cpuSubType )
-                                                       return true;
-                                       }
-                               }
-                       }
-               }
+               ArchPair anArch = *it;
+               if ( cpuType == anArch.arch ) {
+            switch ( cpuType ) {
+                case CPU_TYPE_ARM:
+                    if ( cpuSubType == anArch.subtype ) 
+                        return true;
+                    break;
+                default:
+                    return true;
+            }
+        }
        }
        return false;
 }
        }
        return false;
 }
@@ -414,8 +326,13 @@ UniversalMachOLayout::UniversalMachOLayout(const char* path, const std::set<Arch
 {
        // map in whole file
        int fd = ::open(path, O_RDONLY, 0);
 {
        // map in whole file
        int fd = ::open(path, O_RDONLY, 0);
-       if ( fd == -1 )
-               throwf("can't open file, errno=%d", errno);
+       if ( fd == -1 ) {
+               int err = errno;
+               if  ( err == ENOENT )
+                       throwf("file not found");
+               else
+                       throwf("can't open file, errno=%d", err);
+       }
        struct stat stat_buf;
        if ( fstat(fd, &stat_buf) == -1)
                throwf("can't stat open file %s, errno=%d", path, errno);
        struct stat stat_buf;
        if ( fstat(fd, &stat_buf) == -1)
                throwf("can't stat open file %s, errno=%d", path, errno);
@@ -434,27 +351,17 @@ UniversalMachOLayout::UniversalMachOLayout(const char* path, const std::set<Arch
                        // Fat header is always big-endian
                        const struct fat_arch* slices = (struct fat_arch*)(p + sizeof(struct fat_header));
                        const uint32_t sliceCount = OSSwapBigToHostInt32(fh->nfat_arch);
                        // Fat header is always big-endian
                        const struct fat_arch* slices = (struct fat_arch*)(p + sizeof(struct fat_header));
                        const uint32_t sliceCount = OSSwapBigToHostInt32(fh->nfat_arch);
-                       std::set<uint32_t> slicesToUse;
-                       if ( onlyArchs == NULL ) {
-                               // no filter, so instantiate all slices
-                               for (uint32_t i=0; i < sliceCount; ++i) 
-                                       slicesToUse.insert(i);
-                       }
-                       else {
-                               // instantiate only slices that are best for each architecture
-                               for (std::set<ArchPair>::const_iterator it = onlyArchs->begin(); it != onlyArchs->end(); ++it) {
-                                       uint32_t bestSliceIndex;
-                                       if ( bestSliceForArch(sliceCount, slices, *it, bestSliceIndex) ) 
-                                               slicesToUse.insert(bestSliceIndex);
-                               }
-                       }
                        for (uint32_t i=0; i < sliceCount; ++i) {
                        for (uint32_t i=0; i < sliceCount; ++i) {
-                               if ( slicesToUse.count(i) ) {
+                               if ( requestedSlice(onlyArchs, OSSwapBigToHostInt32(slices[i].cputype), OSSwapBigToHostInt32(slices[i].cpusubtype)) ) {
                                        uint32_t fileOffset = OSSwapBigToHostInt32(slices[i].offset);
                                        if ( fileOffset > stat_buf.st_size ) {
                                                throwf("malformed universal file, slice %u for architecture 0x%08X is beyond end of file: %s", 
                                                                i, OSSwapBigToHostInt32(slices[i].cputype), path);
                                        }
                                        uint32_t fileOffset = OSSwapBigToHostInt32(slices[i].offset);
                                        if ( fileOffset > stat_buf.st_size ) {
                                                throwf("malformed universal file, slice %u for architecture 0x%08X is beyond end of file: %s", 
                                                                i, OSSwapBigToHostInt32(slices[i].cputype), path);
                                        }
+                                       if ( (fileOffset+OSSwapBigToHostInt32(slices[i].size)) > stat_buf.st_size ) {
+                                               throwf("malformed universal file, slice %u for architecture 0x%08X is beyond end of file: %s", 
+                                                               i, OSSwapBigToHostInt32(slices[i].cputype), path);
+                                       }
                                        try {
                                                switch ( OSSwapBigToHostInt32(slices[i].cputype) ) {
                                                        case CPU_TYPE_POWERPC:
                                        try {
                                                switch ( OSSwapBigToHostInt32(slices[i].cputype) ) {
                                                        case CPU_TYPE_POWERPC:
@@ -485,19 +392,19 @@ UniversalMachOLayout::UniversalMachOLayout(const char* path, const std::set<Arch
                else {
                        try {
                                if ( (OSSwapBigToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapBigToHostInt32(mh->cputype) == CPU_TYPE_POWERPC)) {
                else {
                        try {
                                if ( (OSSwapBigToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapBigToHostInt32(mh->cputype) == CPU_TYPE_POWERPC)) {
-                                       if ( (onlyArchs == NULL) || compatibleSubtype(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) ) 
+                                       if ( requestedSlice(onlyArchs, OSSwapBigToHostInt32(mh->cputype), OSSwapBigToHostInt32(mh->cpusubtype)) ) 
                                                fLayouts.push_back(new MachOLayout<ppc>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
                                }
                                else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_I386)) {
                                                fLayouts.push_back(new MachOLayout<ppc>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
                                }
                                else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_I386)) {
-                                       if ( (onlyArchs == NULL) || compatibleSubtype(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) ) 
+                                       if ( requestedSlice(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) ) 
                                                fLayouts.push_back(new MachOLayout<x86>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
                                }
                                else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_X86_64)) {
                                                fLayouts.push_back(new MachOLayout<x86>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
                                }
                                else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_X86_64)) {
-                                       if ( (onlyArchs == NULL) || compatibleSubtype(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) ) 
+                                       if ( requestedSlice(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) ) 
                                                fLayouts.push_back(new MachOLayout<x86_64>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
                                }
                                else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_ARM)) {
                                                fLayouts.push_back(new MachOLayout<x86_64>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
                                }
                                else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_ARM)) {
-                                       if ( (onlyArchs == NULL) || compatibleSubtype(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) ) 
+                                       if ( requestedSlice(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) ) 
                                                fLayouts.push_back(new MachOLayout<arm>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
                                }
                                else if ( (OSSwapBigToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapBigToHostInt32(mh->cputype) == CPU_TYPE_POWERPC64)) {
                                                fLayouts.push_back(new MachOLayout<arm>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
                                }
                                else if ( (OSSwapBigToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapBigToHostInt32(mh->cputype) == CPU_TYPE_POWERPC64)) {
@@ -522,7 +429,8 @@ UniversalMachOLayout::UniversalMachOLayout(const char* path, const std::set<Arch
 template <typename A>
 MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char* path, ino_t inode, time_t modTime, uid_t uid)
  : fPath(path), fOffset(offset), fArchPair(0,0), fMTime(modTime), fInode(inode), fHasSplitSegInfo(false), fRootOwned(uid==0),
 template <typename A>
 MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char* path, ino_t inode, time_t modTime, uid_t uid)
  : fPath(path), fOffset(offset), fArchPair(0,0), fMTime(modTime), fInode(inode), fHasSplitSegInfo(false), fRootOwned(uid==0),
-   fShareableLocation(false)
+   fShareableLocation(false), fDynamicLookupLinkage(false), fMainExecutableLookupLinkage(false), fIsDylib(false), 
+       fHasDyldInfo(false), fDyldInfoExports(NULL)
 {
        fDylibID.name = NULL;
        fDylibID.currentVersion = 0;
 {
        fDylibID.name = NULL;
        fDylibID.currentVersion = 0;
@@ -533,6 +441,8 @@ MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char*
                throw "Layout object is wrong architecture";
        switch ( mh->filetype() ) {
                case MH_DYLIB:
                throw "Layout object is wrong architecture";
        switch ( mh->filetype() ) {
                case MH_DYLIB:
+                       fIsDylib = true;
+                       break;
                case MH_BUNDLE:
                case MH_EXECUTE:
                case MH_DYLIB_STUB:
                case MH_BUNDLE:
                case MH_EXECUTE:
                case MH_DYLIB_STUB:
@@ -546,6 +456,9 @@ MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char*
        fArchPair.arch = mh->cputype();
        fArchPair.subtype = mh->cpusubtype();
        
        fArchPair.arch = mh->cputype();
        fArchPair.subtype = mh->cpusubtype();
        
+       const macho_dyld_info_command<P>* dyldInfo = NULL;
+       const macho_symtab_command<P>* symbolTableCmd = NULL;
+       const macho_dysymtab_command<P>* dynamicSymbolTableCmd = NULL;
        const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)mh + sizeof(macho_header<P>));
        const uint32_t cmd_count = mh->ncmds();
        const macho_load_command<P>* cmd = cmds;
        const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)mh + sizeof(macho_header<P>));
        const uint32_t cmd_count = mh->ncmds();
        const macho_load_command<P>* cmd = cmds;
@@ -564,6 +477,7 @@ MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char*
                        case LC_LOAD_DYLIB:
                        case LC_LOAD_WEAK_DYLIB:
                        case LC_REEXPORT_DYLIB:
                        case LC_LOAD_DYLIB:
                        case LC_LOAD_WEAK_DYLIB:
                        case LC_REEXPORT_DYLIB:
+                       case LC_LOAD_UPWARD_DYLIB:
                                {
                                        macho_dylib_command<P>* dylib = (macho_dylib_command<P>*)cmd;
                                        Library lib;
                                {
                                        macho_dylib_command<P>* dylib = (macho_dylib_command<P>*)cmd;
                                        Library lib;
@@ -584,6 +498,17 @@ MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char*
                                                                segCmd->filesize(), segCmd->initprot(), segCmd->segname()));
                                }
                                break;
                                                                segCmd->filesize(), segCmd->initprot(), segCmd->segname()));
                                }
                                break;
+                       case LC_SYMTAB:
+                               symbolTableCmd = (macho_symtab_command<P>*)cmd;
+                               break;
+                       case LC_DYSYMTAB:
+                               dynamicSymbolTableCmd = (macho_dysymtab_command<P>*)cmd;
+                               break;
+                       case LC_DYLD_INFO:
+                       case LC_DYLD_INFO_ONLY:
+                               fHasDyldInfo = true;
+                               dyldInfo = (struct macho_dyld_info_command<P>*)cmd;
+                               break;
                }
                cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
        }
                }
                cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
        }
@@ -617,10 +542,31 @@ MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char*
                        if ( (fLowReadOnlySegment == NULL) || (seg.address() < fLowReadOnlySegment->address()) )
                                fLowReadOnlySegment = &seg;
                        fVMReadOnlySize += seg.size();
                        if ( (fLowReadOnlySegment == NULL) || (seg.address() < fLowReadOnlySegment->address()) )
                                fLowReadOnlySegment = &seg;
                        fVMReadOnlySize += seg.size();
-               }
+               }               
        }
        if ( (highSegment != NULL) && (fLowSegment != NULL) )
                fVMSize = (highSegment->address() + highSegment->size() - fLowSegment->address() + 4095) & (-4096);                     
        }
        if ( (highSegment != NULL) && (fLowSegment != NULL) )
                fVMSize = (highSegment->address() + highSegment->size() - fLowSegment->address() + 4095) & (-4096);                     
+       
+       // scan undefines looking, for magic ordinals
+       if ( (symbolTableCmd != NULL) && (dynamicSymbolTableCmd != NULL) ) {
+               const macho_nlist<P>* symbolTable = (macho_nlist<P>*)((uint8_t*)machHeader + symbolTableCmd->symoff());
+               const uint32_t startUndefs = dynamicSymbolTableCmd->iundefsym();
+               const uint32_t endUndefs = startUndefs + dynamicSymbolTableCmd->nundefsym();
+               for (uint32_t i=startUndefs; i < endUndefs; ++i) {
+                       uint8_t ordinal = GET_LIBRARY_ORDINAL(symbolTable[i].n_desc());
+                       if ( ordinal == DYNAMIC_LOOKUP_ORDINAL )
+                               fDynamicLookupLinkage = true;
+                       else if ( ordinal == EXECUTABLE_ORDINAL )
+                               fMainExecutableLookupLinkage = true;
+               }
+       }
+       
+       if ( dyldInfo != NULL ) {
+               if ( dyldInfo->export_off() != 0 ) {
+                       fDyldInfoExports = (uint8_t*)machHeader + dyldInfo->export_off();
+               }
+       }
+
 }
 
 template <> cpu_type_t MachOLayout<ppc>::arch()     { return CPU_TYPE_POWERPC; }
 }
 
 template <> cpu_type_t MachOLayout<ppc>::arch()     { return CPU_TYPE_POWERPC; }
index 9dcfc6babd0d4113e7aab01902a879b009cee23a..8907aad90dda84b0b8a8c4a8f13f3b69a898c385 100644 (file)
@@ -57,7 +57,7 @@ public:
        virtual cpu_type_t                                                      getArchitecture() const = 0;
        virtual uint64_t                                                        getBaseAddress() const = 0;
        virtual uint64_t                                                        getVMSize() const = 0;
        virtual cpu_type_t                                                      getArchitecture() const = 0;
        virtual uint64_t                                                        getBaseAddress() const = 0;
        virtual uint64_t                                                        getVMSize() const = 0;
-       virtual void                                                            rebase() = 0;
+       virtual void                                                            rebase(std::vector<void*>&) = 0;
 };
 
 
 };
 
 
@@ -71,7 +71,7 @@ public:
        virtual cpu_type_t                                                      getArchitecture() const;
        virtual uint64_t                                                        getBaseAddress() const;
        virtual uint64_t                                                        getVMSize() const;
        virtual cpu_type_t                                                      getArchitecture() const;
        virtual uint64_t                                                        getBaseAddress() const;
        virtual uint64_t                                                        getVMSize() const;
-       virtual void                                                            rebase();
+       virtual void                                                            rebase(std::vector<void*>&);
 
 protected:
        typedef typename A::P                                   P;
 
 protected:
        typedef typename A::P                                   P;
@@ -85,11 +85,13 @@ private:
        void                                                                            calculateRelocBase();
        void                                                                            adjustLoadCommands();
        void                                                                            adjustSymbolTable();
        void                                                                            calculateRelocBase();
        void                                                                            adjustLoadCommands();
        void                                                                            adjustSymbolTable();
+       void                                                                            optimzeStubs();
+       void                                                                            makeNoPicStub(uint8_t* stub, pint_t logicalAddress);
        void                                                                            adjustDATA();
        void                                                                            adjustCode();
        void                                                                            adjustDATA();
        void                                                                            adjustCode();
-       void                                                                            applyRebaseInfo();
+       void                                                                            applyRebaseInfo(std::vector<void*>& pointersInData);
        void                                                                            adjustExportInfo();
        void                                                                            adjustExportInfo();
-       void                                                                            doRebase(int segIndex, uint64_t segOffset, uint8_t type);
+       void                                                                            doRebase(int segIndex, uint64_t segOffset, uint8_t type, std::vector<void*>& pointersInData);
        void                                                                            adjustSegmentLoadCommand(macho_segment_command<P>* seg);
        pint_t                                                                          getSlideForVMAddress(pint_t vmaddress);
        pint_t*                                                                         mappedAddressForVMAddress(pint_t vmaddress);
        void                                                                            adjustSegmentLoadCommand(macho_segment_command<P>* seg);
        pint_t                                                                          getSlideForVMAddress(pint_t vmaddress);
        pint_t*                                                                         mappedAddressForVMAddress(pint_t vmaddress);
@@ -111,6 +113,8 @@ private:
        const macho_dyld_info_command<P>*                       fDyldInfo;
        bool                                                                            fSplittingSegments;
        bool                                                                            fOrignalVMRelocBaseAddressValid;
        const macho_dyld_info_command<P>*                       fDyldInfo;
        bool                                                                            fSplittingSegments;
        bool                                                                            fOrignalVMRelocBaseAddressValid;
+       pint_t                                                                          fSkipSplitSegInfoStart;
+       pint_t                                                                          fSkipSplitSegInfoEnd;
 };
 
 
 };
 
 
@@ -118,7 +122,8 @@ private:
 template <typename A>
 Rebaser<A>::Rebaser(const MachOLayoutAbstraction& layout)
  :     fLayout(layout), fOrignalVMRelocBaseAddress(NULL), fLinkEditBase(NULL), 
 template <typename A>
 Rebaser<A>::Rebaser(const MachOLayoutAbstraction& layout)
  :     fLayout(layout), fOrignalVMRelocBaseAddress(NULL), fLinkEditBase(NULL), 
-       fSymbolTable(NULL), fDynamicSymbolTable(NULL), fDyldInfo(NULL), fSplittingSegments(false), fOrignalVMRelocBaseAddressValid(false)
+       fSymbolTable(NULL), fDynamicSymbolTable(NULL), fDyldInfo(NULL), fSplittingSegments(false), 
+       fOrignalVMRelocBaseAddressValid(false), fSkipSplitSegInfoStart(0), fSkipSplitSegInfoEnd(0)
 {
        fHeader = (const macho_header<P>*)fLayout.getSegments()[0].mappedAddress();
        switch ( fHeader->filetype() ) {
 {
        fHeader = (const macho_header<P>*)fLayout.getSegments()[0].mappedAddress();
        switch ( fHeader->filetype() ) {
@@ -205,11 +210,11 @@ uint64_t Rebaser<A>::getVMSize() const
 
 
 template <typename A>
 
 
 template <typename A>
-void Rebaser<A>::rebase()
+void Rebaser<A>::rebase(std::vector<void*>& pointersInData)
 {              
        // update writable segments that have internal pointers
        if ( fDyldInfo != NULL )
 {              
        // update writable segments that have internal pointers
        if ( fDyldInfo != NULL )
-               this->applyRebaseInfo();
+               this->applyRebaseInfo(pointersInData);
        else
                this->adjustDATA();
 
        else
                this->adjustDATA();
 
@@ -225,6 +230,9 @@ void Rebaser<A>::rebase()
        // update symbol table  
        this->adjustSymbolTable();
        
        // update symbol table  
        this->adjustSymbolTable();
        
+       // optimize stubs 
+       this->optimzeStubs();
+       
        // update export info
        if ( fDyldInfo != NULL )
                this->adjustExportInfo();
        // update export info
        if ( fDyldInfo != NULL )
                this->adjustExportInfo();
@@ -262,6 +270,7 @@ void Rebaser<A>::adjustLoadCommands()
                        case LC_LOAD_DYLIB:
                        case LC_LOAD_WEAK_DYLIB:
                        case LC_REEXPORT_DYLIB:
                        case LC_LOAD_DYLIB:
                        case LC_LOAD_WEAK_DYLIB:
                        case LC_REEXPORT_DYLIB:
+                       case LC_LOAD_UPWARD_DYLIB:
                                if ( (fHeader->flags() & MH_PREBOUND) != 0 ) {
                                        // clear expected timestamps so that this image will load with invalid prebinding 
                                        macho_dylib_command<P>* dylib  = (macho_dylib_command<P>*)cmd;
                                if ( (fHeader->flags() & MH_PREBOUND) != 0 ) {
                                        // clear expected timestamps so that this image will load with invalid prebinding 
                                        macho_dylib_command<P>* dylib  = (macho_dylib_command<P>*)cmd;
@@ -359,6 +368,66 @@ typename A::P::uint_t* Rebaser<A>::mappedAddressForRelocAddress(pint_t r_address
 }
 
 
 }
 
 
+template <>
+void Rebaser<arm>::makeNoPicStub(uint8_t* stub, pint_t logicalAddress) 
+{
+       uint32_t* instructions = (uint32_t*)stub;
+       if ( (LittleEndian::get32(instructions[0]) == 0xE59FC004) && 
+               (LittleEndian::get32(instructions[1]) == 0xE08FC00C) && 
+               (LittleEndian::get32(instructions[2]) == 0xE59CF000) ) {
+                       uint32_t lazyPtrAddress = instructions[3] + logicalAddress + 12;
+                       LittleEndian::set32(instructions[0], 0xE59FC000);               //      ldr ip, [pc, #0]
+                       LittleEndian::set32(instructions[1], 0xE59CF000);               //      ldr pc, [ip]
+                       LittleEndian::set32(instructions[2], lazyPtrAddress);   //      .long   L_foo$lazy_ptr
+                       LittleEndian::set32(instructions[3], 0xE1A00000);               //      nop
+       }
+       else
+               fprintf(stderr, "unoptimized stub in %s at 0x%08X\n", fLayout.getFilePath(), logicalAddress);
+}
+
+
+#if 0 
+// disable this optimization do allow cache to slide
+template <>
+void Rebaser<arm>::optimzeStubs()
+{
+       // convert pic stubs to no-pic stubs in dyld shared cache
+       const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+       const uint32_t cmd_count = 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 ) {
+                       macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
+                       macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)seg + sizeof(macho_segment_command<P>));
+                       macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
+                       for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+                               if ( (sect->flags() & SECTION_TYPE) == S_SYMBOL_STUBS ) {
+                                       const uint32_t stubSize = sect->reserved2();
+                                       // ARM PIC stubs are 4 32-bit instructions long
+                                       if ( stubSize == 16 ) {
+                                               uint32_t stubCount = sect->size() / 16;
+                                               pint_t stubLogicalAddress = sect->addr();
+                                               uint8_t* stubMappedAddress = (uint8_t*)mappedAddressForNewAddress(stubLogicalAddress);
+                                               for(uint32_t s=0; s < stubCount; ++s) {
+                                                       makeNoPicStub(stubMappedAddress, stubLogicalAddress);
+                                                       stubLogicalAddress += 16;
+                                                       stubMappedAddress += 16;
+                                               }
+                                       }
+                               }
+                       }
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }
+}
+#endif
+
+template <typename A>
+void Rebaser<A>::optimzeStubs()
+{
+       // other architectures don't need stubs changed in shared cache
+}
+
 template <typename A>
 void Rebaser<A>::adjustSymbolTable()
 {
 template <typename A>
 void Rebaser<A>::adjustSymbolTable()
 {
@@ -388,7 +457,7 @@ void Rebaser<A>::adjustExportInfo()
 
        // since export info addresses are offsets from mach_header, everything in __TEXT is fine
        // only __DATA addresses need to be updated
 
        // since export info addresses are offsets from mach_header, everything in __TEXT is fine
        // only __DATA addresses need to be updated
-       const uint8_t* start = &fLinkEditBase[fDyldInfo->export_off()];
+       const uint8_t* start = fLayout.getDyldInfoExports(); 
        const uint8_t* end = &start[fDyldInfo->export_size()];
        std::vector<mach_o::trie::Entry> originalExports;
        try {
        const uint8_t* end = &start[fDyldInfo->export_size()];
        std::vector<mach_o::trie::Entry> originalExports;
        try {
@@ -425,29 +494,13 @@ void Rebaser<A>::adjustExportInfo()
        while ( (newExportTrieBytes.size() % sizeof(pint_t)) != 0 )
                newExportTrieBytes.push_back(0);
        
        while ( (newExportTrieBytes.size() % sizeof(pint_t)) != 0 )
                newExportTrieBytes.push_back(0);
        
-       // copy into place, zero pad
+       // allocate new buffer and set export_off to use new buffer instead
        uint32_t newExportsSize = newExportTrieBytes.size();
        uint32_t newExportsSize = newExportTrieBytes.size();
-       if ( newExportsSize > fDyldInfo->export_size() ) {
-               // it is possible that the new export trie is larger than the old one
-               // for those cases will malloc a block on the side and set up
-               // export_off to point to it.
-               uint8_t* sideTrie = new uint8_t[newExportsSize];
-               memcpy(sideTrie, &newExportTrieBytes[0], newExportsSize);
-               //fprintf(stderr, "set_export_off()=%ld, fLinkEditBase=%p, sideTrie=%p\n", (long)(sideTrie - fLinkEditBase), fLinkEditBase, sideTrie);
-               // warning, export_off is only 32-bits so if the trie grows it must be allocated with 32-bits of fLinkeditBase
-               int64_t offset = sideTrie - fLinkEditBase;
-               int32_t offset32 = (int32_t)offset;
-               if ( offset != offset32 )
-                       throw "internal error, new trie allocated to far from fLinkeditBase";
-               ((macho_dyld_info_command<P>*)fDyldInfo)->set_export_off(offset32);
-               ((macho_dyld_info_command<P>*)fDyldInfo)->set_export_size(newExportsSize);
-       }
-       else {
-               uint8_t* trie = (uint8_t*)&fLinkEditBase[fDyldInfo->export_off()];
-               memcpy(trie, &newExportTrieBytes[0], newExportsSize);
-               bzero(trie+newExportsSize, fDyldInfo->export_size() - newExportsSize);
-               ((macho_dyld_info_command<P>*)fDyldInfo)->set_export_size(newExportsSize);
-       }
+       uint8_t* sideTrie = new uint8_t[newExportsSize];
+       memcpy(sideTrie, &newExportTrieBytes[0], newExportsSize);
+       fLayout.setDyldInfoExports(sideTrie);
+       ((macho_dyld_info_command<P>*)fDyldInfo)->set_export_off(0); // invalidate old trie
+       ((macho_dyld_info_command<P>*)fDyldInfo)->set_export_size(newExportsSize);
 }
 
 
 }
 
 
@@ -455,7 +508,17 @@ void Rebaser<A>::adjustExportInfo()
 template <typename A>
 void Rebaser<A>::doCodeUpdate(uint8_t kind, uint64_t address, int64_t codeToDataDelta, int64_t codeToImportDelta)
 {
 template <typename A>
 void Rebaser<A>::doCodeUpdate(uint8_t kind, uint64_t address, int64_t codeToDataDelta, int64_t codeToImportDelta)
 {
-       //fprintf(stderr, "doCodeUpdate(kind=%d, address=0x%0llX, dataDelta=0x%08llX, importDelta=0x%08llX)\n", kind, address, codeToDataDelta, codeToImportDelta);
+       // begin hack for <rdar://problem/8253549> split seg info wrong for x86_64 stub helpers
+       if ( (fSkipSplitSegInfoStart <= address) && (address < fSkipSplitSegInfoEnd) ) {
+               uint8_t* p = (uint8_t*)mappedAddressForVMAddress(address);
+               // only ignore split seg info for "push" instructions
+               if ( p[-1] == 0x68 )
+                       return;
+       }
+       // end hack for <rdar://problem/8253549> 
+       
+       //fprintf(stderr, "doCodeUpdate(kind=%d, address=0x%0llX, dataDelta=0x%08llX, importDelta=0x%08llX, path=%s)\n", 
+       //                              kind, address, codeToDataDelta, codeToImportDelta, fLayout.getFilePath());
        uint32_t* p;
        uint32_t instruction;
        uint32_t value;
        uint32_t* p;
        uint32_t instruction;
        uint32_t value;
@@ -530,6 +593,7 @@ void Rebaser<A>::adjustCode()
                // get uleb128 compressed runs of code addresses to update
                const uint8_t* infoStart = NULL;
                const uint8_t* infoEnd = NULL;
                // get uleb128 compressed runs of code addresses to update
                const uint8_t* infoStart = NULL;
                const uint8_t* infoEnd = NULL;
+               const macho_segment_command<P>* seg;
                const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
                const uint32_t cmd_count = fHeader->ncmds();
                const macho_load_command<P>* cmd = cmds;
                const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
                const uint32_t cmd_count = fHeader->ncmds();
                const macho_load_command<P>* cmd = cmds;
@@ -542,6 +606,21 @@ void Rebaser<A>::adjustCode()
                                                infoEnd = &infoStart[segInfo->datasize()];
                                        }
                                        break;
                                                infoEnd = &infoStart[segInfo->datasize()];
                                        }
                                        break;
+                               // begin hack for <rdar://problem/8253549> split seg info wrong for x86_64 stub helpers
+                               case macho_segment_command<P>::CMD:
+                                       seg = (macho_segment_command<P>*)cmd;
+                                       if ( (getArchitecture() == CPU_TYPE_X86_64) && (strcmp(seg->segname(), "__TEXT") == 0) ) {
+                                               const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)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) {
+                                                       if ( strcmp(sect->sectname(), "__stub_helper") == 0 ) {
+                                                               fSkipSplitSegInfoStart = sect->addr();
+                                                               fSkipSplitSegInfoEnd = sect->addr() + sect->size() - 16;
+                                                       }       
+                                               }
+                                       }
+                                       break;
+                               // end hack for <rdar://problem/8253549> split seg info wrong for x86_64 stub helpers
                        }
                        cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
                }
                        }
                        cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
                }
@@ -559,7 +638,7 @@ void Rebaser<A>::adjustCode()
                                codeToDataDelta = (dataSeg.newAddress() - codeSeg.newAddress()) - (dataSeg.address() - codeSeg.address());
                }
                // decompress and call doCodeUpdate() on each address
                                codeToDataDelta = (dataSeg.newAddress() - codeSeg.newAddress()) - (dataSeg.address() - codeSeg.address());
                }
                // decompress and call doCodeUpdate() on each address
-               for(const uint8_t* p = infoStart; *p != 0;) {
+               for(const uint8_t* p = infoStart; (*p != 0) && (p < infoEnd);) {
                        uint8_t kind = *p++;
                        p = this->doCodeUpdateForEachULEB128Address(p, kind, orgBaseAddress, codeToDataDelta, codeToImportDelta);
                }
                        uint8_t kind = *p++;
                        p = this->doCodeUpdateForEachULEB128Address(p, kind, orgBaseAddress, codeToDataDelta, codeToImportDelta);
                }
@@ -567,7 +646,7 @@ void Rebaser<A>::adjustCode()
 }
 
 template <typename A>
 }
 
 template <typename A>
-void Rebaser<A>::doRebase(int segIndex, uint64_t segOffset, uint8_t type)
+void Rebaser<A>::doRebase(int segIndex, uint64_t segOffset, uint8_t type, std::vector<void*>& pointersInData)
 {
        const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
        if ( segIndex > segments.size() )
 {
        const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
        if ( segIndex > segments.size() )
@@ -603,11 +682,12 @@ void Rebaser<A>::doRebase(int segIndex, uint64_t segOffset, uint8_t type)
                default:
                        throw "bad rebase type";
        }
                default:
                        throw "bad rebase type";
        }
+       pointersInData.push_back(mappedAddr);
 }
 
 
 template <typename A>
 }
 
 
 template <typename A>
-void Rebaser<A>::applyRebaseInfo()
+void Rebaser<A>::applyRebaseInfo(std::vector<void*>& pointersInData)
 {
        const uint8_t* p = &fLinkEditBase[fDyldInfo->rebase_off()];
        const uint8_t* end = &p[fDyldInfo->rebase_size()];
 {
        const uint8_t* p = &fLinkEditBase[fDyldInfo->rebase_off()];
        const uint8_t* end = &p[fDyldInfo->rebase_size()];
@@ -641,26 +721,26 @@ void Rebaser<A>::applyRebaseInfo()
                                break;
                        case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
                                for (int i=0; i < immediate; ++i) {
                                break;
                        case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
                                for (int i=0; i < immediate; ++i) {
-                                       doRebase(segIndex, segOffset, type);
+                                       doRebase(segIndex, segOffset, type, pointersInData);
                                        segOffset += sizeof(pint_t);
                                }
                                break;
                        case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
                                count = read_uleb128(p, end);
                                for (uint32_t i=0; i < count; ++i) {
                                        segOffset += sizeof(pint_t);
                                }
                                break;
                        case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
                                count = read_uleb128(p, end);
                                for (uint32_t i=0; i < count; ++i) {
-                                       doRebase(segIndex, segOffset, type);
+                                       doRebase(segIndex, segOffset, type, pointersInData);
                                        segOffset += sizeof(pint_t);
                                }
                                break;
                        case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
                                        segOffset += sizeof(pint_t);
                                }
                                break;
                        case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
-                               doRebase(segIndex, segOffset, type);
+                               doRebase(segIndex, segOffset, type, pointersInData);
                                segOffset += read_uleb128(p, end) + sizeof(pint_t);
                                break;
                        case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
                                count = read_uleb128(p, end);
                                skip = read_uleb128(p, end);
                                for (uint32_t i=0; i < count; ++i) {
                                segOffset += read_uleb128(p, end) + sizeof(pint_t);
                                break;
                        case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
                                count = read_uleb128(p, end);
                                skip = read_uleb128(p, end);
                                for (uint32_t i=0; i < count; ++i) {
-                                       doRebase(segIndex, segOffset, type);
+                                       doRebase(segIndex, segOffset, type, pointersInData);
                                        segOffset += skip + sizeof(pint_t);
                                }
                                break;
                                        segOffset += skip + sizeof(pint_t);
                                }
                                break;
index 7c5d4a7e79d5fc713060275ff02891f2f6ea34a8..05a8e070387fbee0682a8f9ed5b9e39dcf9062e3 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
- * Copyright (c) 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #ifndef __MACH_O_TRIE__
 #define __MACH_O_TRIE__
 
 #ifndef __MACH_O_TRIE__
 #define __MACH_O_TRIE__
 
+#include <algorithm>
 
 #include "MachOFileAbstraction.hpp"
 
 
 #include "MachOFileAbstraction.hpp"
 
+
 namespace mach_o {
 namespace trie {
 
 namespace mach_o {
 namespace trie {
 
@@ -41,25 +43,28 @@ struct Edge
 
 struct Node
 {
 
 struct Node
 {
-                                               Node(const char* s) : fCummulativeString(s), fAddress(0), fFlags(0), fOrdered(false), 
+                                               Node(const char* s) : fCummulativeString(s), fAddress(0), fFlags(0), 
+                                                                                       fOther(0), fImportedName(NULL), fOrdered(false), 
                                                                                        fHaveExportInfo(false), fTrieOffset(0) {}
                                                ~Node() { }
        const char*                     fCummulativeString;
        std::vector<Edge>       fChildren;
        uint64_t                        fAddress;
                                                                                        fHaveExportInfo(false), fTrieOffset(0) {}
                                                ~Node() { }
        const char*                     fCummulativeString;
        std::vector<Edge>       fChildren;
        uint64_t                        fAddress;
-       uint32_t                        fFlags;
+       uint64_t                        fFlags;
+       uint64_t                        fOther;
+       const char*                     fImportedName;
        bool                            fOrdered;
        bool                            fHaveExportInfo;
        uint32_t                        fTrieOffset;
        
        bool                            fOrdered;
        bool                            fHaveExportInfo;
        uint32_t                        fTrieOffset;
        
-       void addSymbol(const char* fullStr, uint64_t address, uint32_t flags) {
+       void addSymbol(const char* fullStr, uint64_t address, uint64_t flags, uint64_t other, const char* importName) {
                const char* partialStr = &fullStr[strlen(fCummulativeString)];
                for (std::vector<Edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
                        Edge& e = *it;
                        int subStringLen = strlen(e.fSubString);
                        if ( strncmp(e.fSubString, partialStr, subStringLen) == 0 ) {
                                // already have matching edge, go down that path
                const char* partialStr = &fullStr[strlen(fCummulativeString)];
                for (std::vector<Edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
                        Edge& e = *it;
                        int subStringLen = strlen(e.fSubString);
                        if ( strncmp(e.fSubString, partialStr, subStringLen) == 0 ) {
                                // already have matching edge, go down that path
-                               e.fChild->addSymbol(fullStr, address, flags);
+                               e.fChild->addSymbol(fullStr, address, flags, other, importName);
                                return;
                        }
                        else {
                                return;
                        }
                        else {
@@ -80,18 +85,24 @@ struct Node
                                                abEdge.fChild = bNode;
                                                Edge bcEdge(bcEdgeStr, cNode);
                                                bNode->fChildren.push_back(bcEdge);
                                                abEdge.fChild = bNode;
                                                Edge bcEdge(bcEdgeStr, cNode);
                                                bNode->fChildren.push_back(bcEdge);
-                                               bNode->addSymbol(fullStr, address, flags);
+                                               bNode->addSymbol(fullStr, address, flags, other, importName);
                                                return;
                                        }
                                }
                        }
                }
                                                return;
                                        }
                                }
                        }
                }
+
                // no commonality with any existing child, make a new edge that is this whole string
                Node* newNode = new Node(strdup(fullStr));
                Edge newEdge(strdup(partialStr), newNode);
                fChildren.push_back(newEdge);
                newNode->fAddress = address;
                newNode->fFlags = flags;
                // no commonality with any existing child, make a new edge that is this whole string
                Node* newNode = new Node(strdup(fullStr));
                Edge newEdge(strdup(partialStr), newNode);
                fChildren.push_back(newEdge);
                newNode->fAddress = address;
                newNode->fFlags = flags;
+               newNode->fOther = other;
+               if ( (flags & EXPORT_SYMBOL_FLAGS_REEXPORT) && (importName != NULL) && (strcmp(fullStr,importName) != 0) )
+                       newNode->fImportedName = importName;
+               else
+                       newNode->fImportedName = NULL;
                newNode->fHaveExportInfo = true;
        }
        
                newNode->fHaveExportInfo = true;
        }
        
@@ -114,14 +125,26 @@ struct Node
        }
 
        // byte for terminal node size in bytes, or 0x00 if not terminal node
        }
 
        // byte for terminal node size in bytes, or 0x00 if not terminal node
-       // teminal node (uleb128 flags, uleb128 addr)
+       // teminal node (uleb128 flags, uleb128 addr [uleb128 other])
        // byte for child node count
        //  each child: zero terminated substring, uleb128 node offset
        bool updateOffset(uint32_t& offset) {
        // byte for child node count
        //  each child: zero terminated substring, uleb128 node offset
        bool updateOffset(uint32_t& offset) {
-               uint32_t nodeSize = 1; // byte for length of export info
-               if ( fHaveExportInfo ) 
-                       nodeSize += uleb128_size(fFlags) + uleb128_size(fAddress);
-
+               uint32_t nodeSize = 1; // length of export info when no export info
+               if ( fHaveExportInfo ) {
+                       if ( fFlags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
+                               nodeSize = uleb128_size(fFlags) + uleb128_size(fOther); // ordinal
+                               if ( fImportedName != NULL )
+                                       nodeSize += strlen(fImportedName);
+                               ++nodeSize; // trailing zero in imported name
+                       }
+                       else {
+                               nodeSize = uleb128_size(fFlags) + uleb128_size(fAddress);
+                               if ( fFlags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER )
+                                       nodeSize += uleb128_size(fOther);
+                       }
+                       // do have export info, overall node size so far is uleb128 of export info + export info
+                       nodeSize += uleb128_size(nodeSize); 
+               }
                // add children
                ++nodeSize; // byte for count of chidren
                for (std::vector<Edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
                // add children
                ++nodeSize; // byte for count of chidren
                for (std::vector<Edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
@@ -138,13 +161,42 @@ struct Node
 
        void appendToStream(std::vector<uint8_t>& out) {
                if ( fHaveExportInfo ) {
 
        void appendToStream(std::vector<uint8_t>& out) {
                if ( fHaveExportInfo ) {
-                       // nodes with export info: size, flags, address
-                       out.push_back(uleb128_size(fFlags) + uleb128_size(fAddress));
-                       append_uleb128(fFlags, out);
-                       append_uleb128(fAddress, out);
+                       if ( fFlags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
+                               if ( fImportedName != NULL ) {
+                                       // nodes with re-export info: size, flags, ordinal, string
+                                       uint32_t nodeSize = uleb128_size(fFlags) + uleb128_size(fOther) + strlen(fImportedName) + 1;
+                                       out.push_back(nodeSize);
+                                       append_uleb128(fFlags, out);
+                                       append_uleb128(fOther, out);
+                                       append_string(fImportedName, out);
+                               }
+                               else {
+                                       // nodes with re-export info: size, flags, ordinal, empty-string
+                                       uint32_t nodeSize = uleb128_size(fFlags) + uleb128_size(fOther) + 1;
+                                       out.push_back(nodeSize);
+                                       append_uleb128(fFlags, out);
+                                       append_uleb128(fOther, out);
+                                       out.push_back(0);
+                               }
+                       }
+                       else if ( fFlags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER ) {
+                               // nodes with export info: size, flags, address, other
+                               uint32_t nodeSize = uleb128_size(fFlags) + uleb128_size(fAddress) + uleb128_size(fOther);
+                               out.push_back(nodeSize);
+                               append_uleb128(fFlags, out);
+                               append_uleb128(fAddress, out);
+                               append_uleb128(fOther, out);
+                       }
+                       else {
+                               // nodes with export info: size, flags, address
+                               uint32_t nodeSize = uleb128_size(fFlags) + uleb128_size(fAddress);
+                               out.push_back(nodeSize);
+                               append_uleb128(fFlags, out);
+                               append_uleb128(fAddress, out);
+                       }
                }
                else {
                }
                else {
-                       // no export info
+                       // no export info uleb128 of zero is one byte of zero
                        out.push_back(0);
                }
                // write number of children
                        out.push_back(0);
                }
                // write number of children
@@ -215,22 +267,25 @@ struct Entry
        const char*             name;
        uint64_t                address;
        uint64_t                flags;
        const char*             name;
        uint64_t                address;
        uint64_t                flags;
+       uint64_t                other;
+       const char*             importName;
 };
 
 
 };
 
 
-inline void makeTrie(const std::vector<Entry>& input, std::vector<uint8_t>& output)
+
+inline void makeTrie(const std::vector<Entry>& entries, std::vector<uint8_t>& output)
 {
        Node start(strdup(""));
        
        // make nodes for all exported symbols
 {
        Node start(strdup(""));
        
        // make nodes for all exported symbols
-       for (std::vector<Entry>::const_iterator it = input.begin(); it != input.end(); ++it) {
-               start.addSymbol(it->name, it->address, it->flags);
+       for (std::vector<Entry>::const_iterator it = entries.begin(); it != entries.end(); ++it) {
+               start.addSymbol(it->name, it->address, it->flags, it->other, it->importName);
        }
 
        // create vector of nodes
        std::vector<Node*> orderedNodes;
        }
 
        // create vector of nodes
        std::vector<Node*> orderedNodes;
-       orderedNodes.reserve(input.size()*2);
-       for (std::vector<Entry>::const_iterator it = input.begin(); it != input.end(); ++it) {
+       orderedNodes.reserve(entries.size()*2);
+       for (std::vector<Entry>::const_iterator it = entries.begin(); it != entries.end(); ++it) {
                start.addOrderedNodes(it->name, orderedNodes);
        }
        
                start.addOrderedNodes(it->name, orderedNodes);
        }
        
@@ -262,18 +317,31 @@ struct EntryWithOffset
 
 
 static inline void processExportNode(const uint8_t* const start, const uint8_t* p, const uint8_t* const end, 
 
 
 static inline void processExportNode(const uint8_t* const start, const uint8_t* p, const uint8_t* const end, 
-                                                                                       char* cummulativeString, int curStrOffset, std::vector<EntryWithOffset>& output) 
+                                                                       char* cummulativeString, int curStrOffset, 
+                                                                       std::vector<EntryWithOffset>& output) 
 {
        if ( p >= end )
 {
        if ( p >= end )
-               throwf("malformed trie, node %p outside trie (%p -> %p)", p, start, end);
-       const uint8_t terminalSize = *p++;
+               throw "malformed trie, node past end";
+       const uint8_t terminalSize = read_uleb128(p, end);
        const uint8_t* children = p + terminalSize;
        if ( terminalSize != 0 ) {
                EntryWithOffset e;
                e.nodeOffset = p-start;
                e.entry.name = strdup(cummulativeString);
                e.entry.flags = read_uleb128(p, end);
        const uint8_t* children = p + terminalSize;
        if ( terminalSize != 0 ) {
                EntryWithOffset e;
                e.nodeOffset = p-start;
                e.entry.name = strdup(cummulativeString);
                e.entry.flags = read_uleb128(p, end);
-               e.entry.address = read_uleb128(p, end); 
+               if ( e.entry.flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
+                       e.entry.address = 0;
+                       e.entry.other = read_uleb128(p, end); // dylib ordinal
+                       e.entry.importName = (char*)p;
+               }
+               else {
+                       e.entry.address = read_uleb128(p, end); 
+                       if ( e.entry.flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER )
+                               e.entry.other = read_uleb128(p, end); 
+                       else
+                               e.entry.other = 0;
+                       e.entry.importName = NULL;
+               }
                output.push_back(e);
        }
        const uint8_t childrenCount = *children++;
                output.push_back(e);
        }
        const uint8_t childrenCount = *children++;
@@ -296,7 +364,6 @@ inline void parseTrie(const uint8_t* start, const uint8_t* end, std::vector<Entr
        // empty trie has no entries
        if ( start == end )
                return;
        // empty trie has no entries
        if ( start == end )
                return;
-       
        char cummulativeString[4000];
        std::vector<EntryWithOffset> entries;
        processExportNode(start, start, end, cummulativeString, 0, entries);
        char cummulativeString[4000];
        std::vector<EntryWithOffset> entries;
        processExportNode(start, start, end, cummulativeString, 0, entries);
index ea0329b410cebc192695aa10cc76570df76a9357..43ab45a6dac98aadc0ced69e1a2880ce83eef9b9 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
- * Copyright (c) 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -67,8 +67,8 @@ struct objc_class {
     uint32_t ivar_layout;    // const char *
     uint32_t ext;            // struct objc_class_ext *
     
     uint32_t ivar_layout;    // const char *
     uint32_t ext;            // struct objc_class_ext *
     
-    struct objc_class<A> *getIsa(SharedCache<A> *cache) const INLINE { return (struct objc_class<A> *)cache->mappedCacheAddressForAddress(A::P::E::get32(isa)); }
-    struct objc_method_list<A> *getMethodList(SharedCache<A> *cache) const INLINE { return (struct objc_method_list<A> *)cache->mappedCacheAddressForAddress(A::P::E::get32(methodList)); }
+    struct objc_class<A> *getIsa(SharedCache<A> *cache) const INLINE { return (struct objc_class<A> *)cache->mappedAddressForVMAddress(A::P::E::get32(isa)); }
+    struct objc_method_list<A> *getMethodList(SharedCache<A> *cache) const INLINE { return (struct objc_method_list<A> *)cache->mappedAddressForVMAddress(A::P::E::get32(methodList)); }
 };
 
 template <typename A>
 };
 
 template <typename A>
@@ -81,8 +81,8 @@ struct objc_category {
     uint32_t size;                 // uint32_t
     uint32_t instance_properties;  // struct objc_property_list *
     
     uint32_t size;                 // uint32_t
     uint32_t instance_properties;  // struct objc_property_list *
     
-    struct objc_method_list<A> *getInstanceMethods(SharedCache<A> *cache) const INLINE { return (struct objc_method_list<A> *)cache->mappedCacheAddressForAddress(A::P::E::get32(instance_methods)); }
-    struct objc_method_list<A> *getClassMethods(SharedCache<A> *cache) const INLINE { return (struct objc_method_list<A> *)cache->mappedCacheAddressForAddress(A::P::E::get32(class_methods)); }
+    struct objc_method_list<A> *getInstanceMethods(SharedCache<A> *cache) const INLINE { return (struct objc_method_list<A> *)cache->mappedAddressForVMAddress(A::P::E::get32(instance_methods)); }
+    struct objc_method_list<A> *getClassMethods(SharedCache<A> *cache) const INLINE { return (struct objc_method_list<A> *)cache->mappedAddressForVMAddress(A::P::E::get32(class_methods)); }
 };
 
 template <typename A>
 };
 
 template <typename A>
@@ -95,8 +95,8 @@ struct objc_symtab {
     
     uint16_t getClassCount(void) const INLINE { return A::P::E::get16(cls_def_cnt); }
     uint16_t getCategoryCount(void) const INLINE { return A::P::E::get16(cat_def_cnt); }
     
     uint16_t getClassCount(void) const INLINE { return A::P::E::get16(cls_def_cnt); }
     uint16_t getCategoryCount(void) const INLINE { return A::P::E::get16(cat_def_cnt); }
-    struct objc_class<A> *getClass(SharedCache<A> *cache, int index) const INLINE { return (struct objc_class<A> *)cache->mappedCacheAddressForAddress(A::P::E::get32(defs[index])); }
-    struct objc_category<A> *getCategory(SharedCache<A> *cache, int index) const INLINE { return (struct objc_category<A> *)cache->mappedCacheAddressForAddress(A::P::E::get32(defs[getClassCount() + index])); }
+    struct objc_class<A> *getClass(SharedCache<A> *cache, int index) const INLINE { return (struct objc_class<A> *)cache->mappedAddressForVMAddress(A::P::E::get32(defs[index])); }
+    struct objc_category<A> *getCategory(SharedCache<A> *cache, int index) const INLINE { return (struct objc_category<A> *)cache->mappedAddressForVMAddress(A::P::E::get32(defs[getClassCount() + index])); }
 };
 
 template <typename A>
 };
 
 template <typename A>
@@ -106,7 +106,7 @@ struct objc_module {
     uint32_t name;     // char*
     uint32_t symtab;   // Symtab
     
     uint32_t name;     // char*
     uint32_t symtab;   // Symtab
     
-    struct objc_symtab<A> *getSymtab(SharedCache<A> *cache) const INLINE { return (struct objc_symtab<A> *)cache->mappedCacheAddressForAddress(A::P::E::get32(symtab)); }
+    struct objc_symtab<A> *getSymtab(SharedCache<A> *cache) const INLINE { return (struct objc_symtab<A> *)cache->mappedAddressForVMAddress(A::P::E::get32(symtab)); }
 };
 
 template <typename A>
 };
 
 template <typename A>
@@ -134,8 +134,8 @@ struct objc_protocol {
     uint32_t instance_methods;  // struct objc_method_description_list *
     uint32_t class_methods;     // struct objc_method_description_list *
     
     uint32_t instance_methods;  // struct objc_method_description_list *
     uint32_t class_methods;     // struct objc_method_description_list *
     
-    struct objc_method_description_list<A> *getInstanceMethodDescriptions(SharedCache<A> *cache) const INLINE { return (struct objc_method_description_list<A> *)cache->mappedCacheAddressForAddress(A::P::E::get32(instance_methods)); }
-    struct objc_method_description_list<A> *getClassMethodDescriptions(SharedCache<A> *cache) const INLINE { return (struct objc_method_description_list<A> *)cache->mappedCacheAddressForAddress(A::P::E::get32(class_methods)); }
+    struct objc_method_description_list<A> *getInstanceMethodDescriptions(SharedCache<A> *cache) const INLINE { return (struct objc_method_description_list<A> *)cache->mappedAddressForVMAddress(A::P::E::get32(instance_methods)); }
+    struct objc_method_description_list<A> *getClassMethodDescriptions(SharedCache<A> *cache) const INLINE { return (struct objc_method_description_list<A> *)cache->mappedAddressForVMAddress(A::P::E::get32(class_methods)); }
 };
 
 
 };
 
 
@@ -227,7 +227,7 @@ public:
             header->getSection("__OBJC", "__image_info");
         if (imageInfoSection) {
             objc_image_info<A> *info = (objc_image_info<A> *)
             header->getSection("__OBJC", "__image_info");
         if (imageInfoSection) {
             objc_image_info<A> *info = (objc_image_info<A> *)
-                cache->mappedCacheAddressForAddress(imageInfoSection->addr());
+                cache->mappedAddressForVMAddress(imageInfoSection->addr());
             info->setSelectorsPrebound();
         }
     }
             info->setSelectorsPrebound();
         }
     }
index ef200a5a0d738ad147287e755b56ede5e43eae81..9dc9b90adcad59e5de6a99df4658d0047a581f5f 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
- * Copyright (c) 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
 
  * @APPLE_LICENSE_HEADER_END@
  */
 
+#include <iterator>
+#include <deque>
+
+// iterate an entsize-based list
+// typedef entsize_iterator< A, type_t<A>, type_list_t<A> > type_iterator;
+template <typename A, typename T, typename Tlist>
+struct entsize_iterator {
+    uint32_t entsize;
+    uint32_t index;  // keeping track of this saves a divide in operator-
+    T* current;    
+
+    typedef std::random_access_iterator_tag iterator_category;
+    typedef T value_type;
+    typedef ptrdiff_t difference_type;
+    typedef T* pointer;
+    typedef T& reference;
+    
+    entsize_iterator() { } 
+    
+    entsize_iterator(const Tlist& list, uint32_t start = 0)
+        : entsize(list.getEntsize()), index(start), current(&list.get(start)) 
+    { }
+    
+    const entsize_iterator<A,T,Tlist>& operator += (ptrdiff_t count) {
+        current = (T*)((uint8_t *)current + count*entsize);
+        index += count;
+        return *this;
+    }
+    const entsize_iterator<A,T,Tlist>& operator -= (ptrdiff_t count) {
+        current = (T*)((uint8_t *)current - count*entsize);
+        index -= count;
+        return *this;
+    }
+    const entsize_iterator<A,T,Tlist> operator + (ptrdiff_t count) const {
+        return entsize_iterator(*this) += count;
+    }
+    const entsize_iterator<A,T,Tlist> operator - (ptrdiff_t count) const {
+        return entsize_iterator(*this) -= count;
+    }
+    
+    entsize_iterator<A,T,Tlist>& operator ++ () { *this += 1; return *this; }
+    entsize_iterator<A,T,Tlist>& operator -- () { *this -= 1; return *this; }
+    entsize_iterator<A,T,Tlist> operator ++ (int) { 
+        entsize_iterator<A,T,Tlist> result(*this); *this += 1; return result; 
+    }
+    entsize_iterator<A,T,Tlist> operator -- (int) { 
+        entsize_iterator<A,T,Tlist> result(*this); *this -= 1; return result; 
+    }
+    
+    ptrdiff_t operator - (const entsize_iterator<A,T,Tlist>& rhs) const {
+        return (ptrdiff_t)this->index - (ptrdiff_t)rhs.index;
+    }
+    
+    T& operator * () { return *current; }
+    const T& operator * () const { return *current; }
+    T& operator -> () { return *current; }
+    const T& operator -> () const { return *current; }
+    
+    operator T& () const { return *current; }
+    
+    bool operator == (const entsize_iterator<A,T,Tlist>& rhs) {
+        return this->current == rhs.current;
+    }
+    bool operator != (const entsize_iterator<A,T,Tlist>& rhs) {
+        return this->current != rhs.current;
+    }
+    
+    bool operator < (const entsize_iterator<A,T,Tlist>& rhs) {
+        return this->current < rhs.current;
+    }        
+    bool operator > (const entsize_iterator<A,T,Tlist>& rhs) {
+        return this->current > rhs.current;
+    }
+
+    
+    static void overwrite(entsize_iterator<A,T,Tlist>& dst, const Tlist* srcList)
+    {
+        entsize_iterator<A,T,Tlist> src;
+        uint32_t ee = srcList->getEntsize();
+        for (src = srcList->begin(); src != srcList->end(); ++src) {
+            memcpy(&*dst, &*src, ee);
+            ++dst;
+        }
+    }
+};
+  
+template <typename A> class objc_method_list_t;  // forward reference
+
 template <typename A>
 class objc_method_t {
     typename A::P::uint_t name;   // SEL
     typename A::P::uint_t types;  // const char *
     typename A::P::uint_t imp;    // IMP
 template <typename A>
 class objc_method_t {
     typename A::P::uint_t name;   // SEL
     typename A::P::uint_t types;  // const char *
     typename A::P::uint_t imp;    // IMP
-
+       friend class objc_method_list_t<A>;
 public:
     typename A::P::uint_t getName() const { return A::P::getP(name); }
     void setName(typename A::P::uint_t newName) { A::P::setP(name, newName); }
 public:
     typename A::P::uint_t getName() const { return A::P::getP(name); }
     void setName(typename A::P::uint_t newName) { A::P::setP(name, newName); }
+
+    struct SortBySELAddress : 
+        public std::binary_function<const objc_method_t<A>&, 
+                                    const objc_method_t<A>&, bool>
+    {
+        bool operator() (const objc_method_t<A>& lhs, 
+                         const objc_method_t<A>& rhs)
+        {
+            return lhs.getName() < rhs.getName();
+        }
+    };
 };
 
 template <typename A>
 };
 
 template <typename A>
@@ -39,14 +138,67 @@ class objc_method_list_t {
     uint32_t count;
     objc_method_t<A> first;
 
     uint32_t count;
     objc_method_t<A> first;
 
-       uint32_t getEntsize() const { return A::P::E::get32(entsize) & ~(uint32_t)3; }
+    // use newMethodList instead
+    void* operator new (size_t) { return NULL; }
+    void* operator new (size_t, void* buf) { return buf; }
 
 public:
 
 public:
-    typename A::P::uint_t getCount() const { return A::P::E::get32(count); }
 
 
-    objc_method_t<A>& get(typename A::P::uint_t i) const { return *(objc_method_t<A> *)((uint8_t *)&first + i * getEntsize()); }
+    typedef entsize_iterator< A, objc_method_t<A>, objc_method_list_t<A> > method_iterator;
+
+    uint32_t getCount() const { return A::P::E::get32(count); }
+
+       uint32_t getEntsize() const {return A::P::E::get32(entsize)&~(uint32_t)3;}
+
+    objc_method_t<A>& get(uint32_t i) const { return *(objc_method_t<A> *)((uint8_t *)&first + i * getEntsize()); }
+
+    uint32_t byteSize() const { 
+        return byteSizeForCount(getCount(), getEntsize()); 
+    }
+
+    static uint32_t byteSizeForCount(uint32_t c, uint32_t e = sizeof(objc_method_t<A>)) { 
+        return sizeof(objc_method_list_t<A>) - sizeof(objc_method_t<A>) + c*e;
+    }
+
+    method_iterator begin() { return method_iterator(*this, 0); }
+    method_iterator end() { return method_iterator(*this, getCount()); }
+    const method_iterator begin() const { return method_iterator(*this, 0); }
+    const method_iterator end() const { return method_iterator(*this, getCount()); }
 
     void setFixedUp() { A::P::E::set32(entsize, getEntsize() | 3); }
 
     void setFixedUp() { A::P::E::set32(entsize, getEntsize() | 3); }
+
+       void getPointers(std::set<void*>& pointersToRemove) {
+               for(method_iterator it = begin(); it != end(); ++it) {
+                       objc_method_t<A>& entry = *it;
+                       pointersToRemove.insert(&(entry.name));
+                       pointersToRemove.insert(&(entry.types));
+                       pointersToRemove.insert(&(entry.imp));
+               }
+       }
+       
+       static void addPointers(uint8_t* methodList, std::vector<void*>& pointersToAdd) {
+               objc_method_list_t<A>* mlist = (objc_method_list_t<A>*)methodList;
+               for(method_iterator it = mlist->begin(); it != mlist->end(); ++it) {
+                       objc_method_t<A>& entry = *it;
+                       pointersToAdd.push_back(&(entry.name));
+                       pointersToAdd.push_back(&(entry.types));
+                       pointersToAdd.push_back(&(entry.imp));
+               }
+       }
+
+    static objc_method_list_t<A>* newMethodList(size_t newCount, uint32_t newEntsize) {
+        void *buf = ::calloc(byteSizeForCount(newCount, newEntsize), 1);
+        return new (buf) objc_method_list_t<A>(newCount, newEntsize);
+    }
+
+    void operator delete(void * p) { 
+        ::free(p); 
+    }
+
+    objc_method_list_t(uint32_t newCount, 
+                       uint32_t newEntsize = sizeof(objc_method_t<A>))
+        : entsize(newEntsize), count(newCount) 
+    { }
 };
 
 template <typename A>
 };
 
 template <typename A>
@@ -64,8 +216,128 @@ class objc_ivar_list_t {
     uint32_t count;
     objc_ivar_t<A> first;
 
     uint32_t count;
     objc_ivar_t<A> first;
 
+    // use newIvarList instead
+    void* operator new (size_t) { return NULL; }
+    void* operator new (size_t, void* buf) { return buf; }
+
+public:
+
+    typedef entsize_iterator< A, objc_ivar_t<A>, objc_ivar_list_t<A> > ivar_iterator;
+
+    uint32_t getCount() const { return A::P::E::get32(count); }
+
+       uint32_t getEntsize() const { return A::P::E::get32(entsize); }
+
+    objc_ivar_t<A>& get(typename A::P::pint_t i) const { return *(objc_ivar_t<A> *)((uint8_t *)&first + i * A::P::E::get32(entsize)); }
+
+    uint32_t byteSize() const { 
+        return byteSizeForCount(getCount(), getEntsize()); 
+    }
+
+    static uint32_t byteSizeForCount(uint32_t c, uint32_t e = sizeof(objc_ivar_t<A>)) { 
+        return sizeof(objc_ivar_list_t<A>) - sizeof(objc_ivar_t<A>) + c*e;
+    }
+
+    ivar_iterator begin() { return ivar_iterator(*this, 0); }
+    ivar_iterator end() { return ivar_iterator(*this, getCount()); }
+    const ivar_iterator begin() const { return ivar_iterator(*this, 0); }
+    const ivar_iterator end() const { return ivar_iterator(*this, getCount()); }
+
+    static objc_ivar_list_t<A>* newIvarList(size_t newCount, uint32_t newEntsize) {
+        void *buf = ::calloc(byteSizeForCount(newCount, newEntsize), 1);
+        return new (buf) objc_ivar_list_t<A>(newCount, newEntsize);
+    }
+
+    void operator delete(void * p) { 
+        ::free(p); 
+    }
+
+    objc_ivar_list_t(uint32_t newCount, 
+                         uint32_t newEntsize = sizeof(objc_ivar_t<A>))
+        : entsize(newEntsize), count(newCount) 
+    { }
+
+};
+
+
+template <typename A> class objc_property_list_t; // forward 
+
+template <typename A>
+class objc_property_t {
+    typename A::P::uint_t name;
+    typename A::P::uint_t attributes;
+       friend class objc_property_list_t<A>;
 public:
 public:
-    objc_ivar_t<A>& getIvarAtIndex(typename A::P::pint_t i) const { return *(objc_ivar_t<A> *)((uint8_t *)&first + i * A::P::E::get32(entsize)); }
+    
+    const char * getName(SharedCache<A>* cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); }
+
+    const char * getAttributes(SharedCache<A>* cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(attributes)); }
+};
+
+template <typename A>
+class objc_property_list_t {
+    uint32_t entsize;
+    uint32_t count;
+    objc_property_t<A> first;
+
+    // use newPropertyList instead
+    void* operator new (size_t) { return NULL; }
+    void* operator new (size_t, void* buf) { return buf; }
+
+public:
+
+    typedef entsize_iterator< A, objc_property_t<A>, objc_property_list_t<A> > property_iterator;
+
+    uint32_t getCount() const { return A::P::E::get32(count); }
+
+       uint32_t getEntsize() const { return A::P::E::get32(entsize); }
+
+    objc_property_t<A>& get(uint32_t i) const { return *(objc_property_t<A> *)((uint8_t *)&first + i * getEntsize()); }
+
+    uint32_t byteSize() const { 
+        return byteSizeForCount(getCount(), getEntsize()); 
+    }
+
+    static uint32_t byteSizeForCount(uint32_t c, uint32_t e = sizeof(objc_property_t<A>)) { 
+        return sizeof(objc_property_list_t<A>) - sizeof(objc_property_t<A>) + c*e;
+    }
+
+    property_iterator begin() { return property_iterator(*this, 0); }
+    property_iterator end() { return property_iterator(*this, getCount()); }
+    const property_iterator begin() const { return property_iterator(*this, 0); }
+    const property_iterator end() const { return property_iterator(*this, getCount()); }
+
+       void getPointers(std::set<void*>& pointersToRemove) {
+               for(property_iterator it = begin(); it != end(); ++it) {
+                       objc_property_t<A>& entry = *it;
+                       pointersToRemove.insert(&(entry.name));
+                       pointersToRemove.insert(&(entry.attributes));
+               }
+       }
+
+       static void addPointers(uint8_t* propertyList, std::vector<void*>& pointersToAdd) {
+               objc_property_list_t<A>* plist = (objc_property_list_t<A>*)propertyList;
+               for(property_iterator it = plist->begin(); it != plist->end(); ++it) {
+                       objc_property_t<A>& entry = *it;
+                       pointersToAdd.push_back(&(entry.name));
+                       pointersToAdd.push_back(&(entry.attributes));
+               }
+       }
+
+     static objc_property_list_t<A>* newPropertyList(size_t newCount, uint32_t newEntsize) {
+        void *buf = ::calloc(byteSizeForCount(newCount, newEntsize), 1);
+        return new (buf) objc_property_list_t<A>(newCount, newEntsize);
+    }
+
+    void operator delete(void * p) { 
+        ::free(p); 
+    }
+
+    objc_property_list_t(uint32_t newCount, 
+                         uint32_t newEntsize = sizeof(objc_property_t<A>))
+        : entsize(newEntsize), count(newCount) 
+    { }
+
 };
 
 template <typename A>
 };
 
 template <typename A>
@@ -80,35 +352,85 @@ class objc_protocol_t {
     typename A::P::uint_t instanceProperties;
 
 public:
     typename A::P::uint_t instanceProperties;
 
 public:
-    objc_method_list_t<A> *getInstanceMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedCacheAddressForAddress(A::P::getP(instanceMethods)); }
+    objc_method_list_t<A> *getInstanceMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(instanceMethods)); }
 
 
-    objc_method_list_t<A> *getClassMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedCacheAddressForAddress(A::P::getP(classMethods)); }
+    objc_method_list_t<A> *getClassMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(classMethods)); }
 
 
-    objc_method_list_t<A> *getOptionalInstanceMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedCacheAddressForAddress(A::P::getP(optionalInstanceMethods)); }
+    objc_method_list_t<A> *getOptionalInstanceMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(optionalInstanceMethods)); }
 
 
-    objc_method_list_t<A> *getOptionalClassMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedCacheAddressForAddress(A::P::getP(optionalClassMethods)); }
+    objc_method_list_t<A> *getOptionalClassMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(optionalClassMethods)); }
 
 };
 
 template <typename A>
 class objc_protocol_list_t {
 
 };
 
 template <typename A>
 class objc_protocol_list_t {
-    typename A::P::uint_t count;
-    typename A::P::uint_t list[0];
-};
+    typedef typename A::P::uint_t pint_t;
+    pint_t count;
+    pint_t list[0];
+
+    // use newProtocolList instead
+    void* operator new (size_t) { return NULL; }
+    void* operator new (size_t, void* buf) { return buf; }
+
+public:
+
+    pint_t getCount() const { return A::P::getP(count); }
+
+    objc_protocol_t<A>* get(SharedCache<A>* cache, pint_t i) {
+        return (objc_protocol_t<A>*)cache->mappedAddressForVMAddress(A::P::getP(list[i]));
+    }
+    
+    void overwrite(pint_t& index, const objc_protocol_list_t<A>* src) {
+        pint_t srcCount = src->getCount();
+        memcpy(list+index, src->list, srcCount * sizeof(pint_t));
+        index += srcCount;
+    }
+
+    uint32_t byteSize() const { 
+        return byteSizeForCount(getCount()); 
+    }
+    static uint32_t byteSizeForCount(pint_t c) { 
+        return sizeof(objc_protocol_list_t<A>) + c*sizeof(pint_t);
+    }
 
 
-template < typename P, typename E > 
-struct pad { };
+       void getPointers(std::set<void*>& pointersToRemove) {
+               for(int i=0 ; i < count; ++i) {
+                       pointersToRemove.insert(&list[i]);
+               }
+       }
+
+       static void addPointers(uint8_t* protocolList, std::vector<void*>& pointersToAdd) {
+               objc_protocol_list_t<A>* plist = (objc_protocol_list_t<A>*)protocolList;
+               for(int i=0 ; i < plist->count; ++i) {
+                       pointersToAdd.push_back(&plist->list[i]);
+               }
+       }
+
+    static objc_protocol_list_t<A>* newProtocolList(pint_t newCount) {
+        void *buf = ::calloc(byteSizeForCount(newCount), 1);
+        return new (buf) objc_protocol_list_t<A>(newCount);
+    }
+
+    void operator delete(void * p) { 
+        ::free(p); 
+    }
+
+    objc_protocol_list_t(uint32_t newCount) : count(newCount) { }
+
+};
 
 
-template < typename E >
-struct pad< Pointer64<E>, E > { uint32_t unused; };
 
 template <typename A>
 class objc_class_data_t {
     uint32_t flags;
     uint32_t instanceStart;
 
 template <typename A>
 class objc_class_data_t {
     uint32_t flags;
     uint32_t instanceStart;
-    uint32_t instanceSize;
-    pad<typename A::P, typename A::P::E> reserved;  // ILP32=0 bytes, LP64=4 bytes
-
+    // Note there is 4-bytes of alignment padding between instanceSize and ivarLayout
+    // on 64-bit archs, but no padding on 32-bit archs.
+    // This union is a way to model that.
+    union {
+        uint32_t                instanceSize;
+        typename A::P::uint_t   pad;
+    } instanceSize;
     typename A::P::uint_t ivarLayout;
     typename A::P::uint_t name;
     typename A::P::uint_t baseMethods;
     typename A::P::uint_t ivarLayout;
     typename A::P::uint_t name;
     typename A::P::uint_t baseMethods;
@@ -118,7 +440,37 @@ class objc_class_data_t {
     typename A::P::uint_t baseProperties;
 
 public:
     typename A::P::uint_t baseProperties;
 
 public:
-    objc_method_list_t<A> *getMethodList(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedCacheAddressForAddress(A::P::getP(baseMethods)); }
+    objc_method_list_t<A> *getMethodList(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(baseMethods)); }
+
+    objc_protocol_list_t<A> *getProtocolList(SharedCache<A>* cache) const { return (objc_protocol_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(baseProtocols)); }
+
+    objc_property_list_t<A> *getPropertyList(SharedCache<A>* cache) const { return (objc_property_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(baseProperties)); }
+
+    const char * getName(SharedCache<A>* cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); }
+
+    void setMethodList(SharedCache<A>* cache, objc_method_list_t<A>* mlist) {
+        A::P::setP(baseMethods, cache->VMAddressForMappedAddress(mlist));
+    }
+
+    void setProtocolList(SharedCache<A>* cache, objc_protocol_list_t<A>* protolist) {
+        A::P::setP(baseProtocols, cache->VMAddressForMappedAddress(protolist));
+    }
+    void setPropertyList(SharedCache<A>* cache, objc_property_list_t<A>* proplist) {
+        A::P::setP(baseProperties, cache->VMAddressForMappedAddress(proplist));
+    }
+       
+       void addMethodListPointer(std::vector<void*>& pointersToAdd) {
+               pointersToAdd.push_back(&this->baseMethods);
+       }
+       
+       void addPropertyListPointer(std::vector<void*>& pointersToAdd) {
+               pointersToAdd.push_back(&this->baseProperties);
+       }
+       
+       void addProtocolListPointer(std::vector<void*>& pointersToAdd) {
+               pointersToAdd.push_back(&this->baseProtocols);
+       }
 };
 
 template <typename A>
 };
 
 template <typename A>
@@ -130,11 +482,44 @@ class objc_class_t {
     typename A::P::uint_t data;
 
 public:
     typename A::P::uint_t data;
 
 public:
-    objc_class_t<A> *getIsa(SharedCache<A> *cache) const { return (objc_class_t<A> *)cache->mappedCacheAddressForAddress(A::P::getP(isa)); }
+    objc_class_t<A> *getIsa(SharedCache<A> *cache) const { return (objc_class_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(isa)); }
 
 
-    objc_class_data_t<A> *getData(SharedCache<A>* cache) const { return (objc_class_data_t<A> *)cache->mappedCacheAddressForAddress(A::P::getP(data)); }
+    objc_class_data_t<A> *getData(SharedCache<A>* cache) const { return (objc_class_data_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(data)); }
 
     objc_method_list_t<A> *getMethodList(SharedCache<A>* cache) const { return getData(cache)->getMethodList(cache); }
 
     objc_method_list_t<A> *getMethodList(SharedCache<A>* cache) const { return getData(cache)->getMethodList(cache); }
+
+    objc_protocol_list_t<A> *getProtocolList(SharedCache<A>* cache) const { return getData(cache)->getProtocolList(cache); }
+
+    objc_property_list_t<A> *getPropertyList(SharedCache<A>* cache) const { return getData(cache)->getPropertyList(cache); }
+
+    const char * getName(SharedCache<A>* cache) const { 
+        return getData(cache)->getName(cache);
+    }
+
+    void setMethodList(SharedCache<A>* cache, objc_method_list_t<A>* mlist) {
+        getData(cache)->setMethodList(cache, mlist);
+    }
+
+    void setProtocolList(SharedCache<A>* cache, objc_protocol_list_t<A>* protolist) {
+        getData(cache)->setProtocolList(cache, protolist);
+    }
+
+    void setPropertyList(SharedCache<A>* cache, objc_property_list_t<A>* proplist) {
+        getData(cache)->setPropertyList(cache, proplist);
+    }
+       
+       void addMethodListPointer(SharedCache<A>* cache, std::vector<void*>& pointersToAdd) {
+        getData(cache)->addMethodListPointer(pointersToAdd);
+       }
+       
+       void addPropertyListPointer(SharedCache<A>* cache, std::vector<void*>& pointersToAdd) {
+        getData(cache)->addPropertyListPointer(pointersToAdd);
+       }
+       
+       void addProtocolListPointer(SharedCache<A>* cache, std::vector<void*>& pointersToAdd) {
+        getData(cache)->addProtocolListPointer(pointersToAdd);
+       }
+       
 };
 
 
 };
 
 
@@ -149,9 +534,29 @@ class objc_category_t {
     typename A::P::uint_t instanceProperties;
 
 public:
     typename A::P::uint_t instanceProperties;
 
 public:
-    objc_method_list_t<A> *getInstanceMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedCacheAddressForAddress(A::P::getP(instanceMethods)); }
 
 
-    objc_method_list_t<A> *getClassMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedCacheAddressForAddress(A::P::getP(classMethods)); }
+    const char * getName(SharedCache<A> *cache) const { return (const char *)cache->mappedAddressForVMAddress(A::P::getP(name)); }
+
+    objc_class_t<A> *getClass(SharedCache<A> *cache) const { return (objc_class_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(cls)); }
+
+    objc_method_list_t<A> *getInstanceMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(instanceMethods)); }
+
+    objc_method_list_t<A> *getClassMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(classMethods)); }
+
+    objc_protocol_list_t<A> *getProtocols(SharedCache<A>* cache) const { return (objc_protocol_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(protocols)); }
+    objc_property_list_t<A> *getInstanceProperties(SharedCache<A>* cache) const { return (objc_property_list_t<A> *)cache->mappedAddressForVMAddress(A::P::getP(instanceProperties)); }
+
+       void getPointers(std::set<void*>& pointersToRemove) {
+               pointersToRemove.insert(&name);
+               pointersToRemove.insert(&cls);
+               pointersToRemove.insert(&instanceMethods);
+               pointersToRemove.insert(&classMethods);
+               pointersToRemove.insert(&protocols);
+               pointersToRemove.insert(&instanceProperties);
+       }
+
+
 };
 
 template <typename A>
 };
 
 template <typename A>
@@ -165,38 +570,34 @@ public:
     void setName(typename A::P::uint_t newName) { A::P::setP(sel, newName); }
 };
 
     void setName(typename A::P::uint_t newName) { A::P::setP(sel, newName); }
 };
 
+
+// Call visitor.visitMethodList(mlist) on every method list in a header.
 template <typename A, typename V>
 template <typename A, typename V>
-class SelectorUpdater {
+class MethodListWalker {
 
     typedef typename A::P P;
     typedef typename A::P::uint_t pint_t;
 
 
     typedef typename A::P P;
     typedef typename A::P::uint_t pint_t;
 
-    static void visitMethodList(objc_method_list_t<A> *mlist, V& visitor)
-    {
-        for (pint_t m = 0; m < mlist->getCount(); m++) {
-            pint_t oldValue = mlist->get(m).getName();
-            pint_t newValue = visitor.visit(oldValue);
-            mlist->get(m).setName(newValue);
-        }
-        mlist->setFixedUp();
-    }
+    V& mVisitor;
 
 
-public:
+public: 
+    
+    MethodListWalker(V& visitor) : mVisitor(visitor) { }
 
 
-    static void update(SharedCache<A>* cache, const macho_header<P>* header, 
-                       V& visitor)
-    {
+    void walk(SharedCache<A>* cache, const macho_header<P>* header)
+    {   
         // Method lists in classes
         PointerSection<A, objc_class_t<A> *> 
             classes(cache, header, "__DATA", "__objc_classlist");
         // Method lists in classes
         PointerSection<A, objc_class_t<A> *> 
             classes(cache, header, "__DATA", "__objc_classlist");
+            
         for (pint_t i = 0; i < classes.count(); i++) {
             objc_class_t<A> *cls = classes.get(i);
             objc_method_list_t<A> *mlist;
             if ((mlist = cls->getMethodList(cache))) {
         for (pint_t i = 0; i < classes.count(); i++) {
             objc_class_t<A> *cls = classes.get(i);
             objc_method_list_t<A> *mlist;
             if ((mlist = cls->getMethodList(cache))) {
-                visitMethodList(mlist, visitor);
+                mVisitor.visitMethodList(mlist);
             }
             if ((mlist = cls->getIsa(cache)->getMethodList(cache))) {
             }
             if ((mlist = cls->getIsa(cache)->getMethodList(cache))) {
-                visitMethodList(mlist, visitor);
+                mVisitor.visitMethodList(mlist);
             }
         }
         
             }
         }
         
@@ -207,10 +608,10 @@ public:
             objc_category_t<A> *cat = cats.get(i);
             objc_method_list_t<A> *mlist;
             if ((mlist = cat->getInstanceMethods(cache))) {
             objc_category_t<A> *cat = cats.get(i);
             objc_method_list_t<A> *mlist;
             if ((mlist = cat->getInstanceMethods(cache))) {
-                visitMethodList(mlist, visitor);
+                mVisitor.visitMethodList(mlist);
             }
             if ((mlist = cat->getClassMethods(cache))) {
             }
             if ((mlist = cat->getClassMethods(cache))) {
-                visitMethodList(mlist, visitor);
+                mVisitor.visitMethodList(mlist);
             }
         }
 
             }
         }
 
@@ -221,25 +622,59 @@ public:
             objc_protocol_t<A> *proto = protocols.get(i);
             objc_method_list_t<A> *mlist;
             if ((mlist = proto->getInstanceMethods(cache))) {
             objc_protocol_t<A> *proto = protocols.get(i);
             objc_method_list_t<A> *mlist;
             if ((mlist = proto->getInstanceMethods(cache))) {
-                visitMethodList(mlist, visitor);
+                mVisitor.visitMethodList(mlist);
             }
             if ((mlist = proto->getClassMethods(cache))) {
             }
             if ((mlist = proto->getClassMethods(cache))) {
-                visitMethodList(mlist, visitor);
+                mVisitor.visitMethodList(mlist);
             }
             if ((mlist = proto->getOptionalInstanceMethods(cache))) {
             }
             if ((mlist = proto->getOptionalInstanceMethods(cache))) {
-                visitMethodList(mlist, visitor);
+                mVisitor.visitMethodList(mlist);
             }
             if ((mlist = proto->getOptionalClassMethods(cache))) {
             }
             if ((mlist = proto->getOptionalClassMethods(cache))) {
-                visitMethodList(mlist, visitor);
+                mVisitor.visitMethodList(mlist);
             }
         }
             }
         }
+    }
+};
 
 
+
+// Update selector references. The visitor performs recording and uniquing.
+template <typename A, typename V>
+class SelectorOptimizer {
+
+    typedef typename A::P P;
+    typedef typename A::P::uint_t pint_t;
+
+    V& mVisitor;
+
+    friend class MethodListWalker< A, SelectorOptimizer<A,V> >;
+    void visitMethodList(objc_method_list_t<A> *mlist)
+    {
+        // Gather selectors. Update method names.
+        for (pint_t m = 0; m < mlist->getCount(); m++) {
+            pint_t oldValue = mlist->get(m).getName();
+            pint_t newValue = mVisitor.visit(oldValue);
+            mlist->get(m).setName(newValue);
+        }
+        // Do not setFixedUp: the methods are not yet sorted.
+    }
+
+public:
+
+    SelectorOptimizer(V& visitor) : mVisitor(visitor) { }
+
+    void optimize(SharedCache<A>* cache, const macho_header<P>* header)
+    {
+        // method lists of all kinds
+        MethodListWalker< A, SelectorOptimizer<A,V> > mw(*this);
+        mw.walk(cache, header);
+        
         // @selector references
         PointerSection<A, const char *> 
             selrefs(cache, header, "__DATA", "__objc_selrefs");
         for (pint_t i = 0; i < selrefs.count(); i++) {
             pint_t oldValue = selrefs.getUnmapped(i);
         // @selector references
         PointerSection<A, const char *> 
             selrefs(cache, header, "__DATA", "__objc_selrefs");
         for (pint_t i = 0; i < selrefs.count(); i++) {
             pint_t oldValue = selrefs.getUnmapped(i);
-            pint_t newValue = visitor.visit(oldValue);
+            pint_t newValue = mVisitor.visit(oldValue);
             selrefs.set(i, newValue);
         }
 
             selrefs.set(i, newValue);
         }
 
@@ -249,7 +684,7 @@ public:
         for (pint_t i = 0; i < msgrefs.count(); i++) {
             objc_message_ref_t<A>& msg = msgrefs.get(i);
             pint_t oldValue = msg.getName();
         for (pint_t i = 0; i < msgrefs.count(); i++) {
             objc_message_ref_t<A>& msg = msgrefs.get(i);
             pint_t oldValue = msg.getName();
-            pint_t newValue = visitor.visit(oldValue);
+            pint_t newValue = mVisitor.visit(oldValue);
             msg.setName(newValue);
         }
 
             msg.setName(newValue);
         }
 
@@ -258,8 +693,562 @@ public:
             header->getSection("__DATA", "__objc_imageinfo");
         if (imageInfoSection) {
             objc_image_info<A> *info = (objc_image_info<A> *)
             header->getSection("__DATA", "__objc_imageinfo");
         if (imageInfoSection) {
             objc_image_info<A> *info = (objc_image_info<A> *)
-                cache->mappedCacheAddressForAddress(imageInfoSection->addr());
+                cache->mappedAddressForVMAddress(imageInfoSection->addr());
             info->setSelectorsPrebound();
         }
     }
 };
             info->setSelectorsPrebound();
         }
     }
 };
+
+
+// Sort methods in place by selector.
+template <typename A>
+class MethodListSorter {
+
+    typedef typename A::P P;
+    typedef typename A::P::uint_t pint_t;
+
+    friend class MethodListWalker<A, MethodListSorter<A> >;
+    void visitMethodList(objc_method_list_t<A> *mlist)
+    {
+        typename objc_method_t<A>::SortBySELAddress sorter;
+        std::stable_sort(mlist->begin(), mlist->end(), sorter);
+        mlist->setFixedUp();
+    }
+
+public:
+
+    void optimize(SharedCache<A>* cache, macho_header<P>* header)
+    {
+        MethodListWalker<A, MethodListSorter<A> > mw(*this);
+        mw.walk(cache, header);
+    }
+};
+
+
+// Attach categories to classes in the same framework. 
+// Merge method and protocol and property lists.
+template <typename A>
+class CategoryAttacher {
+
+    typedef typename A::P P;
+    typedef typename A::P::uint_t pint_t;
+
+    uint8_t *mBytes;
+    ssize_t mBytesFree;
+    ssize_t mBytesUsed;
+
+    size_t mCategoriesAttached;
+
+    bool segmentContainsPointer(SharedCache<A>* cache, 
+                                const macho_segment_command<P>* seg, void *ptr)
+    {
+        if (!seg) return false;
+        void *start = (void*)
+            cache->mappedAddressForVMAddress(seg->vmaddr());
+        void *end   = (uint8_t *)start + seg->filesize();
+        return (ptr >= start  &&  ptr < end);
+    }
+
+    bool headerContainsPointer(SharedCache<A>* cache, 
+                               macho_header<P>* header, void *ptr)
+    {
+        return 
+            segmentContainsPointer(cache, header->getSegment("__DATA"), ptr) ||
+            segmentContainsPointer(cache, header->getSegment("__TEXT"), ptr) ||
+            segmentContainsPointer(cache, header->getSegment("__OBJC"), ptr);
+    }
+
+    struct pointer_hash {
+        size_t operator () (void* ptr) const { 
+            return __gnu_cxx::hash<long>()((long)ptr); 
+        }
+    };
+
+    typedef std::deque<objc_category_t<A>*> CategoryList;
+    typedef std::vector<uint64_t> CategoryRefs;
+
+    struct ClassChanges {
+        CategoryList categories;
+        CategoryRefs catrefs;
+        
+        objc_method_list_t<A>* instanceMethods;
+        objc_method_list_t<A>* classMethods;
+        objc_protocol_list_t<A>* protocols;
+        objc_property_list_t<A>* instanceProperties;
+
+        ClassChanges() 
+            : instanceMethods(NULL), classMethods(NULL), 
+              protocols(NULL), instanceProperties(NULL)
+        { }
+
+        ~ClassChanges() { 
+            if (instanceMethods) delete instanceMethods;
+            if (classMethods) delete classMethods;
+            if (protocols) delete protocols;
+            if (instanceProperties) delete instanceProperties;
+        }
+    };
+
+    typedef __gnu_cxx::hash_map<objc_class_t<A>*, ClassChanges, pointer_hash> ClassMap;
+
+    class RangeArray {
+        typedef std::pair<uint8_t*,uint32_t> Range;
+        std::deque<Range> ranges;
+
+        class SizeFits {
+        private:
+            uint32_t mSize;
+        public:
+            SizeFits(uint32_t size) : mSize(size) { } 
+            bool operator() (const Range& r) { 
+                return r.second >= mSize;
+            }
+        };
+
+        struct AddressComp {
+            bool operator() (const Range& lhs, const Range& rhs) {
+                return (lhs.first < rhs.first);
+            }
+        };
+    public:
+        RangeArray() { }
+        void add(void* p, uint32_t size) {
+            add(Range((uint8_t *)p, size));
+        }
+        void add(const Range& r) {
+            // find insertion point
+            std::deque<Range>::iterator iter;
+            iter = upper_bound(ranges.begin(), ranges.end(), r, AddressComp());
+            // coalesce
+            // fixme doesn't fully coalesce if new range exactly fills a gap
+            if (iter != ranges.begin()) {
+                std::deque<Range>::iterator prev = iter - 1;
+                if ((*prev).first + (*prev).second == r.first) {
+                    (*prev).second += r.second;
+                    return;
+                }
+            }
+            if (iter != ranges.end()  &&  iter+1 != ranges.end()) {
+                std::deque<Range>::iterator next = iter + 1;
+                if (r.first + r.second == (*next).first) {
+                    (*next).second += r.second;
+                    (*next).first = r.first;
+                    return;
+                }
+            }
+            ranges.insert(iter, r);
+        }
+
+        uint8_t* remove(uint32_t size) {
+            // first-fit search
+            // this saves 50-75% of space overhead; 
+            // a better algorithm might do better
+
+            std::deque<Range>::iterator iter;
+            iter = find_if(ranges.begin(), ranges.end(), SizeFits(size));
+            if (iter == ranges.end()) {
+                return NULL;
+            }
+
+            Range& found = *iter;
+            uint8_t *result = found.first;
+            if (found.second > size) {
+                // keep leftovers
+                found.first += size;
+                found.second -= size;
+            } else {
+                ranges.erase(iter);
+            }
+
+            return result;
+        }
+    };
+
+    void copyMethods(typename objc_method_list_t<A>::method_iterator& dst, 
+                     const objc_method_list_t<A>* srcList)
+    {
+        objc_method_list_t<A>::method_iterator::
+            overwrite(dst, srcList);
+    }
+
+    void copyProperties(typename objc_property_list_t<A>::property_iterator& dst, 
+                        const objc_property_list_t<A>* srcList)
+    {
+        objc_property_list_t<A>::property_iterator::
+            overwrite(dst, srcList);
+    }
+
+    void copyProtocols(objc_protocol_list_t<A>* dst, pint_t& dstIndex,
+                       const objc_protocol_list_t<A>* src)
+    {
+        dst->overwrite(dstIndex, src);
+    }
+
+       class InSet
+       {
+       public:
+               InSet(std::set<void*>& deadPointers) : _deadPointers(deadPointers) {}
+
+               bool operator()(void* ptr) const {
+                       return ( _deadPointers.count(ptr) != 0 );
+               }
+
+       private:
+               std::set<void*>& _deadPointers;
+       };
+
+public:
+
+    CategoryAttacher(uint8_t *bytes, ssize_t bytesFree) 
+        : mBytes(bytes), mBytesFree(bytesFree)
+        , mBytesUsed(0), mCategoriesAttached(0) 
+    { }
+
+    size_t count() const { return mCategoriesAttached; }
+
+    const char *optimize(SharedCache<A>* cache, macho_header<P>* header, std::vector<void*>& pointersInData)
+    {
+        // Build class=>cateories mapping.
+        // Disregard target classes that aren't in this binary.
+
+        ClassMap map;
+
+               PointerSection<A, objc_category_t<A> *> 
+            nlcatsect(cache, header, "__DATA", "__objc_nlcatlist");
+        PointerSection<A, objc_category_t<A> *> 
+            catsect(cache, header, "__DATA", "__objc_catlist");
+        for (pint_t i = 0; i < catsect.count(); i++) {
+            objc_category_t<A> *cat = catsect.get(i);
+            objc_class_t<A> *cls = cat->getClass(cache);
+            if (!cls) continue;
+            if (!headerContainsPointer(cache, header, cls)) continue;
+                       if ( nlcatsect.count() !=0 ) {
+                               // don't optimize categories also in __objc_nlcatlist
+                               bool alsoInNlcatlist = false;
+                               for (pint_t nli = 0; nli < nlcatsect.count(); nli++) {
+                                       if ( nlcatsect.get(nli) == cat ) {
+                                               //fprintf(stderr, "skipping cat in __objc_nlcatlist for mh=%p\n", header);
+                                               alsoInNlcatlist = true;
+                                               break;
+                                       }
+                               }
+                               if ( alsoInNlcatlist ) 
+                                       continue;
+                       }
+
+            // The LAST category found is the FIRST to be processed later.
+            map[cls].categories.push_front(cat);
+
+            // We don't care about the category reference order.
+            map[cls].catrefs.push_back(i);
+        }
+
+        if (map.size() == 0) {
+            // No attachable categories.
+            return NULL;
+        }
+
+        // Process each class.
+        // Each class is all-or-nothing: either all of its categories 
+        // are attached successfully, or none of them are. This preserves 
+        // cache validity if we run out of space for more reallocations.
+
+        // unusedMemory stores memory ranges evacuated by now-unused metadata.
+        // It is available for re-use by other newly-added metadata.
+        // fixme could packing algorithm be improved?
+        RangeArray unusedMemory;
+
+        ssize_t reserve = 0;
+
+        // First: build new aggregated lists on the heap.
+        // Require enough space in mBytes for all of it.
+
+               std::set<void*> pointersToRemove;
+        for (typename ClassMap::iterator i = map.begin(); 
+             i != map.end(); 
+             ++i) 
+        {
+            objc_class_t<A>* cls = i->first;
+            objc_class_t<A>* meta = cls->getIsa(cache);
+            ClassChanges& changes = i->second;
+            CategoryList& cats = changes.categories;
+
+            // Count memory needed for all categories on this class.
+
+            uint32_t methodEntsize = 0;
+            uint32_t propertyEntsize = 0;
+            objc_method_list_t<A>* mlist;
+            objc_property_list_t<A>* proplist;
+            objc_protocol_list_t<A>* protolist;
+            uint32_t instanceMethodsCount = 0;
+            uint32_t classMethodsCount = 0;
+            uint32_t instancePropertyCount = 0;
+            pint_t protocolCount = 0;
+            bool addedInstanceMethods = false;
+            bool addedClassMethods = false;
+            bool addedInstanceProperties = false;
+            bool addedProtocols = false;
+
+            mlist = cls->getMethodList(cache);
+            if (mlist) {
+                instanceMethodsCount = mlist->getCount();
+                methodEntsize = 
+                    std::max(methodEntsize, mlist->getEntsize());
+            }
+
+            mlist = meta->getMethodList(cache);
+            if (mlist) {
+                classMethodsCount = mlist->getCount();
+                methodEntsize = 
+                    std::max(methodEntsize, mlist->getEntsize());
+            }
+
+            proplist = cls->getPropertyList(cache);
+            if (proplist) {
+                instancePropertyCount = proplist->getCount();
+                propertyEntsize = 
+                    std::max(propertyEntsize, proplist->getEntsize());
+            }
+
+            protolist = cls->getProtocolList(cache);
+            if (protolist) {
+                protocolCount = protolist->getCount();
+            }
+
+            typename CategoryList::iterator j;
+            for (j = cats.begin(); j != cats.end(); ++j) {
+                objc_category_t<A>* cat = *j;
+
+                mlist = cat->getInstanceMethods(cache);
+                if (mlist  &&  mlist->getCount() > 0) {
+                    addedInstanceMethods = true;
+                    instanceMethodsCount += mlist->getCount();
+                    methodEntsize = 
+                        std::max(methodEntsize, mlist->getEntsize());
+                }
+
+                mlist = cat->getClassMethods(cache);
+                if (mlist  &&  mlist->getCount() > 0) {
+                    addedClassMethods = true;
+                    classMethodsCount += mlist->getCount();
+                    methodEntsize = 
+                        std::max(methodEntsize, mlist->getEntsize());
+                }
+
+                proplist = cat->getInstanceProperties(cache);
+                if (proplist  &&  proplist->getCount() > 0) {
+                    addedInstanceProperties = true;
+                    instancePropertyCount += proplist->getCount();
+                    propertyEntsize = 
+                        std::max(propertyEntsize, proplist->getEntsize());
+                }
+
+                protolist = cat->getProtocols(cache);
+                if (protolist  &&  protolist->getCount() > 0) {
+                    addedProtocols = true;
+                    protocolCount += protolist->getCount();
+                }
+            }
+
+            // Allocate memory for aggregated lists. 
+            // Reserve the same amount of space from mBytes.
+
+            if (addedInstanceMethods) {
+                changes.instanceMethods = objc_method_list_t<A>::newMethodList(instanceMethodsCount, methodEntsize);
+                reserve = P::round_up(reserve + changes.instanceMethods->byteSize());
+            }
+            if (addedClassMethods) {
+                changes.classMethods = objc_method_list_t<A>::newMethodList(classMethodsCount, methodEntsize);
+                reserve = P::round_up(reserve + changes.classMethods->byteSize());
+            }
+            if (addedInstanceProperties) {
+                changes.instanceProperties = objc_property_list_t<A>::newPropertyList(instancePropertyCount, propertyEntsize);
+                reserve = P::round_up(reserve + changes.instanceProperties->byteSize());
+            }
+            if (addedProtocols) {
+                changes.protocols = objc_protocol_list_t<A>::newProtocolList(protocolCount);
+                reserve = P::round_up(reserve + changes.protocols->byteSize());
+            }
+
+                       // Merge. The LAST category's contents ends up FIRST in each list.
+                       // The aggregated lists are not sorted; a future pass does that.
+
+            typename objc_method_list_t<A>::method_iterator newInstanceMethods;
+            typename objc_method_list_t<A>::method_iterator newClassMethods;
+            typename objc_property_list_t<A>::property_iterator newInstanceProperties;
+            pint_t newProtocolIndex;
+
+            if (addedInstanceMethods) {
+                newInstanceMethods = changes.instanceMethods->begin();
+            }
+            if (addedClassMethods) {
+                newClassMethods = changes.classMethods->begin();
+            }
+            if (addedInstanceProperties) {
+                newInstanceProperties = changes.instanceProperties->begin();
+            }
+            if (addedProtocols) {
+                newProtocolIndex = 0;
+            }
+            
+            for (j = cats.begin(); j != cats.end(); ++j) {
+                objc_category_t<A>* cat = *j;
+
+                mlist = cat->getInstanceMethods(cache);
+                if (mlist) {
+                    copyMethods(newInstanceMethods, mlist);
+                                       mlist->getPointers(pointersToRemove);
+                    unusedMemory.add(mlist, mlist->byteSize());
+                }
+
+                mlist = cat->getClassMethods(cache);
+                if (mlist) {
+                    copyMethods(newClassMethods, mlist);
+                                       mlist->getPointers(pointersToRemove);
+                                       unusedMemory.add(mlist, mlist->byteSize());
+                }
+
+                proplist = cat->getInstanceProperties(cache);
+                if (proplist) {
+                    copyProperties(newInstanceProperties, proplist);
+                                       proplist->getPointers(pointersToRemove);
+                                       unusedMemory.add(proplist, proplist->byteSize());
+                }
+
+                protolist = cat->getProtocols(cache);
+                if (protolist) {
+                    copyProtocols(changes.protocols, newProtocolIndex, protolist);
+                                       protolist->getPointers(pointersToRemove);
+                                       unusedMemory.add(protolist, protolist->byteSize());
+                }
+
+                               cat->getPointers(pointersToRemove);
+                               unusedMemory.add(cat, sizeof(*cat));                
+            }
+
+            if (addedInstanceMethods && (mlist = cls->getMethodList(cache))) {
+                copyMethods(newInstanceMethods, mlist);
+                               mlist->getPointers(pointersToRemove);
+                               unusedMemory.add(mlist, mlist->byteSize());
+            }
+            if (addedClassMethods && (mlist = meta->getMethodList(cache))) {
+                copyMethods(newClassMethods, mlist);
+                               mlist->getPointers(pointersToRemove);
+                unusedMemory.add(mlist, mlist->byteSize());
+            }
+            if (addedInstanceProperties && (proplist = cls->getPropertyList(cache))) {
+                copyProperties(newInstanceProperties, proplist);
+                               proplist->getPointers(pointersToRemove);
+                               unusedMemory.add(proplist, proplist->byteSize());
+            }
+            if (addedProtocols && (protolist = cls->getProtocolList(cache))) {
+                copyProtocols(changes.protocols, newProtocolIndex, protolist);
+                               protolist->getPointers(pointersToRemove);
+                unusedMemory.add(protolist, protolist->byteSize());
+            }
+        }
+
+               if (reserve > mBytesFree) {
+                       return "insufficient space for category data (metadata not optimized)";
+               }
+
+               // update cache slide info and remove areas now longer containing pointers
+               //fprintf(stderr, "found %lu pointers in objc structures being moved\n", pointersToRemove.size());
+               pointersInData.erase(std::remove_if(pointersInData.begin(), pointersInData.end(), InSet(pointersToRemove)), pointersInData.end());
+               
+
+               // All lists are now built.
+        // mBytes is big enough to hold everything if necessary.
+        // Everything in unusedMemory is now available for re-use.
+        // The original metadata is still untouched.
+
+        // Second: write lists into mBytes and unusedMemory, 
+        // then disconnect categories.
+
+        for (typename ClassMap::iterator i = map.begin(); 
+             i != map.end(); 
+             ++i) 
+        {
+            objc_class_t<A>* cls = i->first;
+            objc_class_t<A>* meta = cls->getIsa(cache);
+            ClassChanges& changes = i->second;
+
+            // Write lists.
+            
+            if (changes.instanceMethods) {
+                uint8_t *bytes;
+                uint32_t size = changes.instanceMethods->byteSize();
+                if (! (bytes = unusedMemory.remove(size))) {
+                    bytes = mBytes + mBytesUsed;
+                    mBytesFree -= size;
+                    mBytesUsed += size;
+                }
+                memcpy(bytes, changes.instanceMethods, size);
+                               objc_method_list_t<A>::addPointers(bytes, pointersInData);
+                               cls->setMethodList(cache, (objc_method_list_t<A> *)bytes);
+                               cls->addMethodListPointer(cache, pointersInData);
+            }
+            
+            if (changes.classMethods) {
+                uint8_t *bytes;
+                uint32_t size = changes.classMethods->byteSize();
+                if (! (bytes = unusedMemory.remove(size))) {
+                    bytes = mBytes + mBytesUsed;
+                    mBytesFree -= size;
+                    mBytesUsed += size;
+                }
+                memcpy(bytes, changes.classMethods, size);
+                               objc_method_list_t<A>::addPointers(bytes, pointersInData);
+                               meta->setMethodList(cache, (objc_method_list_t<A> *)bytes);
+                               meta->addMethodListPointer(cache, pointersInData);
+            }
+            
+            if (changes.instanceProperties) {
+                uint8_t *bytes;
+                uint32_t size = changes.instanceProperties->byteSize();
+                if (! (bytes = unusedMemory.remove(size))) {
+                    bytes = mBytes + mBytesUsed;
+                    mBytesFree -= size;
+                    mBytesUsed += size;
+                }
+                memcpy(bytes, changes.instanceProperties, size);
+                               objc_property_list_t<A>::addPointers(bytes, pointersInData);
+                cls->setPropertyList(cache, (objc_property_list_t<A> *)bytes);
+                               cls->addPropertyListPointer(cache, pointersInData);
+          }
+
+            if (changes.protocols) {
+                uint8_t *bytes;
+                uint32_t size = changes.protocols->byteSize();
+                if (! (bytes = unusedMemory.remove(size))) {
+                    bytes = mBytes + mBytesUsed;
+                    mBytesFree -= size;
+                    mBytesUsed += size;
+                }
+                memcpy(bytes, changes.protocols, size);
+                cls->setProtocolList(cache, (objc_protocol_list_t<A> *)bytes);
+                               objc_protocol_list_t<A>::addPointers(bytes, pointersInData);
+                               cls->addProtocolListPointer(cache, pointersInData);
+                               meta->setProtocolList(cache, (objc_protocol_list_t<A> *)bytes);
+                               meta->addProtocolListPointer(cache, pointersInData);
+          }
+
+            // Disavow all knowledge of the categories.
+
+            for (typename CategoryRefs::iterator j = changes.catrefs.begin();
+                 j != changes.catrefs.end();
+                 ++j)
+            {
+                catsect.set(*j, 0);
+            }
+
+            mCategoriesAttached += changes.categories.size();
+        }
+
+        catsect.removeNulls();
+
+        return NULL;
+    }
+
+    ssize_t bytesUsed() { return mBytesUsed; }
+};
diff --git a/launch-cache/dsc_extractor.cpp b/launch-cache/dsc_extractor.cpp
new file mode 100644 (file)
index 0000000..b86b366
--- /dev/null
@@ -0,0 +1,443 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * 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>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/syslimits.h>
+#include <libkern/OSByteOrder.h>
+#include <mach-o/fat.h>
+#include <mach-o/arch.h>
+#include <mach-o/loader.h>
+#include <Availability.h>
+
+#define NO_ULEB 
+#include "Architectures.hpp"
+#include "MachOFileAbstraction.hpp"
+
+#include "dsc_iterator.h"
+#include "dsc_extractor.h"
+
+#include <vector>
+#include <map>
+#include <ext/hash_map>
+#include <algorithm>
+#include <dispatch/dispatch.h>
+
+struct seg_info
+{
+                               seg_info(const char* n, uint64_t o, uint64_t s) 
+                                       : segName(n), offset(o), sizem(s) { }
+       const char* segName;
+       uint64_t        offset;
+       uint64_t        sizem;
+};
+
+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;
+
+
+template <typename A>
+int optimize_linkedit(macho_header<typename A::P>* mh, const void* mapped_cache, uint64_t* newSize) 
+{
+       typedef typename A::P P;
+       typedef typename A::P::E E;
+    typedef typename A::P::uint_t pint_t;
+
+       // update header flags
+       mh->set_flags(mh->flags() & 0x7FFFFFFF); // remove in-cache bit
+       
+       // update load commands
+       uint64_t cumulativeFileSize = 0;
+       const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)mh + sizeof(macho_header<P>));
+       const uint32_t cmd_count = mh->ncmds();
+       const macho_load_command<P>* cmd = cmds;
+       macho_segment_command<P>* linkEditSegCmd = NULL;
+       macho_symtab_command<P>* symtab = NULL;
+       macho_dysymtab_command<P>*      dynamicSymTab = NULL;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+                       // update segment/section file offsets
+                       macho_segment_command<P>* segCmd = (macho_segment_command<P>*)cmd;
+                       segCmd->set_fileoff(cumulativeFileSize);
+                       macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
+                       macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
+                       for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+                               if ( sect->offset() != 0 )
+                                       sect->set_offset(cumulativeFileSize+sect->addr()-segCmd->vmaddr());
+                       }
+                       if ( strcmp(segCmd->segname(), "__LINKEDIT") == 0 ) {
+                               linkEditSegCmd = segCmd;
+                       }
+                       cumulativeFileSize += segCmd->filesize();
+               }
+               else if ( cmd->cmd() == LC_DYLD_INFO_ONLY ) {
+                       // zero out all dyld info
+                       macho_dyld_info_command<P>* dyldInfo = (macho_dyld_info_command<P>*)cmd;
+                       dyldInfo->set_rebase_off(0);
+                       dyldInfo->set_rebase_size(0);
+                       dyldInfo->set_bind_off(0);
+                       dyldInfo->set_bind_size(0);
+                       dyldInfo->set_weak_bind_off(0);
+                       dyldInfo->set_weak_bind_size(0);
+                       dyldInfo->set_lazy_bind_off(0);
+                       dyldInfo->set_lazy_bind_size(0);
+                       dyldInfo->set_export_off(0);
+                       dyldInfo->set_export_size(0);
+               }
+               else if ( cmd->cmd() == LC_SYMTAB ) {
+                       symtab = (macho_symtab_command<P>*)cmd;
+               }
+               else if ( cmd->cmd() == LC_DYSYMTAB ) {
+                       dynamicSymTab = (macho_dysymtab_command<P>*)cmd;
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }
+       
+       // rebuild symbol table
+       if ( linkEditSegCmd == NULL ) {
+               fprintf(stderr, "__LINKEDIT not found\n");
+               return -1;
+       }
+       if ( symtab == NULL ) {
+               fprintf(stderr, "LC_SYMTAB not found\n");
+               return -1;
+       }
+       if ( dynamicSymTab == NULL ) {
+               fprintf(stderr, "LC_DYSYMTAB not found\n");
+               return -1;
+       }
+       // copy symbol entries and strings from original cache file to new mapped dylib file
+       const uint32_t newSymTabOffset = linkEditSegCmd->fileoff();
+       const uint32_t newIndSymTabOffset = newSymTabOffset + symtab->nsyms()*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;
+       newStringPoolStart[poolOffset++] = '\0'; // first pool entry is always empty string
+       for (const macho_nlist<P>* s = mergedSymTabStart; s != mergedSymTabend; ++s) {
+               *t = *s;
+               t->set_n_strx(poolOffset);
+               strcpy(&newStringPoolStart[poolOffset], &mergedStringPoolStart[s->n_strx()]);
+               poolOffset += (strlen(&newStringPoolStart[poolOffset]) + 1);
+               ++t;
+       }
+       // pointer align string pool size
+       while ( (poolOffset % sizeof(pint_t)) != 0 )
+               ++poolOffset; 
+       // copy indirect symbol table
+       memcpy(newIndSymTab, mergedIndSymTab, dynamicSymTab->nindirectsyms()*sizeof(uint32_t));
+       
+       // update load commands
+       symtab->set_symoff(newSymTabOffset);
+       symtab->set_stroff(newStringPoolOffset);
+       symtab->set_strsize(poolOffset);
+       dynamicSymTab->set_extreloff(0);
+       dynamicSymTab->set_nextrel(0);
+       dynamicSymTab->set_locreloff(0);
+       dynamicSymTab->set_nlocrel(0);
+       dynamicSymTab->set_indirectsymoff(newIndSymTabOffset);
+       linkEditSegCmd->set_filesize(symtab->stroff()+symtab->strsize() - linkEditSegCmd->fileoff());
+       linkEditSegCmd->set_vmsize( (linkEditSegCmd->filesize()+4095) & (-4096) );
+       
+       // return new size
+       *newSize = (symtab->stroff()+symtab->strsize()+4095) & (-4096);
+       
+       return 0;
+}
+
+
+
+static void make_dirs(const char* file_path) 
+{
+       //printf("make_dirs(%s)\n", file_path);
+       char dirs[strlen(file_path)+1];
+       strcpy(dirs, file_path);
+       char* lastSlash = strrchr(dirs, '/');
+       if ( lastSlash == NULL )
+               return;
+       lastSlash[1] = '\0';
+       struct stat stat_buf;
+       if ( stat(dirs, &stat_buf) != 0 ) {
+               const char* afterSlash = &dirs[1];
+               char* slash;
+               while ( (slash = strchr(afterSlash, '/')) != NULL ) {
+                       *slash = '\0';
+                       ::mkdir(dirs, S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH);
+                       //printf("mkdir(%s)\n", dirs);
+                       *slash = '/';
+                       afterSlash = slash+1;
+               }
+       }
+}
+
+
+
+template <typename A>
+size_t dylib_maker(const void* mapped_cache, std::vector<uint8_t> &dylib_data, const std::vector<seg_info>& segments) {                
+       typedef typename A::P P;
+    
+    size_t  additionalSize  = 0;
+       for(std::vector<seg_info>::const_iterator it=segments.begin(); it != segments.end(); ++it) {
+               additionalSize                          += it->sizem;
+       }
+    
+    dylib_data.reserve(dylib_data.size() + additionalSize);
+    
+    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)))
+    
+    if(dylib_data.size() >= 4096 && OSSwapBigToHostInt32(FH->magic) == FAT_MAGIC) {
+               // have fat header, append new arch to end
+        nfat_archs                              = OSSwapBigToHostInt32(FH->nfat_arch);
+               offsetInFatFile                         = OSSwapBigToHostInt32(FA->offset) + OSSwapBigToHostInt32(FA->size);
+    }
+    
+    dylib_data.resize(offsetInFatFile);
+    base_ptr                                    = &dylib_data.front();
+    
+    FH->magic                                   = OSSwapHostToBigInt32(FAT_MAGIC);
+    FH->nfat_arch                               = OSSwapHostToBigInt32(++nfat_archs);
+    
+    FA->cputype                                 = 0; // filled in later
+    FA->cpusubtype                              = 0; // filled in later
+    FA->offset                                  = OSSwapHostToBigInt32(offsetInFatFile);
+    FA->size                                    = 0; // filled in later
+    FA->align                                   = OSSwapHostToBigInt32(12);
+    
+       // Write regular segments into the buffer
+       uint32_t                totalSize           = 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);
+            FA->cputype                         = OSSwapHostToBigInt32(textMH->cputype()); 
+            FA->cpusubtype                      = OSSwapHostToBigInt32(textMH->cpusubtype());
+            
+            // if this cputype/subtype already exist in fat header, then return immediately
+            for(uint32_t i=0; i < nfat_archs-1; ++i) {
+                fat_arch            *afa        = reinterpret_cast<fat_arch*>(base_ptr+8)+i;
+                
+                if(   afa->cputype == FA->cputype
+                   && afa->cpusubtype == FA->cpusubtype) {
+                    fprintf(stderr, "arch already exists in fat dylib\n");
+                    dylib_data.resize(offsetInFatFile);
+                    return offsetInFatFile;
+                }
+            }
+               }
+        
+               //printf("segName=%s, offset=0x%llX, size=0x%0llX\n", it->segName, it->offset, it->sizem);
+        std::copy(((uint8_t*)mapped_cache)+it->offset, ((uint8_t*)mapped_cache)+it->offset+it->sizem, std::back_inserter(dylib_data));
+        base_ptr                                = &dylib_data.front();
+        totalSize                               += it->sizem;
+       }
+    
+       FA->size                                    = OSSwapHostToBigInt32(totalSize); 
+    
+       // optimize linkedit
+       uint64_t                newSize             = dylib_data.size();
+       optimize_linkedit<A>(((macho_header<P>*)(base_ptr+offsetInFatFile)), mapped_cache, &newSize);
+       
+       // update fat header with new file size
+    dylib_data.resize(offsetInFatFile+newSize);
+    base_ptr                                    = &dylib_data.front();
+       FA->size                                    = OSSwapHostToBigInt32(newSize);
+#undef FH
+#undef FA
+       return offsetInFatFile;
+} 
+
+
+extern int dyld_shared_cache_extract_dylibs_progress(const char* shared_cache_file_path, const char* extraction_root_path,
+                                                                                                       void (^progress)(unsigned current, unsigned total))
+{
+       struct stat statbuf;
+       if (stat(shared_cache_file_path, &statbuf)) {
+               fprintf(stderr, "Error: stat failed for dyld shared cache at %s\n", shared_cache_file_path);
+               return -1;
+       }
+               
+       int cache_fd = open(shared_cache_file_path, O_RDONLY);
+       if (cache_fd < 0) {
+               fprintf(stderr, "Error: failed to open shared cache file at %s\n", shared_cache_file_path);
+               return -1;
+       }
+       
+       void* 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_file_path, errno);
+               return -1;
+       }
+    
+    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 ) 
+               dylib_create_func = dylib_maker<x86>;
+       else if ( strcmp((char*)mapped_cache, "dyld_v1  x86_64") == 0 ) 
+               dylib_create_func = dylib_maker<x86_64>;
+       else if ( strcmp((char*)mapped_cache, "dyld_v1     ppc") == 0 ) 
+               dylib_create_func = dylib_maker<ppc>;
+       else if ( strcmp((char*)mapped_cache, "dyld_v1   armv5") == 0 ) 
+               dylib_create_func = dylib_maker<arm>;
+       else if ( strcmp((char*)mapped_cache, "dyld_v1   armv6") == 0 ) 
+               dylib_create_func = dylib_maker<arm>;
+       else if ( strcmp((char*)mapped_cache, "dyld_v1   armv7") == 0 ) 
+               dylib_create_func = dylib_maker<arm>;
+       else {
+               fprintf(stderr, "Error: unrecognized dyld shared cache magic.\n");
+        munmap(mapped_cache, statbuf.st_size);
+               return -1;
+       }
+
+       // 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));
+               });
+
+       // for each dylib instantiate a dylib file
+    dispatch_group_t        group               = dispatch_group_create();
+    dispatch_semaphore_t    sema                = dispatch_semaphore_create(4);
+    dispatch_queue_t        process_queue       = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
+    dispatch_queue_t        writer_queue        = dispatch_queue_create("dyld writer queue", 0);
+    
+       __block int             cumulativeResult    = 0;
+       __block unsigned        count               = 0;
+    
+       for ( NameToSegments::iterator it = map.begin(); it != map.end(); ++it) {
+        dispatch_group_async(group, process_queue, ^{
+            dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
+            
+            char    dylib_path[PATH_MAX];
+            strcpy(dylib_path, extraction_root_path);
+            strcat(dylib_path, "/");
+            strcat(dylib_path, it->first);
+            
+            //printf("%s with %lu segments\n", dylib_path, segments.size());
+            // make sure all directories in this path exist
+            make_dirs(dylib_path);
+            
+            // open file, create if does not already exist
+            int fd = ::open(dylib_path, O_CREAT | O_EXLOCK | O_RDWR, 0644);
+            if ( fd == -1 ) {
+                fprintf(stderr, "can't open or create dylib file %s, errnor=%d\n", dylib_path, errno);
+                cumulativeResult    = -1;
+                return;
+            }
+            
+            struct stat statbuf;
+            if (fstat(fd, &statbuf)) {
+                fprintf(stderr, "Error: stat failed for dyld file %s, errnor=%d\n", dylib_path, errno);
+                close(fd);
+                cumulativeResult    = -1;
+                return;
+            }
+            
+            std::vector<uint8_t> *vec   = new std::vector<uint8_t>(statbuf.st_size);
+            if(pread(fd, &vec->front(), vec->size(), 0) != (long)vec->size()) {
+                fprintf(stderr, "can't read dylib file %s, errnor=%d\n", dylib_path, errno);
+                close(fd);
+                cumulativeResult    = -1;
+                return;
+            }
+            
+            const size_t    offset  = dylib_create_func(mapped_cache, *vec, it->second);
+            
+            dispatch_group_async(group, writer_queue, ^{
+                progress(count++, map.size());
+                
+                if(offset != vec->size()) {
+                    //Write out the first page, and everything after offset
+                    if(   pwrite(fd, &vec->front(), 4096, 0) == -1 
+                       || pwrite(fd, &vec->front() + offset, vec->size() - offset, offset) == -1) {
+                        fprintf(stderr, "error writing, errnor=%d\n", errno);
+                        cumulativeResult    = -1;
+                    }
+                }
+                
+                delete vec;
+                close(fd);
+                dispatch_semaphore_signal(sema);
+            });
+        });
+       }
+    
+    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
+    dispatch_release(group);
+    dispatch_release(writer_queue);
+    
+    munmap(mapped_cache, statbuf.st_size);
+       return cumulativeResult;
+}
+
+
+
+int dyld_shared_cache_extract_dylibs(const char* shared_cache_file_path, const char* extraction_root_path)
+{
+       return dyld_shared_cache_extract_dylibs_progress(shared_cache_file_path, extraction_root_path, 
+                                                                                                       ^(unsigned , unsigned) {} );
+}
+
+
+#if 0 
+int main(int argc, const char* argv[])
+{
+       if ( argc != 3 ) {
+               fprintf(stderr, "usage: dsc_extractor <path-to-cache-file> <path-to-device-dir>\n");
+               return 1;
+       }
+               
+       int result = dyld_shared_cache_extract_dylibs_progress(argv[1], argv[2], ^(unsigned c, unsigned total) { printf("%d/%d\n", c, total); } );
+       fprintf(stderr, "dyld_shared_cache_extract_dylibs_progress() => %d\n", result);
+       return 0;
+}
+#endif
+
+
+
diff --git a/launch-cache/dsc_extractor.h b/launch-cache/dsc_extractor.h
new file mode 100644 (file)
index 0000000..a8620d0
--- /dev/null
@@ -0,0 +1,43 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * 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@
+ */
+
+#ifndef _DYLD_SHARED_CACHE_EXTRACTOR_
+#define _DYLD_SHARED_CACHE_EXTRACTOR_
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif 
+
+extern int dyld_shared_cache_extract_dylibs(const char* shared_cache_file_path, const char* extraction_root_path);
+extern int dyld_shared_cache_extract_dylibs_progress(const char* shared_cache_file_path, const char* extraction_root_path,
+                                                                                                       void (^progress)(unsigned current, unsigned total));
+
+#ifdef __cplusplus
+}
+#endif 
+
+#endif // _DYLD_SHARED_CACHE_EXTRACTOR_
+
index 5110cbc751ba5aa1f36e8f2e050954396a104136..9b5cac4f962f40a9a0d55a25e8db002949f9a2b9 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
- * Copyright (c) 2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -23,6 +23,9 @@
  */
 
 #include <stdlib.h>
  */
 
 #include <stdlib.h>
+#include <stdio.h>
+#include <Availability.h>
+
 
 #include "dsc_iterator.h"
 #include "dyld_cache_format.h"
 
 #include "dsc_iterator.h"
 #include "dyld_cache_format.h"
 #include "CacheFileAbstraction.hpp"
 
 
 #include "CacheFileAbstraction.hpp"
 
 
+
 namespace dyld {
 
 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)
        // 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)
@@ -50,7 +55,7 @@ namespace dyld {
 
        // call the callback block on each segment in this image                                                          
        template <typename A>
 
        // 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, dyld_shared_cache_iterator_t callback) 
+       void walkSegments(const uint8_t* cache, const char* dylibPath, const uint8_t* machHeader, uint64_t slide, dyld_shared_cache_iterator_slide_t callback) 
        {
                typedef typename A::P           P;      
                typedef typename A::P::E        E;      
        {
                typedef typename A::P           P;      
                typedef typename A::P::E        E;      
@@ -61,26 +66,47 @@ namespace dyld {
                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;
                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;
-                               const uint8_t* segStartInCache = mappedAddress<E>(cache, segCmd->vmaddr());
-                               uint64_t fileOffset = segStartInCache - cache;
-                               callback(dylibPath, segCmd->segname(), fileOffset, segCmd->vmsize());
+                               uint64_t fileOffset = segCmd->fileoff();
+                               // work around until <rdar://problem/7022345> is fixed
+                               if ( fileOffset == 0 ) {
+                                       fileOffset = (machHeader - cache);
+                               }
+                               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;
+                                       }
+                               }
+                               callback(dylibPath, segCmd->segname(), fileOffset, sizem, segCmd->vmaddr()+slide, slide);
                        }
                        cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
                }
        }
                        }
                        cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
                }
        }
-                                               
+                       
                                                          
        // call walkSegments on each image in the cache                                                           
        template <typename A>
                                                          
        // call walkSegments on each image in the cache                                                           
        template <typename A>
-       int walkImages(const uint8_t* cache, dyld_shared_cache_iterator_t callback) 
+       int walkImages(const uint8_t* cache, dyld_shared_cache_iterator_slide_t callback) 
        {
        {
-               typedef typename A::P::E   E;   
+               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;
                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()];
                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());
                const dyldCacheImageInfo<E>* dylibs = (dyldCacheImageInfo<E>*)&cache[header->imagesOffset()];
                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, callback);
+                       walkSegments<A>(cache, dylibPath, machHeader, slide, callback);
                }
                return 0;
        }
                }
                return 0;
        }
@@ -92,7 +118,7 @@ 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.
 // 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(const void* shared_cache_file, dyld_shared_cache_iterator_t callback)
+int dyld_shared_cache_iterate_segments_with_slide(const void* shared_cache_file, dyld_shared_cache_iterator_slide_t callback)
 {
        const uint8_t* cache = (uint8_t*)shared_cache_file;
                 if ( strcmp((char*)cache, "dyld_v1    i386") == 0 ) 
 {
        const uint8_t* cache = (uint8_t*)shared_cache_file;
                 if ( strcmp((char*)cache, "dyld_v1    i386") == 0 ) 
@@ -101,7 +127,42 @@ int dyld_shared_cache_iterate_segments(const void* shared_cache_file, dyld_share
                        return dyld::walkImages<x86_64>(cache, callback);
        else if ( strcmp((char*)cache, "dyld_v1     ppc") == 0 ) 
                        return dyld::walkImages<ppc>(cache, callback);
                        return dyld::walkImages<x86_64>(cache, callback);
        else if ( strcmp((char*)cache, "dyld_v1     ppc") == 0 ) 
                        return dyld::walkImages<ppc>(cache, callback);
+       else if ( strcmp((char*)cache, "dyld_v1   armv5") == 0 ) 
+                       return dyld::walkImages<arm>(cache, callback);
+       else if ( strcmp((char*)cache, "dyld_v1   armv6") == 0 ) 
+                       return dyld::walkImages<arm>(cache, callback);
+       else if ( strcmp((char*)cache, "dyld_v1   armv7") == 0 ) 
+                       return dyld::walkImages<arm>(cache, callback);
        else
                return -1;
 }
 
        else
                return -1;
 }
 
+// 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)
+{
+       return dyld_shared_cache_iterate_segments_with_slide(shared_cache_file, ^(const char* dylibName, const char* segName, 
+                                                                                                       uint64_t offset, uint64_t size, uint64_t mappedddress, uint64_t slide) {
+                                                                                                               (*func)(dylibName, segName, offset, size, mappedddress, slide, userData);
+       });
+}
+
+
+// implement non-slide version by wrapping slide version in block
+int dyld_shared_cache_iterate_segments(const void* shared_cache_file, dyld_shared_cache_iterator_t callback)
+{
+       dyld_shared_cache_iterator_slide_t wrapper_cb = ^(const char* dylibName, const char* segName, uint64_t offset, 
+                                                                                                               uint64_t size, uint64_t mappedddress, uint64_t slide) {
+                                                                                                               callback(dylibName, segName, offset, size, mappedddress);
+                                                                                                       };
+       return dyld_shared_cache_iterate_segments_with_slide(shared_cache_file, wrapper_cb);
+}
+
+// implement non-slide,non-block version by wrapping slide version in block
+int dyld_shared_cache_iterate_segments_nb(const void* shared_cache_file, dyld_shared_cache_iterator_nb_t func, void* userData)
+{
+       return dyld_shared_cache_iterate_segments_with_slide(shared_cache_file, ^(const char* dylibName, const char* segName, 
+                                                                                                                                                         uint64_t offset, uint64_t size, uint64_t mappedddress, uint64_t slide) {
+               (*func)(dylibName, segName, offset, size, mappedddress, userData);
+       });
+}
+
index 418eece8a1a2da5315941c53c31153470099ccaf..981386f7cc8496d22d740d195014dfbaa4b91040 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
- * Copyright (c) 2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 extern "C" {
 #endif 
 
 extern "C" {
 #endif 
 
-       typedef void (^dyld_shared_cache_iterator_t)(const char* dylib, const char* segName, uint64_t offset, uint64_t size);
 
 
-       // 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);
+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);
+
 
 
-       
 #ifdef __cplusplus
 }
 #endif 
 #ifdef __cplusplus
 }
 #endif 
diff --git a/launch-cache/dsc_slider.cpp b/launch-cache/dsc_slider.cpp
new file mode 100644 (file)
index 0000000..d11f46a
--- /dev/null
@@ -0,0 +1,308 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * 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>
+#include <stdio.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <Availability.h>
+
+#define NO_ULEB 1
+#include "dyld_cache_format.h"
+#include "Architectures.hpp"
+#include "MachOFileAbstraction.hpp"
+#include "CacheFileAbstraction.hpp"
+
+#include "dsc_slider.h"
+
+int update_dyld_shared_cache_load_address(const char* path, void (*logProc)(const char* format, ...) )
+{
+       int fd = open(path, O_RDONLY, 0);
+       if ( fd == -1 ) {
+               (*logProc)("open(%s) failed, errno=%d\n", path, errno);
+               return -1;
+       }
+       (void)fcntl(fd, F_NOCACHE, 1); // tell kernel to not cache file content
+
+       uint8_t buffer[4096];
+       if ( read(fd, buffer, 4096) != 4096 ) {
+               (*logProc)("read(%s) failed, errno=%d\n", path, errno);
+               close(fd);
+               return -1;
+       }
+       bool has64BitPointers = false;
+       bool isBigEndian = false;
+       uint64_t startReadOnlySharedRegion = 0;
+       uint64_t endReadOnlySharedRegion = 0;
+       uint64_t startReadWriteSharedRegion = 0;
+       uint64_t endReadWriteSharedRegion = 0;
+       if ( strcmp((char*)buffer, "dyld_v1    i386") == 0 ) {
+               has64BitPointers = false;
+               isBigEndian = false;
+       }
+       else if ( strcmp((char*)buffer, "dyld_v1  x86_64") == 0 ) {
+               has64BitPointers = true;
+               isBigEndian = false;
+               startReadOnlySharedRegion  = 0x7FFF80000000LL;
+               endReadOnlySharedRegion    = 0x7FFFC0000000LL;
+               startReadWriteSharedRegion = 0x7FFF70000000LL;
+               endReadWriteSharedRegion   = 0x7FFF80000000LL;
+       }
+       else if ( strcmp((char*)buffer, "dyld_v1     ppc") == 0 ) {
+               has64BitPointers = false;
+               isBigEndian = true;
+       }
+       else if ( strcmp((char*)buffer, "dyld_v1   armv5") == 0 ) {
+               has64BitPointers = false;
+               isBigEndian = false;
+               startReadOnlySharedRegion  = 0x30000000LL;
+               endReadOnlySharedRegion    = 0x3E000000LL;
+               startReadWriteSharedRegion = 0x3E000000LL;
+               endReadWriteSharedRegion   = 0x40000000LL;
+       }
+       else if ( strcmp((char*)buffer, "dyld_v1   armv6") == 0 ) {
+               has64BitPointers = false;
+               isBigEndian = false;
+               startReadOnlySharedRegion  = 0x30000000LL;
+               endReadOnlySharedRegion    = 0x3E000000LL;
+               startReadWriteSharedRegion = 0x3E000000LL;
+               endReadWriteSharedRegion   = 0x40000000LL;
+       }
+       else if ( strcmp((char*)buffer, "dyld_v1   armv7") == 0 ) {
+               has64BitPointers = false;
+               isBigEndian = false;
+               startReadOnlySharedRegion  = 0x30000000LL;
+               endReadOnlySharedRegion    = 0x3E000000LL;
+               startReadWriteSharedRegion = 0x3E000000LL;
+               endReadWriteSharedRegion   = 0x40000000LL;
+       }
+       else {
+               (*logProc)("file %s is not a known dyld shared cache file\n", path);
+               close(fd);
+               return -1;
+       }
+#if __BIG_ENDIAN__ 
+       bool swap = !isBigEndian;
+#else
+       bool swap = isBigEndian;
+#endif
+       
+       const dyld_cache_header* header = (dyld_cache_header*)buffer;
+       uint32_t mappingOffset = swap ? OSSwapInt32(header->mappingOffset) : header->mappingOffset;
+       if ( mappingOffset < 0x48 ) {
+               (*logProc)("dyld shared cache file %s is old format\n", path);
+               close(fd);
+               return -1;
+       }
+
+       uint32_t mappingCount = swap ? OSSwapInt32(header->mappingCount) : header->mappingCount;
+       if ( mappingCount != 3 ) {
+               (*logProc)("dyld shared cache file %s has wrong mapping count\n", path);
+               close(fd);
+               return -1;
+       }
+
+       uint64_t slidePointersOffset = swap ? OSSwapInt64(header->slidePointersOffset) : header->slidePointersOffset;
+       uint64_t slidePointersSize = swap ? OSSwapInt64(header->slidePointersSize) : header->slidePointersSize;
+       if ( (slidePointersOffset == 0) || (slidePointersSize == 0) ) {
+               (*logProc)("dyld shared cache file %s is missing slide information\n", path);
+               close(fd);
+               return -1;
+       }
+       
+       // read slide info
+       void* slideInfo = malloc(slidePointersSize);
+       if ( slideInfo == NULL ) {
+               (*logProc)("malloc(%llu) failed\n", slidePointersSize);
+               close(fd);
+               return -1;
+       }
+       int64_t amountRead = pread(fd, slideInfo, slidePointersSize, slidePointersOffset);
+       if ( amountRead != (int64_t)slidePointersSize ) {
+               (*logProc)("slide info pread(fd, buf, %llu, %llu) failed\n", slidePointersSize, slidePointersOffset);
+               close(fd);
+               return -1;
+       }
+
+       // read all DATA 
+       const dyld_cache_mapping_info* mappings = (dyld_cache_mapping_info*)&buffer[mappingOffset];
+       uint64_t dataFileOffset = swap ? OSSwapInt64(mappings[1].fileOffset) : mappings[1].fileOffset;
+       uint64_t dataSize = swap ? OSSwapInt64(mappings[1].size) : mappings[1].size;
+       uint8_t* data = (uint8_t*)malloc(dataSize);
+       amountRead = pread(fd, data, dataSize, dataFileOffset);
+       if ( amountRead != (int64_t)dataSize ) {
+               (*logProc)("data pread(fd, buf, %llu, %llu) failed\n", data, dataSize);
+               close(fd);
+               return -1;
+       }
+       
+       // close read-only file
+       close(fd);
+       
+       // extract current slide
+       uint64_t headerDataUses;
+       if ( has64BitPointers ) {
+               headerDataUses = *((uint64_t*)data);
+               if ( swap ) 
+                       headerDataUses = OSSwapInt64(headerDataUses);
+       }
+       else {
+               uint32_t temp = *((uint32_t*)data);
+               if ( swap ) 
+                       temp = OSSwapInt32(temp);
+               headerDataUses = temp;
+       }
+       uint64_t textAddress = swap ? OSSwapInt64(mappings[0].address) : mappings[0].address;
+       uint32_t currentSlide = headerDataUses - textAddress;
+       (*logProc)("currentSlide=0x%08X\n", currentSlide);
+       
+       // find read-only space
+       uint64_t linkeditAddress = swap ? OSSwapInt64(mappings[2].address) : mappings[2].address;
+       uint64_t linkeditSize = swap ? OSSwapInt64(mappings[2].size) : mappings[2].size;
+       uint64_t linkeditEnd = linkeditAddress + linkeditSize;
+       uint64_t roSpace = endReadOnlySharedRegion - linkeditEnd;
+       (*logProc)("ro space=0x%08llX\n", roSpace);
+       
+       // find read-write space
+       uint64_t dataAddress = swap ? OSSwapInt64(mappings[1].address) : mappings[1].address;
+       uint64_t dataEnd = dataAddress + dataSize;
+       uint64_t rwSpace = endReadWriteSharedRegion - dataEnd;
+       (*logProc)("rw space=0x%08llX\n", rwSpace);
+       
+       // choose new random slide
+       uint32_t slideSpace = rwSpace;
+       if ( roSpace < rwSpace )
+               slideSpace = roSpace;
+       uint32_t newSlide = (arc4random() % slideSpace) & (-4096);
+       (*logProc)("newSlide=0x%08X\n", newSlide);
+       int32_t slideAdjustment = newSlide - currentSlide;
+       
+       // update DATA with slide info
+       uint64_t offsetInCacheFile = 0;
+       const uint8_t* infoStart = (uint8_t*)slideInfo;
+       const uint8_t* infoEnd = infoStart + slidePointersSize;
+       for(const uint8_t* p = infoStart; (*p != 0) && (p < infoEnd); ) {
+               uint64_t delta = 0;
+               uint32_t shift = 0;
+               bool more = true;
+               do {
+                       uint8_t byte = *p++;
+                       delta |= ((byte & 0x7F) << shift);
+                       shift += 7;
+                       if ( byte < 0x80 ) {
+                               offsetInCacheFile += delta;
+                               // verify in DATA range
+                               if ( (offsetInCacheFile < dataFileOffset) || (offsetInCacheFile > (dataFileOffset+dataSize)) ) {
+                                       (*logProc)("pointer offset 0x%llX outside DATA range\n", offsetInCacheFile);
+                                       return -1;
+                               }
+                               uint32_t offsetInData = offsetInCacheFile - dataFileOffset;
+                               if ( has64BitPointers ) {
+                                       uint64_t value64 = *((uint64_t*)(&data[offsetInData]));
+                                       if ( swap ) 
+                                               value64 = OSSwapInt64(value64);
+                                       value64 += slideAdjustment;
+                                       if ( swap ) 
+                                               value64 = OSSwapInt64(value64);
+                                       *((uint64_t*)(&data[offsetInData])) = value64;
+                               }
+                               else {
+                                       uint64_t value32 = *((uint32_t*)(&data[offsetInData]));
+                                       if ( swap ) 
+                                               value32 = OSSwapInt32(value32);
+                                       value32 += slideAdjustment;
+                                       if ( swap ) 
+                                               value32 = OSSwapInt32(value32);
+                                       *((uint32_t*)(&data[offsetInData])) = value32;
+                               }
+                               //(*logProc)("update pointer at offset 0x%08X", offsetInData);
+                               more = false;
+                       }
+               } while (more);
+       }
+       free(slideInfo);
+       slideInfo = NULL;
+       
+       // re-open cache file and overwrite DATA range
+       fd = open(path, O_RDWR, 0);
+       if ( fd == -1 ) {
+               (*logProc)("open(%s) failed, errno=%d\n", path, errno);
+               return -1;
+       }
+       (void)fcntl(fd, F_NOCACHE, 1); // tell kernel to not cache file content
+       uint64_t amountWrote = pwrite(fd, data, dataSize, dataFileOffset);
+       if ( amountWrote != dataSize ) {
+               (*logProc)("data pwrite(fd, buf, %llu, %llu) failed\n", data, dataSize);
+               close(fd);
+               return -1;
+       }
+       close(fd);
+       
+       // re-open and re-read to verify write
+       fd = open(path, O_RDONLY, 0);
+       if ( fd == -1 ) {
+               (*logProc)("verify open(%s) failed, errno=%d\n", path, errno);
+               return -1;
+       }
+       (void)fcntl(fd, F_NOCACHE, 1); // tell kernel to not cache file content
+       uint8_t* dataVerify = (uint8_t*)malloc(dataSize);
+       amountRead = pread(fd, dataVerify, dataSize, dataFileOffset);
+       if ( amountRead != (int64_t)dataSize ) {
+               (*logProc)("verify data pread(fd, buf, %llu, %llu) failed\n", data, dataSize);
+               close(fd);
+               return -1;
+       }
+       close(fd);
+       if ( memcmp(data, dataVerify, dataSize) != 0 ) {
+               (*logProc)("data update verification failed\n");
+               return -1;
+       }
+       free(data);
+       free(dataVerify);
+
+       
+       // success
+       return 0;
+}
+
+
+#if 0
+static void logger(const char* format, ...)
+{
+       va_list list;
+       va_start(list, format);
+       fprintf(stderr, "error: ");
+       vfprintf(stderr, format, list);
+}
+
+
+int main(int argc, const char* argv[])
+{
+       return update_dyld_shared_cache_load_address(argv[1], logger);
+}
+#endif
+
+
diff --git a/launch-cache/dsc_slider.h b/launch-cache/dsc_slider.h
new file mode 100644 (file)
index 0000000..4979562
--- /dev/null
@@ -0,0 +1,43 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * 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 <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif 
+
+//
+// This function is called with a path to a dyld shared cache file.  It will update the shared cache file 
+// in place.  The update randomizes the load address when the shared cache file is later used by dyld.
+//
+// On success, the return value is zero.  
+// On failure the return value is non-zero and an explanation error was written to the logProc callback.
+//
+extern int update_dyld_shared_cache_load_address(const char* path, void (*logProc)(const char* format, ...) );
+
+
+#ifdef __cplusplus
+}
+#endif 
index 748fff56bdd24b1c51280052fce00002a0914bab..42a1a139155e60e2c5f53b753b5a18a13b232ba7 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
- * Copyright (c) 2006-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2006-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <mach/shared_region.h>
 
 
 #include <mach/shared_region.h>
 
 
- struct dyld_cache_header
+struct dyld_cache_header
 {
        char            magic[16];                              // e.g. "dyld_v0     ppc"
 {
        char            magic[16];                              // e.g. "dyld_v0     ppc"
-       uint32_t        mappingOffset;                  // file offset to first shared_file_mapping_np
-       uint32_t        mappingCount;                   // number of shared_file_mapping_np entries
+       uint32_t        mappingOffset;                  // file offset to first dyld_cache_mapping_info
+       uint32_t        mappingCount;                   // number of dyld_cache_mapping_info entries
        uint32_t        imagesOffset;                   // file offset to first dyld_cache_image_info
        uint32_t        imagesCount;                    // number of dyld_cache_image_info entries
        uint64_t        dyldBaseAddress;                // base address of dyld when cache was built
        uint32_t        imagesOffset;                   // file offset to first dyld_cache_image_info
        uint32_t        imagesCount;                    // number of dyld_cache_image_info entries
        uint64_t        dyldBaseAddress;                // base address of dyld when cache was built
+       uint64_t        codeSignatureOffset;    // file offset of code signature blob
+       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
+};
+
+struct dyld_cache_mapping_info {
+       uint64_t        address;
+       uint64_t        size;
+       uint64_t        fileOffset;
+       uint32_t        maxProt;
+       uint32_t        initProt;
 };
 
 struct dyld_cache_image_info
 };
 
 struct dyld_cache_image_info
@@ -48,7 +60,22 @@ struct dyld_cache_image_info
        uint32_t        pad;
 };
 
        uint32_t        pad;
 };
 
-#define DYLD_SHARED_CACHE_DIR                  "/var/db/dyld/"
+struct dyld_cache_slide_info
+{
+       uint32_t        version;                // currently 1
+       uint32_t        toc_offset;
+       uint32_t        toc_count;
+       uint32_t        entries_offset;
+       uint32_t        entries_count;
+       uint32_t        entries_size;  // currently 128 
+       // uint16_t toc[toc_count];
+       // entrybitmap entries[entries_count];
+};
+
+
+
+#define MACOSX_DYLD_SHARED_CACHE_DIR   "/var/db/dyld/"
+#define IPHONE_DYLD_SHARED_CACHE_DIR   "/System/Library/Caches/com.apple.dyld/"
 #define DYLD_SHARED_CACHE_BASE_NAME            "dyld_shared_cache_"
 
 
 #define DYLD_SHARED_CACHE_BASE_NAME            "dyld_shared_cache_"
 
 
diff --git a/launch-cache/dyld_shared_cache_util.cpp b/launch-cache/dyld_shared_cache_util.cpp
new file mode 100644 (file)
index 0000000..d82674a
--- /dev/null
@@ -0,0 +1,492 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2009-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 <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/syslimits.h>
+#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 "Architectures.hpp"
+#include "MachOFileAbstraction.hpp"
+#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
+
+// 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 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;
+};
+
+void usage() {
+       fprintf(stderr, "Usage: dscutil -list [ -uuid ] [-vmaddr] | -dependents <dylib-path> [ -versions ] | -linkedit [ shared-cache-file ]\n");
+}
+
+/*
+ * Get the path to the native shared cache for this host
+ */
+static const char* default_shared_cache_path() {
+#if __i386__
+       return MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "i386";
+#elif __x86_64__ 
+       return MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "x86_64";
+#elif __ppc__ 
+       return MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "rosetta";
+#elif __ARM_ARCH_5TEJ__ 
+       return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv5";
+#elif __ARM_ARCH_6K__ 
+       return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv6";
+#elif __ARM_ARCH_7A__ 
+       return IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME "armv7";
+#else
+       #error unsupported architecture
+#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;
+}
+
+/*
+ * 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) {
+       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 (compatibility version %u.%u.%u, current version %u.%u.%u)\n", 
+                       name, 
+                       (compat_vers >> 16),
+                       (compat_vers >> 8) & 0xff,
+                       (compat_vers) & 0xff,
+                       (current_vers >> 16),
+                       (current_vers >> 8) & 0xff,
+                       (current_vers) & 0xff);
+            } else {
+                printf("\t%s\n", name);
+            }                  
+               }
+       }
+}
+
+/*
+ * Print out a dylib from the shared cache, optionally including the UUID
+ */
+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();
+                       }
+               }                       
+       }
+
+       if (args->print_vmaddrs)
+               printf("0x%08llX ", vmaddr+slide);
+       if (args->print_uuids) {
+               if (got_uuid)
+                       printf("%s ", uuid_str);
+           else
+                       printf("<     no uuid in dylib               > ");
+    }
+       printf("%s\n", dylib);
+}
+
+
+uint64_t                                       sLinkeditBase = 0;
+std::map<uint32_t, char*>      sPageToContent;
+
+
+
+
+static void add_linkedit(uint32_t pageStart, uint32_t pageEnd, char* message) 
+{      
+       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);
+               }
+               else {
+                       char* oldMessage = pos->second;
+                       char* newMesssage;
+                       asprintf(&newMesssage, "%s, %s", oldMessage, message);
+                       sPageToContent[p] = newMesssage;
+                       free(oldMessage);
+               }
+       }
+}
+
+
+/*
+ * get LINKEDIT info for dylib
+ */
+template <typename A>
+void process_linkedit(const char* dylib, void* headerAddr) {   
+       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 )
+               return;
+       seenImages.insert(headerAddr);
+       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++) {
+               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;
+                       // 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 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 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 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);
+                       }
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }
+}
+
+
+
+/*
+ * This callback is used with dsc_iterator, and called once for each segment in the target shared cache
+ */
+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;
+       }
+}
+
+
+
+
+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;
+    
+    for (uint32_t optind = 1; optind < argc; optind++) {
+        char *opt = argv[optind];
+        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)) {
+                    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 {
+                fprintf(stderr, "Error: unrecognized option %s\n", opt);
+                usage();
+                exit(1);
+            }
+        } else {
+            shared_cache_path = opt;
+        }
+    }
+    
+       if ( !print_slide_info ) {
+               if (args.op == OP_NULL) {
+                       fprintf(stderr, "Error: select one of -list or -dependents\n");
+                       usage();
+                       exit(1);
+               }
+               
+               if (args.print_uuids && args.op != OP_LIST_DYLIBS)
+                       fprintf(stderr, "Warning: -uuid option ignored outside of -list mode\n");
+               if (args.print_vmaddrs && args.op != OP_LIST_DYLIBS)
+                       fprintf(stderr, "Warning: -vmaddr option ignored outside of -list mode\n");
+               if (args.print_dylib_versions && args.op != OP_LIST_DEPENDENCIES)
+                       fprintf(stderr, "Warning: -versions option ignored outside of -dependents mode\n");
+               
+               if (args.op == OP_LIST_DEPENDENCIES && !args.target_path) {
+                       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);
+               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);
+               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);
+               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) ) {
+                       fprintf(stderr, "Error: unrecognized dyld shared cache magic or arch does not support sliding\n");
+                       exit(1);
+               }
+               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>* dataMapping = &mappings[1];
+               uint64_t dataStartAddress = dataMapping->address();
+               uint64_t dataSize = dataMapping->size();
+               const dyldCacheSlideInfo<LittleEndian>* slideInfoHeader = (dyldCacheSlideInfo<LittleEndian>*)((char*)mapped_cache+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());
+               for(int i=0; i < slideInfoHeader->toc_count(); ++i) {
+                       printf("0x%08llX: [% 5d,% 5d] ", dataStartAddress + i*4096, i, slideInfoHeader->toc(i));
+                       const dyldCacheSlideInfoEntry* entry = &entries[slideInfoHeader->toc(i)];
+                       for(int j=0; j < slideInfoHeader->entries_size(); ++j)
+                               printf("%02X", entry->bits[j]);
+                       printf("\n");
+               }
+               
+
+       }
+       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     ppc") == 0 ) 
+                       callback = segment_callback<ppc>;
+               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 {
+                       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);
+                                                                                  });
+       #else
+               dyld_shared_cache_iterate_segments_with_slide_nb(mapped_cache, callback, &args);
+       #endif
+               
+               if (args.op == OP_LIST_LINKEDIT) {
+                       // 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);
+                       }
+               }
+               
+               
+               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);
+                       exit(1);
+               }
+       }
+       return 0;
+}
index 704aa81c133c9168b5ce72ac1d92e7139ae2ee9b..c7a3874b9a11d379d092e722768eca189bea818b 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
- * Copyright (c) 2006-2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2006-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -44,8 +44,6 @@
 #include <servers/bootstrap.h>
 #include <mach-o/loader.h>
 #include <mach-o/fat.h>
 #include <servers/bootstrap.h>
 #include <mach-o/loader.h>
 #include <mach-o/fat.h>
-#include <vproc.h>
-#include <vproc_priv.h>
 
 #include "dyld_cache_format.h"
 
 
 #include "dyld_cache_format.h"
 
 #define SELOPT_WRITE
 #include <objc/objc-selopt.h>
 
 #define SELOPT_WRITE
 #include <objc/objc-selopt.h>
 
+#define FIRST_DYLIB_TEXT_OFFSET 0x5000
+#define FIRST_DYLIB_DATA_OFFSET 0x1000
+
+#ifndef LC_FUNCTION_STARTS
+    #define LC_FUNCTION_STARTS 0x26
+#endif
 
 static bool                                                    verbose = false;
 static bool                                                    progress = false;
 
 static bool                                                    verbose = false;
 static bool                                                    progress = false;
+static bool                                                    iPhoneOS = false;
 static std::vector<const char*>                warnings;
 
 
 static std::vector<const char*>                warnings;
 
 
@@ -95,6 +100,11 @@ static uint64_t pageAlign(uint64_t addr) { return ( (addr + 4095) & (-4096) ); }
 class ArchGraph
 {
 public:
 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;
+
        static void                     addArchPair(ArchPair ap);
        static void                     addRoot(const char* vpath, const std::set<ArchPair>& archs);
        static void                     findSharedDylibs(ArchPair ap);
        static void                     addArchPair(ArchPair ap);
        static void                     addRoot(const char* vpath, const std::set<ArchPair>& archs);
        static void                     findSharedDylibs(ArchPair ap);
@@ -104,6 +114,7 @@ public:
        
        ArchPair                                                                                        getArchPair() { return fArchPair; }
        std::set<const class MachOLayoutAbstraction*>&          getSharedDylibs() { return fSharedDylibs; }
        
        ArchPair                                                                                        getArchPair() { return fArchPair; }
        std::set<const class MachOLayoutAbstraction*>&          getSharedDylibs() { return fSharedDylibs; }
+       StringToString&                                                                         getDylibAliases() { return fAliasesMap; }
        const char*                                                                                     archName() { return archName(fArchPair); }
        
 private:
        const char*                                                                                     archName() { return archName(fArchPair); }
        
 private:
@@ -128,9 +139,6 @@ private:
                std::set<DependencyNode*>                                       fRootsDependentOnThis;
        };
 
                std::set<DependencyNode*>                                       fRootsDependentOnThis;
        };
 
-       struct CStringEquals {
-               bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
-       };
        typedef __gnu_cxx::hash_map<const char*, class DependencyNode*, __gnu_cxx::hash<const char*>, CStringEquals> PathToNode;
 
 
        typedef __gnu_cxx::hash_map<const char*, class DependencyNode*, __gnu_cxx::hash<const char*>, CStringEquals> PathToNode;
 
 
@@ -139,6 +147,7 @@ private:
        DependencyNode*                         getNode(const char* path);
        DependencyNode*                         getNodeForVirtualPath(const char* vpath);
        static bool                                     canBeShared(const MachOLayoutAbstraction* layout, ArchPair ap, const std::set<const MachOLayoutAbstraction*>& possibleLibs, std::map<const MachOLayoutAbstraction*, bool>& shareableMap);
        DependencyNode*                         getNode(const char* path);
        DependencyNode*                         getNodeForVirtualPath(const char* vpath);
        static bool                                     canBeShared(const MachOLayoutAbstraction* layout, ArchPair ap, const std::set<const MachOLayoutAbstraction*>& possibleLibs, std::map<const MachOLayoutAbstraction*, bool>& shareableMap);
+       static bool                                     sharable(const MachOLayoutAbstraction* layout, ArchPair ap, char** msg);
 
        static std::map<ArchPair, ArchGraph*>   fgPerArchGraph;
        static const char*                                              fgFileSystemRoot;
 
        static std::map<ArchPair, ArchGraph*>   fgPerArchGraph;
        static const char*                                              fgFileSystemRoot;
@@ -148,6 +157,7 @@ private:
        std::set<DependencyNode*>                                       fRoots;
        PathToNode                                                                      fNodes;
        std::set<const MachOLayoutAbstraction*>         fSharedDylibs;  // use set to avoid duplicates when installname!=realpath
        std::set<DependencyNode*>                                       fRoots;
        PathToNode                                                                      fNodes;
        std::set<const MachOLayoutAbstraction*>         fSharedDylibs;  // use set to avoid duplicates when installname!=realpath
+       StringToString                                                          fAliasesMap;
 };
 std::map<ArchPair, ArchGraph*>         ArchGraph::fgPerArchGraph;
 const char*                                                    ArchGraph::fgFileSystemRoot = "";
 };
 std::map<ArchPair, ArchGraph*>         ArchGraph::fgPerArchGraph;
 const char*                                                    ArchGraph::fgFileSystemRoot = "";
@@ -187,17 +197,18 @@ void ArchGraph::addRoot(const char* vpath, const std::set<ArchPair>& onlyArchs)
                for(std::set<ArchPair>::iterator ait = onlyArchs.begin(); ait != onlyArchs.end(); ++ait) {
                        try {
                                const MachOLayoutAbstraction* layout = uni.getSlice(*ait);
                for(std::set<ArchPair>::iterator ait = onlyArchs.begin(); ait != onlyArchs.end(); ++ait) {
                        try {
                                const MachOLayoutAbstraction* layout = uni.getSlice(*ait);
-                               fgPerArchGraph[*ait]->addRoot(path, layout);
+                               if ( layout != NULL )
+                                       fgPerArchGraph[*ait]->addRoot(path, layout);
                        }
                        catch (const char* msg) {
                                if ( verbose ) 
                        }
                        catch (const char* msg) {
                                if ( verbose ) 
-                                       fprintf(stderr, "update_dyld_shared_cache: warning for %s can't use root %s: %s\n", fgPerArchGraph[*ait]->archName(), path, msg);
+                                       fprintf(stderr, "update_dyld_shared_cache: warning for %s can't use root '%s': %s\n", fgPerArchGraph[*ait]->archName(), path, msg);
                        }
                        
                }
        }
        catch (const char* msg) {
                        }
                        
                }
        }
        catch (const char* msg) {
-               fprintf(stderr, "update_dyld_shared_cache: warning can't use root %s: %s\n", path, msg);
+               fprintf(stderr, "update_dyld_shared_cache: warning can't use root '%s': %s\n", path, msg);
        }
 }
 
        }
 }
 
@@ -218,6 +229,7 @@ void ArchGraph::addRoot(const char* path, const MachOLayoutAbstraction* layout)
                node->markNeededByRoot(NULL);
 }
 
                node->markNeededByRoot(NULL);
 }
 
+// a virtual path does not have the fgFileSystemRoot prefix
 // a virtual path does not have the fgFileSystemRoot prefix
 ArchGraph::DependencyNode* ArchGraph::getNodeForVirtualPath(const char* vpath)
 {
 // a virtual path does not have the fgFileSystemRoot prefix
 ArchGraph::DependencyNode* ArchGraph::getNodeForVirtualPath(const char* vpath)
 {
@@ -229,12 +241,32 @@ ArchGraph::DependencyNode* ArchGraph::getNodeForVirtualPath(const char* vpath)
                strcpy(completePath, fgFileSystemRoot);
                strcat(completePath, vpath);    // assumes vpath starts with '/'
                if ( fgUsesOverlay ) {
                strcpy(completePath, fgFileSystemRoot);
                strcat(completePath, vpath);    // assumes vpath starts with '/'
                if ( fgUsesOverlay ) {
-                       // using -overlay means if /overlay/usr/lib exists use it, otherwise use original path
+                       // using -overlay means if /overlay/path/dylib exists use it, otherwise use /path/dylib
                        struct stat stat_buf;
                        if ( stat(completePath, &stat_buf) == 0 )
                                return this->getNode(completePath);
                        struct stat stat_buf;
                        if ( stat(completePath, &stat_buf) == 0 )
                                return this->getNode(completePath);
-                       else
+                       else {
+                               // <rdar://problem/9279770> support when install name is a symlink
+                               if ( (lstat(vpath, &stat_buf) == 0) && S_ISLNK(stat_buf.st_mode) ) {
+                                       // requested path did not exist in /overlay, but leaf of path is a symlink in /
+                                       char pathInSymLink[MAXPATHLEN];
+                                       size_t res = readlink(vpath, pathInSymLink, sizeof(pathInSymLink));
+                                       if ( res != -1 ) {
+                                               pathInSymLink[res] = '\0';
+                                               if ( pathInSymLink[0] != '/' ) {
+                                                       char symFullPath[MAXPATHLEN];
+                                                       strcpy(symFullPath, vpath);
+                                                       char* lastSlash = strrchr(symFullPath, '/');
+                                                       if ( lastSlash != NULL ) {
+                                                               strcpy(lastSlash+1, pathInSymLink);
+                                                               // (re)try looking for what symlink points to, but in /overlay
+                                                               return this->getNodeForVirtualPath(symFullPath);
+                                                       }
+                                               } 
+                                       }
+                               }
                                return this->getNode(vpath);
                                return this->getNode(vpath);
+                       }
                }
                else {
                        // using -root means always use /rootpath/usr/lib
                }
                else {
                        // using -root means always use /rootpath/usr/lib
@@ -257,8 +289,20 @@ ArchGraph::DependencyNode* ArchGraph::getNode(const char* path)
        
        // look up real path to see if node already exists
        pos = fNodes.find(realPath);
        
        // look up real path to see if node already exists
        pos = fNodes.find(realPath);
-       if ( pos != fNodes.end() )
+       if ( pos != fNodes.end() ) {
+               // update fAliasesMap with symlinks found
+               const char* aliasPath = path;
+               if ( (fgFileSystemRoot != NULL) && (strncmp(path, fgFileSystemRoot, strlen(fgFileSystemRoot)) == 0) ) {
+                       aliasPath = &path[strlen(fgFileSystemRoot)];
+               }
+               if ( fAliasesMap.find(aliasPath) == fAliasesMap.end() ) {
+                       if ( strcmp(aliasPath, pos->second->getLayout()->getID().name) != 0 ) {
+                               fAliasesMap[strdup(aliasPath)] = pos->second->getLayout()->getID().name;
+                               //fprintf(stderr, "getNode() %s: added alias %s -> %s\n", archName(fArchPair), aliasPath, fAliasesMap[aliasPath]);
+                       }
+               }
                return pos->second;
                return pos->second;
+       }
        
        // still does not exist, so create a new node
        const UniversalMachOLayout& uni = UniversalMachOLayout::find(realPath);
        
        // still does not exist, so create a new node
        const UniversalMachOLayout& uni = UniversalMachOLayout::find(realPath);
@@ -270,8 +314,29 @@ ArchGraph::DependencyNode* ArchGraph::getNode(const char* path)
        fNodes[node->getPath()] = node;
        // if install name is not real path, add install name to node map
        if ( (node->getLayout()->getFileType() == MH_DYLIB) && (strcmp(realPath, node->getLayout()->getID().name) != 0) ) {
        fNodes[node->getPath()] = node;
        // if install name is not real path, add install name to node map
        if ( (node->getLayout()->getFileType() == MH_DYLIB) && (strcmp(realPath, node->getLayout()->getID().name) != 0) ) {
-               //fprintf(stderr, "adding node alias 0x%08X %s for %s\n", fArch, node->getLayout()->getID().name, realPath);
-               fNodes[node->getLayout()->getID().name] = node;
+               //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);
+               }
+               else
+                       fNodes[node->getLayout()->getID().name] = node;
+               // update fAliasesMap with symlinks found
+               const char* aliasPath = realPath;
+               if ( (fgFileSystemRoot != NULL) && (strncmp(realPath, fgFileSystemRoot, strlen(fgFileSystemRoot)) == 0) ) {
+                       aliasPath = &realPath[strlen(fgFileSystemRoot)];
+               }
+               if ( fAliasesMap.find(aliasPath) == fAliasesMap.end() ) {
+                       if ( strcmp(aliasPath, node->getLayout()->getID().name) != 0 ) {
+                               fAliasesMap[strdup(aliasPath)] = node->getLayout()->getID().name;
+                               //fprintf(stderr, "getNode() %s: added alias %s -> %s\n", archName(fArchPair), aliasPath, fAliasesMap[aliasPath]);
+                       }
+               }
        }
        return node;
 }
        }
        return node;
 }
@@ -292,7 +357,13 @@ void ArchGraph::DependencyNode::loadDependencies(const MachOLayoutAbstraction* m
                                        // expand @executable_path path prefix
                                        const char* executablePath = mainExecutableLayout->getFilePath();
                                        char newPath[strlen(executablePath) + strlen(dependentPath)+2];
                                        // expand @executable_path path prefix
                                        const char* executablePath = mainExecutableLayout->getFilePath();
                                        char newPath[strlen(executablePath) + strlen(dependentPath)+2];
-                                       strcpy(newPath, executablePath);
+                                       if ( (fgFileSystemRoot != NULL) && (strncmp(executablePath, fgFileSystemRoot, strlen(fgFileSystemRoot)) == 0) ) {
+                                               // executablePath already has rootPath prefix, need to remove that to get to base virtual path
+                                               strcpy(newPath, &executablePath[strlen(fgFileSystemRoot)]);
+                                       }
+                                       else {
+                                               strcpy(newPath, executablePath);
+                                       }
                                        char* addPoint = strrchr(newPath,'/');
                                        if ( addPoint != NULL )
                                                strcpy(&addPoint[1], &dependentPath[17]);
                                        char* addPoint = strrchr(newPath,'/');
                                        if ( addPoint != NULL )
                                                strcpy(&addPoint[1], &dependentPath[17]);
@@ -303,7 +374,13 @@ void ArchGraph::DependencyNode::loadDependencies(const MachOLayoutAbstraction* m
                                else if ( strncmp(dependentPath, "@loader_path/", 13) == 0 ) {
                                        // expand @loader_path path prefix
                                        char newPath[strlen(fPath) + strlen(dependentPath)+2];
                                else if ( strncmp(dependentPath, "@loader_path/", 13) == 0 ) {
                                        // expand @loader_path path prefix
                                        char newPath[strlen(fPath) + strlen(dependentPath)+2];
-                                       strcpy(newPath, fPath);
+                                       if ( (fgFileSystemRoot != NULL) && (strncmp(fPath, fgFileSystemRoot, strlen(fgFileSystemRoot)) == 0) ) {
+                                               // fPath already has rootPath prefix, need to remove that to get to base virtual path
+                                               strcpy(newPath, &fPath[strlen(fgFileSystemRoot)]);
+                                       }
+                                       else {
+                                               strcpy(newPath, fPath);
+                                       }
                                        char* addPoint = strrchr(newPath,'/');
                                        if ( addPoint != NULL )
                                                strcpy(&addPoint[1], &dependentPath[13]);
                                        char* addPoint = strrchr(newPath,'/');
                                        if ( addPoint != NULL )
                                                strcpy(&addPoint[1], &dependentPath[13]);
@@ -314,7 +391,15 @@ void ArchGraph::DependencyNode::loadDependencies(const MachOLayoutAbstraction* m
                                else if ( strncmp(dependentPath, "@rpath/", 7) == 0 ) {
                                        throw "@rpath not supported in dyld shared cache";
                                }
                                else if ( strncmp(dependentPath, "@rpath/", 7) == 0 ) {
                                        throw "@rpath not supported in dyld shared cache";
                                }
-                               fDependsOn.insert(fGraph->getNodeForVirtualPath(dependentPath));
+                               // <rdar://problem/9161945> silently ignore dependents from main executables that can't be in shared cache
+                               bool addDependent = true;
+                               if ( fLayout->getFileType() == MH_EXECUTE ) {
+                                       if ( (strncmp(dependentPath, "/usr/lib/", 9) != 0) && (strncmp(dependentPath, "/System/Library/", 16) != 0) ) {
+                                               addDependent = false;
+                                       }
+                               }
+                               if ( addDependent )
+                                       fDependsOn.insert(fGraph->getNodeForVirtualPath(dependentPath));
                        }
                        catch (const char* msg) {
                                if ( it->weakImport && ! fLayout->hasSplitSegInfo() ) {
                        }
                        catch (const char* msg) {
                                if ( it->weakImport && ! fLayout->hasSplitSegInfo() ) {
@@ -355,15 +440,27 @@ void ArchGraph::findSharedDylibs(ArchPair ap)
 {
        const PathToNode& nodes = fgPerArchGraph[ap]->fNodes;
        std::set<const MachOLayoutAbstraction*> possibleLibs;
 {
        const PathToNode& nodes = fgPerArchGraph[ap]->fNodes;
        std::set<const MachOLayoutAbstraction*> possibleLibs;
-       //fprintf(stderr, "shared for arch 0x%08X\n", arch);
+       //fprintf(stderr, "shared for arch %s\n", archName(ap));
        for(PathToNode::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
                DependencyNode* node = it->second;
                // <rdar://problem/6127437> put all dylibs in shared cache - not just ones used by more than one app
                if ( node->allDependentsFound() /*&& (node->useCount() > 1)*/ ) {
                        const MachOLayoutAbstraction* layout = node->getLayout();
        for(PathToNode::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
                DependencyNode* node = it->second;
                // <rdar://problem/6127437> put all dylibs in shared cache - not just ones used by more than one app
                if ( node->allDependentsFound() /*&& (node->useCount() > 1)*/ ) {
                        const MachOLayoutAbstraction* layout = node->getLayout();
-                       if ( layout->hasSplitSegInfo() && layout->isRootOwned() && layout->inSharableLocation() ) 
-                               possibleLibs.insert(layout);
-                       //fprintf(stderr, "\t%s\n", it->first);
+                       if ( layout->isDylib() ) {
+                               char* msg;
+                               if ( sharable(layout, ap, &msg) ) {
+                                       possibleLibs.insert(layout);
+                               }
+                               else {
+                                       if ( layout->getID().name[0] == '@' ) {
+                                               // <rdar://problem/7770139> update_dyld_shared_cache should suppress warnings for embedded frameworks
+                                       }
+                                       else {
+                                               warnings.push_back(msg);
+                                               fprintf(stderr, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap), msg);
+                                       }
+                               }
+                       }
                }
        }
        
                }
        }
        
@@ -405,6 +502,27 @@ const char*        ArchGraph::archName(ArchPair ap)
        }
 }
 
        }
 }
 
+bool ArchGraph::sharable(const MachOLayoutAbstraction* layout, ArchPair ap, char** msg)
+{
+       if ( ! layout->isTwoLevelNamespace() ) 
+               asprintf(msg, "can't put %s in shared cache because it was built -flat_namespace", layout->getID().name);
+       else if ( ! layout->hasSplitSegInfo() ) 
+               asprintf(msg, "can't put %s in shared cache because it was not built for %s or later", layout->getID().name, (iPhoneOS ? "iPhoneOS 3.1" : "MacOSX 10.5"));
+       else if ( ! layout->isRootOwned() )
+               asprintf(msg, "can't put %s in shared cache because it is not owned by root", layout->getID().name);
+       else if ( ! layout->inSharableLocation() )
+               asprintf(msg, "can't put %s in shared cache because it is not in /usr/lib or /System/Library", layout->getID().name);
+       else if ( layout->hasDynamicLookupLinkage() )
+               asprintf(msg, "can't put %s in shared cache because it was built with '-undefined dynamic_lookup'", layout->getID().name);
+       else if ( layout->hasMainExecutableLookupLinkage() )
+               asprintf(msg, "can't put %s in shared cache because it was built with '-bundle_loader'", layout->getID().name);
+       //else if ( ! layout->hasDyldInfo() )
+       //      asprintf(msg, "can't put %s in shared cache because it was built for older OS", layout->getID().name);
+       else
+               return true;
+       return false;
+}
+
 bool ArchGraph::canBeShared(const MachOLayoutAbstraction* layout, ArchPair ap, const std::set<const MachOLayoutAbstraction*>& possibleLibs, std::map<const MachOLayoutAbstraction*, bool>& shareableMap)
 {
        // check map which is a cache of results
 bool ArchGraph::canBeShared(const MachOLayoutAbstraction* layout, ArchPair ap, const std::set<const MachOLayoutAbstraction*>& possibleLibs, std::map<const MachOLayoutAbstraction*, bool>& shareableMap)
 {
        // check map which is a cache of results
@@ -416,14 +534,8 @@ bool ArchGraph::canBeShared(const MachOLayoutAbstraction* layout, ArchPair ap, c
        if ( possibleLibs.count(layout) == 0 ) {
                shareableMap[layout] = false;
                char* msg;
        if ( possibleLibs.count(layout) == 0 ) {
                shareableMap[layout] = false;
                char* msg;
-               if ( ! layout->hasSplitSegInfo() )
-                       asprintf(&msg, "can't put %s in shared cache because it was not built for 10.5 or later", layout->getID().name);
-               else if ( ! layout->isRootOwned() )
-                       asprintf(&msg, "can't put %s in shared cache because it is not owned by root", layout->getID().name);
-               else if ( ! layout->inSharableLocation() )
-                       asprintf(&msg, "can't put %s in shared cache because it is not in /usr/lib or /System/Library", layout->getID().name);
-               else
-                       asprintf(&msg, "can't put %s in shared cache", layout->getID().name);
+               if ( sharable(layout, ap, &msg) )
+                       asprintf(&msg, "can't put %s in shared cache, unknown reason", layout->getID().name);
                warnings.push_back(msg);
                if ( verbose )
                        fprintf(stderr, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap), msg);
                warnings.push_back(msg);
                if ( verbose )
                        fprintf(stderr, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap), msg);
@@ -470,22 +582,28 @@ template <typename A>
 class SharedCache
 {
 public:
 class SharedCache
 {
 public:
-                                                       SharedCache(ArchGraph* graph, const char* rootPath, bool alphaSort, bool verify, bool optimize, bool overlay, uint64_t dyldBaseAddress);
+                                                       SharedCache(ArchGraph* graph, const char* rootPath, const char* cacheDir, bool alphaSort, bool verify, bool optimize, bool overlay, uint64_t dyldBaseAddress);
        bool                                    update(bool usesOverlay, bool force, bool optimize, bool deleteExistingFirst, int archIndex, 
                                                                                int archCount, bool keepSignatures);
        static const char*              cacheFileSuffix(bool optimized, const char* archName);
 
        bool                                    update(bool usesOverlay, bool force, bool optimize, bool deleteExistingFirst, int archIndex, 
                                                                                int archCount, bool keepSignatures);
        static const char*              cacheFileSuffix(bool optimized, const char* archName);
 
-    uint64_t                           mappedCacheAddressForAddress(uint64_t addr);
+    // vm address = address AS WRITTEN into the cache
+    // mapped address = address AS MAPPED into the update process only
+    // file offset = offset relative to start of cache file
+    void *                                     mappedAddressForVMAddress(uint64_t vmaddr);
+    uint64_t                           VMAddressForMappedAddress(const void *mapaddr);
+       uint64_t                                cacheFileOffsetForVMAddress(uint64_t addr) const;
+       uint64_t                                VMAddressForCacheFileOffset(uint64_t addr) const;
 
 private:
        typedef typename A::P                   P;
     typedef typename A::P::E           E;
     typedef typename A::P::uint_t      pint_t;
 
 
 private:
        typedef typename A::P                   P;
     typedef typename A::P::E           E;
     typedef typename A::P::uint_t      pint_t;
 
-       bool                                    notUpToDate(const char* path);
-       bool                                    notUpToDate(const void* cache);
+       bool                                    notUpToDate(const char* path, unsigned int aliasCount);
+       bool                                    notUpToDate(const void* cache, unsigned int aliasCount);
        uint8_t*                                optimizeLINKEDIT(bool keepSignatures);
        uint8_t*                                optimizeLINKEDIT(bool keepSignatures);
-       void                                    optimizeObjC();
+       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 void                             getSharedCacheBasAddresses(cpu_type_t arch, uint64_t* baseReadOnly, uint64_t* baseWritable);
        static cpu_type_t               arch();
@@ -495,13 +613,13 @@ private:
        static uint64_t                 sharedRegionReadOnlySize();
        static uint64_t                 sharedRegionWritableSize();
        static uint64_t                 getWritableSegmentNewAddress(uint64_t proposedNewAddress, uint64_t originalAddress, uint64_t executableSlide);
        static uint64_t                 sharedRegionReadOnlySize();
        static uint64_t                 sharedRegionWritableSize();
        static uint64_t                 getWritableSegmentNewAddress(uint64_t proposedNewAddress, uint64_t originalAddress, uint64_t executableSlide);
+       static bool                             addCacheSlideInfo();
        
        
-       
-       void                                    assignNewBaseAddresses();
-       uint64_t                                cacheFileOffsetForAddress(uint64_t addr);
+       void                                    assignNewBaseAddresses(bool verify);
 
        struct LayoutInfo {
                const MachOLayoutAbstraction*           layout;
 
        struct LayoutInfo {
                const MachOLayoutAbstraction*           layout;
+               std::vector<const char*>                        aliases;
                dyld_cache_image_info                           info;
        };
        
                dyld_cache_image_info                           info;
        };
        
@@ -520,8 +638,8 @@ private:
                 // one image has no segments
                 return segs_l.size() > segs_r.size();
             }
                 // one image has no segments
                 return segs_l.size() > segs_r.size();
             }
-            const macho_header<P> *mh_l = (const macho_header<P>*)segs_l[0].mappedAddress();
-            const macho_header<P> *mh_r = (const macho_header<P>*)segs_r[0].mappedAddress();
+            const macho_header<P> *mh_l = (macho_header<P>*)segs_l[0].mappedAddress();
+            const macho_header<P> *mh_r = (macho_header<P>*)segs_r[0].mappedAddress();
             const macho_section<P> *cstring_l = mh_l->getSection("__TEXT", "__cstring");
             const macho_section<P> *cstring_r = mh_r->getSection("__TEXT", "__cstring");
             if (!cstring_l  ||  !cstring_r) {
             const macho_section<P> *cstring_l = mh_l->getSection("__TEXT", "__cstring");
             const macho_section<P> *cstring_r = mh_r->getSection("__TEXT", "__cstring");
             if (!cstring_l  ||  !cstring_r) {
@@ -542,13 +660,15 @@ private:
                std::map<const MachOLayoutAbstraction*, uint32_t>& fMap;
        };
        
                std::map<const MachOLayoutAbstraction*, uint32_t>& fMap;
        };
        
-
+       
        ArchGraph*                                                      fArchGraph;
        const bool                                                      fVerify;
        bool                                                            fExistingIsNotUpToDate;
        ArchGraph*                                                      fArchGraph;
        const bool                                                      fVerify;
        bool                                                            fExistingIsNotUpToDate;
+       bool                                                            fCacheFileInFinalLocation;
        const char*                                                     fCacheFilePath;
        uint8_t*                                                        fExistingCacheForVerification;
        std::vector<LayoutInfo>                         fDylibs;
        const char*                                                     fCacheFilePath;
        uint8_t*                                                        fExistingCacheForVerification;
        std::vector<LayoutInfo>                         fDylibs;
+       std::vector<LayoutInfo>                         fDylibAliases;
        std::vector<shared_file_mapping_np>     fMappings;
        uint32_t                                                        fHeaderSize;
     uint8_t*                                                   fInMemoryCache;
        std::vector<shared_file_mapping_np>     fMappings;
        uint32_t                                                        fHeaderSize;
     uint8_t*                                                   fInMemoryCache;
@@ -561,6 +681,15 @@ private:
        uint32_t                                                        fOffsetOfLazyBindInfoInCombinedLinkedit;
        uint32_t                                                        fOffsetOfExportInfoInCombinedLinkedit;
        uint32_t                                                        fOffsetOfOldSymbolTableInfoInCombinedLinkedit;
        uint32_t                                                        fOffsetOfLazyBindInfoInCombinedLinkedit;
        uint32_t                                                        fOffsetOfExportInfoInCombinedLinkedit;
        uint32_t                                                        fOffsetOfOldSymbolTableInfoInCombinedLinkedit;
+       uint32_t                                                        fSizeOfOldSymbolTableInfoInCombinedLinkedit;
+       uint32_t                                                        fOffsetOfOldExternalRelocationsInCombinedLinkedit;
+       uint32_t                                                        fSizeOfOldExternalRelocationsInCombinedLinkedit;
+       uint32_t                                                        fOffsetOfOldIndirectSymbolsInCombinedLinkedit;
+       uint32_t                                                        fSizeOfOldIndirectSymbolsInCombinedLinkedit;
+       uint32_t                                                        fOffsetOfOldStringPoolInCombinedLinkedit;
+       uint32_t                                                        fSizeOfOldStringPoolInCombinedLinkedit;
+       uint32_t                                                        fOffsetOfFunctionStartsInCombinedLinkedit;
+       uint32_t                                                        fSizeOfFunctionStartsInCombinedLinkedit;
        uint32_t                                                        fLinkEditsTotalOptimizedSize;
 };
 
        uint32_t                                                        fLinkEditsTotalOptimizedSize;
 };
 
@@ -572,17 +701,17 @@ class PointerSection
     typedef typename A::P P;
     typedef typename A::P::uint_t pint_t;
 
     typedef typename A::P P;
     typedef typename A::P::uint_t pint_t;
 
-    SharedCache<A>* const fCache;
-    const macho_section<P>* const fSection;
-    pint_t * const fBase;
-    uint64_t const fCount;
+    SharedCache<A>* const                      fCache;
+    const macho_section<P>* const      fSection;
+    pint_t * const                                     fBase;
+    uint64_t                                           fCount;
 
 public:
     PointerSection(SharedCache<A>* cache, const macho_header<P>* header, 
                    const char *segname, const char *sectname)
         : fCache(cache)
         , fSection(header->getSection(segname, sectname))
 
 public:
     PointerSection(SharedCache<A>* cache, const macho_header<P>* header, 
                    const char *segname, const char *sectname)
         : fCache(cache)
         , fSection(header->getSection(segname, sectname))
-        , fBase(fSection ? (pint_t *)cache->mappedCacheAddressForAddress(fSection->addr()) : 0)
+        , fBase(fSection ? (pint_t *)cache->mappedAddressForVMAddress(fSection->addr()) : 0)
         , fCount(fSection ? fSection->size() / sizeof(pint_t) : 0)
     {
     }
         , fCount(fSection ? fSection->size() / sizeof(pint_t) : 0)
     {
     }
@@ -595,13 +724,27 @@ public:
     }
 
     T get(uint64_t index) const { 
     }
 
     T get(uint64_t index) const { 
-        return (T)fCache->mappedCacheAddressForAddress(getUnmapped(index));
+        return (T)fCache->mappedAddressForVMAddress(getUnmapped(index));
     }
 
     void set(uint64_t index, uint64_t value) {
         if (index >= fCount) throwf("index out of range");
         P::setP(fBase[index], value);
     }
     }
 
     void set(uint64_t index, uint64_t value) {
         if (index >= fCount) throwf("index out of range");
         P::setP(fBase[index], value);
     }
+       
+    void removeNulls() {
+        uint64_t shift = 0;
+        for (uint64_t i = 0; i < fCount; i++) {
+            pint_t value = fBase[i];
+            if (value) {
+                fBase[i-shift] = value;
+            } else {
+                shift++;
+            }
+        }
+        fCount -= shift;
+               const_cast<macho_section<P>*>(fSection)->set_size(fCount * sizeof(pint_t));
+    }
 };
 
 // Access a section containing an array of structures
 };
 
 // Access a section containing an array of structures
@@ -620,7 +763,7 @@ public:
                  const char *segname, const char *sectname)
         : fCache(cache)
         , fSection(header->getSection(segname, sectname))
                  const char *segname, const char *sectname)
         : fCache(cache)
         , fSection(header->getSection(segname, sectname))
-        , fBase(fSection ? (T *)cache->mappedCacheAddressForAddress(fSection->addr()) : 0)
+        , fBase(fSection ? (T *)cache->mappedAddressForVMAddress(fSection->addr()) : 0)
         , fCount(fSection ? fSection->size() / sizeof(T) : 0)
     {
     }
         , fCount(fSection ? fSection->size() / sizeof(T) : 0)
     {
     }
@@ -651,19 +794,19 @@ template <>        uint64_t       SharedCache<x86_64>::sharedRegionReadOnlyStartAddress() {
 template <>     uint64_t       SharedCache<arm>::sharedRegionReadOnlyStartAddress()    { return 0x30000000; }
 
 template <>     uint64_t       SharedCache<ppc>::sharedRegionWritableStartAddress()    { return 0xA0000000; }
 template <>     uint64_t       SharedCache<arm>::sharedRegionReadOnlyStartAddress()    { return 0x30000000; }
 
 template <>     uint64_t       SharedCache<ppc>::sharedRegionWritableStartAddress()    { return 0xA0000000; }
-template <>     uint64_t       SharedCache<x86>::sharedRegionWritableStartAddress()    { return 0xA0000000; }
+template <>     uint64_t       SharedCache<x86>::sharedRegionWritableStartAddress()    { return 0xAC000000; }
 template <>     uint64_t       SharedCache<x86_64>::sharedRegionWritableStartAddress() { return 0x7FFF70000000LL; }
 template <>     uint64_t       SharedCache<x86_64>::sharedRegionWritableStartAddress() { return 0x7FFF70000000LL; }
-template <>     uint64_t       SharedCache<arm>::sharedRegionWritableStartAddress()    { return 0x38000000; }
+template <>     uint64_t       SharedCache<arm>::sharedRegionWritableStartAddress()    { return 0x3E000000; }
 
 template <>     uint64_t       SharedCache<ppc>::sharedRegionReadOnlySize()                    { return 0x10000000; }
 
 template <>     uint64_t       SharedCache<ppc>::sharedRegionReadOnlySize()                    { return 0x10000000; }
-template <>     uint64_t       SharedCache<x86>::sharedRegionReadOnlySize()                    { return 0x10000000; }
-template <>     uint64_t       SharedCache<x86_64>::sharedRegionReadOnlySize()                 { return 0x7FE00000; }
-template <>     uint64_t       SharedCache<arm>::sharedRegionReadOnlySize()                    { return 0x08000000; }
+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<ppc>::sharedRegionWritableSize()                    { return 0x10000000; }
 
 template <>     uint64_t       SharedCache<ppc>::sharedRegionWritableSize()                    { return 0x10000000; }
-template <>     uint64_t       SharedCache<x86>::sharedRegionWritableSize()                    { return 0x10000000; }
-template <>     uint64_t       SharedCache<x86_64>::sharedRegionWritableSize()                 { return 0x20000000; }
-template <>     uint64_t       SharedCache<arm>::sharedRegionWritableSize()                    { return 0x08000000; }
+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 <>     const char*    SharedCache<ppc>::archName()    { return "ppc"; }
 
 
 template <>     const char*    SharedCache<ppc>::archName()    { return "ppc"; }
@@ -677,15 +820,25 @@ template <>        const char*    SharedCache<x86_64>::cacheFileSuffix(bool, const char*
 template <>     const char*    SharedCache<arm>::cacheFileSuffix(bool, const char* archName)   { return archName; }
 
 template <typename A>
 template <>     const char*    SharedCache<arm>::cacheFileSuffix(bool, const char* archName)   { return archName; }
 
 template <typename A>
-SharedCache<A>::SharedCache(ArchGraph* graph, const char* rootPath, bool alphaSort, bool verify, bool optimize, bool overlay, uint64_t dyldBaseAddress) 
-  : fArchGraph(graph), fVerify(verify), fExistingIsNotUpToDate(true), fCacheFilePath(NULL),
-       fExistingCacheForVerification(NULL), fDyldBaseAddress(dyldBaseAddress)
+SharedCache<A>::SharedCache(ArchGraph* graph, const char* rootPath, const char* cacheDir, bool alphaSort, bool verify, bool optimize, bool overlay, uint64_t dyldBaseAddress) 
+  : fArchGraph(graph), fVerify(verify), fExistingIsNotUpToDate(true), 
+       fCacheFileInFinalLocation(rootPath[0] == '\0'), fCacheFilePath(NULL),
+       fExistingCacheForVerification(NULL), fDyldBaseAddress(dyldBaseAddress),
+       fOffsetOfBindInfoInCombinedLinkedit(0), fOffsetOfWeakBindInfoInCombinedLinkedit(0),
+       fOffsetOfLazyBindInfoInCombinedLinkedit(0), fOffsetOfExportInfoInCombinedLinkedit(0),
+       fOffsetOfOldSymbolTableInfoInCombinedLinkedit(0), fSizeOfOldSymbolTableInfoInCombinedLinkedit(0),
+       fOffsetOfOldExternalRelocationsInCombinedLinkedit(0), fSizeOfOldExternalRelocationsInCombinedLinkedit(0),
+       fOffsetOfOldIndirectSymbolsInCombinedLinkedit(0), fSizeOfOldIndirectSymbolsInCombinedLinkedit(0),
+       fOffsetOfOldStringPoolInCombinedLinkedit(0), fSizeOfOldStringPoolInCombinedLinkedit(0),
+       fOffsetOfFunctionStartsInCombinedLinkedit(0), fSizeOfFunctionStartsInCombinedLinkedit(0)
 {
        if ( fArchGraph->getArchPair().arch != arch() )
                throwf("SharedCache object is wrong architecture: 0x%08X vs 0x%08X", fArchGraph->getArchPair().arch, arch());
                
        // build vector of all shared dylibs
 {
        if ( fArchGraph->getArchPair().arch != arch() )
                throwf("SharedCache object is wrong architecture: 0x%08X vs 0x%08X", fArchGraph->getArchPair().arch, arch());
                
        // build vector of all shared dylibs
+       unsigned int aliasCount = 0;
        std::set<const MachOLayoutAbstraction*>& dylibs = fArchGraph->getSharedDylibs();
        std::set<const MachOLayoutAbstraction*>& dylibs = fArchGraph->getSharedDylibs();
+       ArchGraph::StringToString& aliases = fArchGraph->getDylibAliases();
        for(std::set<const MachOLayoutAbstraction*>::iterator it = dylibs.begin(); it != dylibs.end(); ++it) {
                const MachOLayoutAbstraction* lib = *it;
                LayoutInfo temp;
        for(std::set<const MachOLayoutAbstraction*>::iterator it = dylibs.begin(); it != dylibs.end(); ++it) {
                const MachOLayoutAbstraction* lib = *it;
                LayoutInfo temp;
@@ -693,26 +846,44 @@ SharedCache<A>::SharedCache(ArchGraph* graph, const char* rootPath, bool alphaSo
                temp.info.address = 0;
                temp.info.modTime = lib->getLastModTime();
                temp.info.inode = lib->getInode();
                temp.info.address = 0;
                temp.info.modTime = lib->getLastModTime();
                temp.info.inode = lib->getInode();
-               temp.info.pathFileOffset = lib->getNameFileOffset();
+               temp.info.pathFileOffset = lib->getNameFileOffset();  // for now this is the offset within the dylib
+               for(ArchGraph::StringToString::iterator ait = aliases.begin(); ait != aliases.end(); ++ait) {
+                       if ( strcmp(ait->second, lib->getID().name) == 0 ) {
+                               temp.aliases.push_back(ait->first);
+                               ++aliasCount;
+                       }
+               }
                fDylibs.push_back(temp);
        }
 
                fDylibs.push_back(temp);
        }
 
-       // examine the existing shared cache file
+       // create path to cache file
+       char cachePathNonOverlay[1024];
+       strcpy(cachePathNonOverlay, cacheDir);
+       if ( cachePathNonOverlay[strlen(cachePathNonOverlay)-1] != '/' )
+               strcat(cachePathNonOverlay, "/");
+       strcat(cachePathNonOverlay, DYLD_SHARED_CACHE_BASE_NAME);
+       strcat(cachePathNonOverlay, cacheFileSuffix(optimize, fArchGraph->archName()));
        char cachePath[1024];
        strcpy(cachePath, rootPath);
        char cachePath[1024];
        strcpy(cachePath, rootPath);
-       strcat(cachePath, DYLD_SHARED_CACHE_DIR);
-       strcat(cachePath, DYLD_SHARED_CACHE_BASE_NAME);
-       strcat(cachePath, cacheFileSuffix(optimize, fArchGraph->archName()));
-       fCacheFilePath = strdup(cachePath);
-       const char* pathToExistingCacheFile = fCacheFilePath;
-       char cachePathNonOverlay[1024];
+       strcat(cachePath, "/");
+       strcat(cachePath, cachePathNonOverlay);
+       if ( !overlay && (rootPath[0] != '\0') )
+               fCacheFilePath = strdup(cachePathNonOverlay);
+       else
+               fCacheFilePath = strdup(cachePath);
        if ( overlay ) {
        if ( overlay ) {
-               strcpy(cachePathNonOverlay, DYLD_SHARED_CACHE_DIR);
-               strcat(cachePathNonOverlay, DYLD_SHARED_CACHE_BASE_NAME);
-               strcat(cachePathNonOverlay, cacheFileSuffix(optimize, fArchGraph->archName()));
-               pathToExistingCacheFile = cachePathNonOverlay;
+               // in overlay mode if there already is a cache file in the overlay
+               // check if it is up to date.  If there is no file, check if
+               // the one in the boot volume is up to date.
+               struct stat stat_buf;
+               if ( stat(fCacheFilePath, &stat_buf) == 0 ) 
+                       fExistingIsNotUpToDate = this->notUpToDate(fCacheFilePath, aliasCount);
+               else
+                       fExistingIsNotUpToDate = this->notUpToDate(cachePathNonOverlay, aliasCount);
+       }
+       else {
+               fExistingIsNotUpToDate = this->notUpToDate(fCacheFilePath, aliasCount);
        }
        }
-       fExistingIsNotUpToDate = this->notUpToDate(pathToExistingCacheFile);
        
        // sort shared dylibs
        if ( verify ) {
        
        // sort shared dylibs
        if ( verify ) {
@@ -730,7 +901,30 @@ SharedCache<A>::SharedCache(ArchGraph* graph, const char* rootPath, bool alphaSo
        }
        
        // assign segments in each dylib a new address
        }
        
        // assign segments in each dylib a new address
-       this->assignNewBaseAddresses();
+       this->assignNewBaseAddresses(verify);
+       
+       // calculate where string pool offset will start
+       // calculate cache file header size
+       fHeaderSize = sizeof(dyld_cache_header) 
+                                                       + fMappings.size()*sizeof(shared_file_mapping_np) 
+                                                       + (fDylibs.size()+aliasCount)*sizeof(dyld_cache_image_info);
+       //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) {
+               for(std::vector<const char*>::const_iterator ait = it->aliases.begin(); ait != it->aliases.end(); ++ait) {
+                       LayoutInfo temp = *it;
+                       // alias looks just like real dylib, but has a different name string
+                       const char* aliasPath = *ait;
+                       temp.aliases.clear();
+                       temp.aliases.push_back(aliasPath);
+                       temp.info.pathFileOffset = fHeaderSize; 
+                       fDylibAliases.push_back(temp);
+                       fHeaderSize += strlen(aliasPath)+1;
+               }
+       }
+       std::sort(fDylibAliases.begin(), fDylibAliases.end(), ByNameSorter());
+       //fprintf(stderr, "fHeaderSize=0x%08X, fDylibAliases.size()=%lu\n", fHeaderSize, fDylibAliases.size());
+       fHeaderSize = pageAlign(fHeaderSize);
        
        // check that cache we are about to create for verification purposes has same layout as existing cache
        if ( verify ) {
        
        // check that cache we are about to create for verification purposes has same layout as existing cache
        if ( verify ) {
@@ -749,13 +943,8 @@ SharedCache<A>::SharedCache(ArchGraph* graph, const char* rootPath, bool alphaSo
                }
        }
        
                }
        }
        
-       // calculate cache file header size
-       fHeaderSize = pageAlign(sizeof(dyld_cache_header) 
-                                                       + fMappings.size()*sizeof(shared_file_mapping_np) 
-                                                       + fDylibs.size()*sizeof(dyld_cache_image_info) );
-                                                       //+ fDependencyPool.size()*sizeof(uint16_t));
        
        
-       if ( fHeaderSize > 0x3000 )
+       if ( fHeaderSize > FIRST_DYLIB_TEXT_OFFSET )
                throwf("header size miscalculation 0x%08X", fHeaderSize);
 }
 
                throwf("header size miscalculation 0x%08X", fHeaderSize);
 }
 
@@ -775,11 +964,42 @@ uint64_t SharedCache<ppc>::getWritableSegmentNewAddress(uint64_t proposedNewAddr
 
 
 template <typename A>
 
 
 template <typename A>
-void SharedCache<A>::assignNewBaseAddresses()
+void SharedCache<A>::assignNewBaseAddresses(bool verify)
 {
 {
-       // first layout TEXT and DATA for split-seg (or can be split-seg) dylibs
-       uint64_t currentExecuteAddress = sharedRegionReadOnlyStartAddress() + 0x3000;   
-       uint64_t currentWritableAddress = sharedRegionWritableStartAddress();
+       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());
+                               }
+                       }
+                       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
        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(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;
@@ -859,13 +1079,19 @@ void SharedCache<A>::assignNewBaseAddresses()
        }
        fLinkEditsTotalUnoptimizedSize = (currentReadOnlyAddress - fLinkEditsStartAddress + 4095) & (-4096);
 
        }
        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));
+               
 
        // populate large mappings
        uint64_t cacheFileOffset = 0;
 
        // populate large mappings
        uint64_t cacheFileOffset = 0;
-       if ( currentExecuteAddress > sharedRegionReadOnlyStartAddress() + 0x3000 ) {
+       if ( currentExecuteAddress > sharedCacheStartAddress + FIRST_DYLIB_TEXT_OFFSET ) {
                shared_file_mapping_np  executeMapping;
                shared_file_mapping_np  executeMapping;
-               executeMapping.sfm_address              = sharedRegionReadOnlyStartAddress();
-               executeMapping.sfm_size                 = currentExecuteAddress - sharedRegionReadOnlyStartAddress();
+               executeMapping.sfm_address              = sharedCacheStartAddress;
+               executeMapping.sfm_size                 = currentExecuteAddress - sharedCacheStartAddress;
                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;
                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;
@@ -906,7 +1132,7 @@ void SharedCache<A>::assignNewBaseAddresses()
                // empty cache
                shared_file_mapping_np  cacheHeaderMapping;
                cacheHeaderMapping.sfm_address          = sharedRegionWritableStartAddress();
                // empty cache
                shared_file_mapping_np  cacheHeaderMapping;
                cacheHeaderMapping.sfm_address          = sharedRegionWritableStartAddress();
-               cacheHeaderMapping.sfm_size                     = 0x3000;
+               cacheHeaderMapping.sfm_size                     = FIRST_DYLIB_TEXT_OFFSET;
                cacheHeaderMapping.sfm_file_offset      = cacheFileOffset;
                cacheHeaderMapping.sfm_max_prot         = VM_PROT_READ;
                cacheHeaderMapping.sfm_init_prot        = VM_PROT_READ;
                cacheHeaderMapping.sfm_file_offset      = cacheFileOffset;
                cacheHeaderMapping.sfm_max_prot         = VM_PROT_READ;
                cacheHeaderMapping.sfm_init_prot        = VM_PROT_READ;
@@ -917,26 +1143,43 @@ void SharedCache<A>::assignNewBaseAddresses()
 
 
 template <typename A>
 
 
 template <typename A>
-uint64_t SharedCache<A>::cacheFileOffsetForAddress(uint64_t addr)
+uint64_t SharedCache<A>::cacheFileOffsetForVMAddress(uint64_t vmaddr) const
 {
 {
-       for(std::vector<shared_file_mapping_np>::iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
-               if ( (it->sfm_address <= addr) && (addr < it->sfm_address+it->sfm_size) )
-                       return it->sfm_file_offset + addr - it->sfm_address;
+       for(std::vector<shared_file_mapping_np>::const_iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
+               if ( (it->sfm_address <= vmaddr) && (vmaddr < it->sfm_address+it->sfm_size) )
+                       return it->sfm_file_offset + vmaddr - it->sfm_address;
        }
        }
-       throwf("address 0x%0llX is not in cache", addr);
+       throwf("address 0x%0llX is not in cache", vmaddr);
+}
+
+template <typename A>
+uint64_t SharedCache<A>::VMAddressForCacheFileOffset(uint64_t offset) const
+{
+    for(std::vector<shared_file_mapping_np>::const_iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
+        if ( (it->sfm_file_offset <= offset) && (offset < it->sfm_file_offset+it->sfm_size) )
+            return it->sfm_address + offset - it->sfm_file_offset;
+    }
+    throwf("offset 0x%0llX is not in cache", offset);
 }
 
 }
 
+template <typename A>
+void *SharedCache<A>::mappedAddressForVMAddress(uint64_t vmaddr)
+{
+    if (!vmaddr) return NULL;
+    else return fInMemoryCache + cacheFileOffsetForVMAddress(vmaddr);
+}
 
 template <typename A>
 
 template <typename A>
-uint64_t SharedCache<A>::mappedCacheAddressForAddress(uint64_t addr)
+uint64_t SharedCache<A>::VMAddressForMappedAddress(const void *mapaddr)
 {
 {
-    if (!addr) return 0;
-    else return (uint64_t)(fInMemoryCache + cacheFileOffsetForAddress(addr));
+    if (!mapaddr) return 0;
+    uint64_t offset = (uint8_t *)mapaddr - (uint8_t *)fInMemoryCache;
+    return VMAddressForCacheFileOffset(offset);
 }
 
 
 template <typename A>
 }
 
 
 template <typename A>
-bool SharedCache<A>::notUpToDate(const void* cache)
+bool SharedCache<A>::notUpToDate(const void* cache, unsigned int aliasCount)
 {
        dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)cache;
        // not valid if header signature is wrong
 {
        dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)cache;
        // not valid if header signature is wrong
@@ -950,21 +1193,25 @@ bool SharedCache<A>::notUpToDate(const void* cache)
                        return false;
                }
                else {
                        return false;
                }
                else {
-                       fprintf(stderr, "update_dyld_shared_cache[%u] current cache file has invalid header\n", getpid());
+                       fprintf(stderr, "update_dyld_shared_cache[%u] updating cache because current cache file has invalid header\n", getpid());
                        return true;
                }
        }
        // not valid if count of images does not match current images needed
                        return true;
                }
        }
        // not valid if count of images does not match current images needed
-       if ( header->imagesCount() != fDylibs.size() ) {
+       if ( header->imagesCount() != (fDylibs.size()+aliasCount) ) {
                if ( fVerify ) {
                        fprintf(stderr, "update_dyld_shared_cache[%u] cannot verify %s because current cache file contains a different set of dylibs\n", getpid(), archName());
                        return false;
                }
                else {
                if ( fVerify ) {
                        fprintf(stderr, "update_dyld_shared_cache[%u] cannot verify %s because current cache file contains a different set of dylibs\n", getpid(), archName());
                        return false;
                }
                else {
-                       fprintf(stderr, "update_dyld_shared_cache[%u] current cache file is invalid because it contains a different set of dylibs\n", getpid());
+                       fprintf(stderr, "update_dyld_shared_cache[%u] updating %s cache because current cache file contains a different set of dylibs\n", getpid(), archName());
                        return true;
                }
        }
                        return true;
                }
        }
+       // get end of TEXT region
+       const dyldCacheFileMapping<E>* textMapping = (dyldCacheFileMapping<E>*)((uint8_t*)cache+sizeof(dyldCacheHeader<E>));
+       const uint32_t textSize = textMapping->size();
+       
        // verify every dylib in constructed graph is in existing cache with same inode and modTime     
        std::map<const MachOLayoutAbstraction*, uint32_t> sortingMap;
        const dyldCacheImageInfo<E>* imagesStart = (dyldCacheImageInfo<E>*)((uint8_t*)cache + header->imagesOffset());
        // verify every dylib in constructed graph is in existing cache with same inode and modTime     
        std::map<const MachOLayoutAbstraction*, uint32_t> sortingMap;
        const dyldCacheImageInfo<E>* imagesStart = (dyldCacheImageInfo<E>*)((uint8_t*)cache + header->imagesOffset());
@@ -974,6 +1221,10 @@ bool SharedCache<A>::notUpToDate(const void* cache)
                //fprintf(stderr, "inode=0x%llX, mTime=0x%llX, path=%s\n", it->info.inode, it->info.modTime, it->layout->getID().name);
                for(const dyldCacheImageInfo<E>* cacheEntry = imagesStart; cacheEntry < imagesEnd; ++cacheEntry) {
                        if ( fVerify ) {
                //fprintf(stderr, "inode=0x%llX, mTime=0x%llX, path=%s\n", it->info.inode, it->info.modTime, it->layout->getID().name);
                for(const dyldCacheImageInfo<E>* cacheEntry = imagesStart; cacheEntry < imagesEnd; ++cacheEntry) {
                        if ( fVerify ) {
+                               if ( cacheEntry->pathFileOffset() > textSize ) {
+                                       throwf("update_dyld_shared_cache[%u]: for arch=%s, image entries corrupt, bad path offset in %s\n", 
+                                                               getpid(), archName(), it->layout->getID().name);
+                               }
                                // in -verify mode, just match by path and warn if file looks different
                                if ( strcmp((char*)cache+cacheEntry->pathFileOffset(), it->layout->getID().name) == 0 ) {
                                        found = true;
                                // in -verify mode, just match by path and warn if file looks different
                                if ( strcmp((char*)cache+cacheEntry->pathFileOffset(), it->layout->getID().name) == 0 ) {
                                        found = true;
@@ -986,6 +1237,10 @@ bool SharedCache<A>::notUpToDate(const void* cache)
                                }
                        }
                        else {
                                }
                        }
                        else {
+                               if ( cacheEntry->pathFileOffset() > textSize ) {
+                                       // cache corrupt, needs to be regenerated
+                                       return true;
+                               }
                                // in normal update mode, everything has to match for cache to be up-to-date
                                if ( (cacheEntry->inode() == it->info.inode) 
                                                && (cacheEntry->modTime() == it->info.modTime) 
                                // in normal update mode, everything has to match for cache to be up-to-date
                                if ( (cacheEntry->inode() == it->info.inode) 
                                                && (cacheEntry->modTime() == it->info.modTime) 
@@ -1000,7 +1255,7 @@ bool SharedCache<A>::notUpToDate(const void* cache)
                                throwf("update_dyld_shared_cache[%u] can't verify %s cache because %s is not in existing cache\n", getpid(), archName(), it->layout->getID().name);
                        }
                        else {
                                throwf("update_dyld_shared_cache[%u] can't verify %s cache because %s is not in existing cache\n", getpid(), archName(), it->layout->getID().name);
                        }
                        else {
-                               fprintf(stderr, "update_dyld_shared_cache[%u] current %s cache file invalid because %s has changed\n", getpid(), archName(), it->layout->getID().name);
+                               fprintf(stderr, "update_dyld_shared_cache[%u] updating %s cache because dylib at %s has changed\n", getpid(), archName(), it->layout->getID().name);
                                return true;
                        }
                }
                                return true;
                        }
                }
@@ -1024,7 +1279,7 @@ bool SharedCache<A>::notUpToDate(const void* cache)
 
 
 template <typename A>
 
 
 template <typename A>
-bool SharedCache<A>::notUpToDate(const char* path)
+bool SharedCache<A>::notUpToDate(const char* path, unsigned int aliasCount)
 {
        // mmap existing cache file 
        int fd = ::open(path, O_RDONLY);        
 {
        // mmap existing cache file 
        int fd = ::open(path, O_RDONLY);        
@@ -1032,20 +1287,27 @@ bool SharedCache<A>::notUpToDate(const char* path)
                return true;
        struct stat stat_buf;
        ::fstat(fd, &stat_buf);
                return true;
        struct stat stat_buf;
        ::fstat(fd, &stat_buf);
-       uint8_t* mappingAddr = (uint8_t*)mmap(NULL, stat_buf.st_size, PROT_READ , MAP_FILE | MAP_PRIVATE, fd, 0);
+    uint32_t cacheFileSize = stat_buf.st_size;
+    uint32_t cacheAllocatedSize = (cacheFileSize + 4095) & (-4096);
+    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);
+    // <rdar://problem/8960832> update_dyld_shared_cache -verify finds differences
+       (void)fcntl(fd, F_NOCACHE, 1);
+    ssize_t readResult = pread(fd, mappingAddr, cacheFileSize, 0);
+    if ( readResult != cacheFileSize )
+        throw "can't read existing cache file";
        ::close(fd);
        ::close(fd);
-       if ( mappingAddr == (uint8_t*)(-1) )
-               return true;
 
        // validate it
 
        // validate it
-       bool result = this->notUpToDate(mappingAddr);
+       bool result = this->notUpToDate(mappingAddr, aliasCount);
        if ( fVerify ) {
                // don't unmap yet, leave so it can be verified later
                fExistingCacheForVerification = mappingAddr;
        }
        else {
                // unmap
        if ( fVerify ) {
                // don't unmap yet, leave so it can be verified later
                fExistingCacheForVerification = mappingAddr;
        }
        else {
                // unmap
-               ::munmap(mappingAddr, stat_buf.st_size);
+        vm_deallocate(mach_task_self(), (vm_address_t)mappingAddr, cacheAllocatedSize);
                if ( verbose && !result )
                        fprintf(stderr, "update_dyld_shared_cache: %s is up-to-date\n", path);
        }
                if ( verbose && !result )
                        fprintf(stderr, "update_dyld_shared_cache: %s is up-to-date\n", path);
        }
@@ -1128,7 +1390,7 @@ template <typename A>
 class LinkEditOptimizer
 {
 public:
 class LinkEditOptimizer
 {
 public:
-                                                                                       LinkEditOptimizer(const MachOLayoutAbstraction&, uint8_t*, StringPool&);
+                                                                                       LinkEditOptimizer(const MachOLayoutAbstraction&, const SharedCache<A>&, uint8_t*, StringPool&);
        virtual                                                                 ~LinkEditOptimizer() {}
 
                void                                                            copyBindInfo(uint32_t&);
        virtual                                                                 ~LinkEditOptimizer() {}
 
                void                                                            copyBindInfo(uint32_t&);
@@ -1140,6 +1402,7 @@ public:
                void                                                            copyImportedSymbols(uint32_t symbolTableOffset, uint32_t&);
                void                                                            copyExternalRelocations(uint32_t& offset);
                void                                                            copyIndirectSymbolTable(uint32_t& offset);
                void                                                            copyImportedSymbols(uint32_t symbolTableOffset, uint32_t&);
                void                                                            copyExternalRelocations(uint32_t& offset);
                void                                                            copyIndirectSymbolTable(uint32_t& offset);
+               void                                                            copyFunctionStarts(uint32_t& offset);
                void                                                            updateLoadCommands(uint64_t newVMAddress, uint64_t size, uint32_t stringPoolOffset, 
                                                                                                                                uint32_t linkEditsFileOffset, bool keepSignatures);
        
                void                                                            updateLoadCommands(uint64_t newVMAddress, uint64_t size, uint32_t stringPoolOffset, 
                                                                                                                                uint32_t linkEditsFileOffset, bool keepSignatures);
        
@@ -1151,12 +1414,14 @@ protected:
                        
 private:
 
                        
 private:
 
+       const SharedCache<A>&                                           fSharedCache;
        const macho_header<P>*                                          fHeader; 
        uint8_t*                                                                        fNewLinkEditStart;      
        uint8_t*                                                                        fLinkEditBase;          
        const MachOLayoutAbstraction&                           fLayout;
        macho_dyld_info_command<P>*                                     fDyldInfo;
        macho_dysymtab_command<P>*                                      fDynamicSymbolTable;
        const macho_header<P>*                                          fHeader; 
        uint8_t*                                                                        fNewLinkEditStart;      
        uint8_t*                                                                        fLinkEditBase;          
        const MachOLayoutAbstraction&                           fLayout;
        macho_dyld_info_command<P>*                                     fDyldInfo;
        macho_dysymtab_command<P>*                                      fDynamicSymbolTable;
+       macho_linkedit_data_command<P>*                         fFunctionStarts;
        macho_symtab_command<P>*                                        fSymbolTableLoadCommand;
        const macho_nlist<P>*                                           fSymbolTable;
        const char*                                                                     fStrings;
        macho_symtab_command<P>*                                        fSymbolTableLoadCommand;
        const macho_nlist<P>*                                           fSymbolTable;
        const char*                                                                     fStrings;
@@ -1179,14 +1444,15 @@ private:
        uint32_t                                                                        fImportedSymbolsCountInNewLinkEdit;
        uint32_t                                                                        fExternalRelocationsOffsetIntoNewLinkEdit;
        uint32_t                                                                        fIndirectSymbolTableOffsetInfoNewLinkEdit;
        uint32_t                                                                        fImportedSymbolsCountInNewLinkEdit;
        uint32_t                                                                        fExternalRelocationsOffsetIntoNewLinkEdit;
        uint32_t                                                                        fIndirectSymbolTableOffsetInfoNewLinkEdit;
+       uint32_t                                                                        fFunctionStartsOffsetInNewLinkEdit;
 };
 
 
 
 template <typename A>
 };
 
 
 
 template <typename A>
-LinkEditOptimizer<A>::LinkEditOptimizer(const MachOLayoutAbstraction& layout, uint8_t* newLinkEdit, StringPool& stringPool)
- :     fLayout(layout), fLinkEditBase(NULL), fNewLinkEditStart(newLinkEdit), fDyldInfo(NULL),
-       fDynamicSymbolTable(NULL), fSymbolTableLoadCommand(NULL), fSymbolTable(NULL), fStrings(NULL), fNewStringPool(stringPool),
+LinkEditOptimizer<A>::LinkEditOptimizer(const MachOLayoutAbstraction& layout, const SharedCache<A>& sharedCache, uint8_t* newLinkEdit, StringPool& stringPool)
+ :     fSharedCache(sharedCache), fLayout(layout), fLinkEditBase(NULL), fNewLinkEditStart(newLinkEdit), fDyldInfo(NULL),
+       fDynamicSymbolTable(NULL), fFunctionStarts(NULL), fSymbolTableLoadCommand(NULL), fSymbolTable(NULL), fStrings(NULL), fNewStringPool(stringPool),
        fBindInfoOffsetIntoNewLinkEdit(0), fBindInfoSizeInNewLinkEdit(0),
        fWeakBindInfoOffsetIntoNewLinkEdit(0), fWeakBindInfoSizeInNewLinkEdit(0),
        fLazyBindInfoOffsetIntoNewLinkEdit(0), fLazyBindInfoSizeInNewLinkEdit(0),
        fBindInfoOffsetIntoNewLinkEdit(0), fBindInfoSizeInNewLinkEdit(0),
        fWeakBindInfoOffsetIntoNewLinkEdit(0), fWeakBindInfoSizeInNewLinkEdit(0),
        fLazyBindInfoOffsetIntoNewLinkEdit(0), fLazyBindInfoSizeInNewLinkEdit(0),
@@ -1195,7 +1461,8 @@ LinkEditOptimizer<A>::LinkEditOptimizer(const MachOLayoutAbstraction& layout, ui
        fLocalSymbolsStartIndexInNewLinkEdit(0), fLocalSymbolsCountInNewLinkEdit(0),
        fExportedSymbolsStartIndexInNewLinkEdit(0), fExportedSymbolsCountInNewLinkEdit(0),
        fImportSymbolsStartIndexInNewLinkEdit(0), fImportedSymbolsCountInNewLinkEdit(0),
        fLocalSymbolsStartIndexInNewLinkEdit(0), fLocalSymbolsCountInNewLinkEdit(0),
        fExportedSymbolsStartIndexInNewLinkEdit(0), fExportedSymbolsCountInNewLinkEdit(0),
        fImportSymbolsStartIndexInNewLinkEdit(0), fImportedSymbolsCountInNewLinkEdit(0),
-       fExternalRelocationsOffsetIntoNewLinkEdit(0), fIndirectSymbolTableOffsetInfoNewLinkEdit(0)
+       fExternalRelocationsOffsetIntoNewLinkEdit(0), fIndirectSymbolTableOffsetInfoNewLinkEdit(0),
+       fFunctionStartsOffsetInNewLinkEdit(0)
        
 {
        fHeader = (const macho_header<P>*)fLayout.getSegments()[0].mappedAddress();
        
 {
        fHeader = (const macho_header<P>*)fLayout.getSegments()[0].mappedAddress();
@@ -1228,6 +1495,9 @@ LinkEditOptimizer<A>::LinkEditOptimizer(const MachOLayoutAbstraction& layout, ui
                        case LC_DYLD_INFO_ONLY:
                                fDyldInfo = (macho_dyld_info_command<P>*)cmd;
                                break;
                        case LC_DYLD_INFO_ONLY:
                                fDyldInfo = (macho_dyld_info_command<P>*)cmd;
                                break;
+                       case LC_FUNCTION_STARTS:
+                               fFunctionStarts = (macho_linkedit_data_command<P>*)cmd;
+                               break;
                }
                cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
        }       
                }
                cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
        }       
@@ -1290,11 +1560,10 @@ void LinkEditOptimizer<A>::copyLazyBindInfo(uint32_t& offset)
 template <typename A>
 void LinkEditOptimizer<A>::copyExportInfo(uint32_t& offset)
 {
 template <typename A>
 void LinkEditOptimizer<A>::copyExportInfo(uint32_t& offset)
 {
-       if ( (fDyldInfo != NULL) && (fDyldInfo->export_off() != 0) ) {
+       if ( (fDyldInfo != NULL) && (fLayout.getDyldInfoExports() != NULL) ) {
                fExportInfoOffsetIntoNewLinkEdit = offset;
                fExportInfoSizeInNewLinkEdit = fDyldInfo->export_size();
                fExportInfoOffsetIntoNewLinkEdit = offset;
                fExportInfoSizeInNewLinkEdit = fDyldInfo->export_size();
-               // warning, export_off is only 32-bits so if the trie grows it must be allocated with 32-bits of fLinkeditBase
-               memcpy(fNewLinkEditStart+offset, fLinkEditBase+(int32_t)fDyldInfo->export_off(), fDyldInfo->export_size());
+               memcpy(fNewLinkEditStart+offset, fLayout.getDyldInfoExports(), fDyldInfo->export_size());
                offset += fDyldInfo->export_size();
        }
 }
                offset += fDyldInfo->export_size();
        }
 }
@@ -1314,7 +1583,7 @@ void LinkEditOptimizer<A>::copyLocalSymbols(uint32_t symbolTableOffset, uint32_t
                if ( (entry->n_type() & N_TYPE) == N_SECT ) {
                        macho_nlist<P>* newSymbolEntry = &newSymbolTableStart[symbolIndex];
                        *newSymbolEntry = *entry;
                if ( (entry->n_type() & N_TYPE) == N_SECT ) {
                        macho_nlist<P>* newSymbolEntry = &newSymbolTableStart[symbolIndex];
                        *newSymbolEntry = *entry;
-                       newSymbolEntry->set_n_strx(fNewStringPool.add(&fStrings[entry->n_strx()]));
+                       newSymbolEntry->set_n_strx(fNewStringPool.addUnique(&fStrings[entry->n_strx()]));
                        ++symbolIndex;
                }
        }
                        ++symbolIndex;
                }
        }
@@ -1336,7 +1605,7 @@ void LinkEditOptimizer<A>::copyExportedSymbols(uint32_t symbolTableOffset, uint3
                                                && (strncmp(&fStrings[entry->n_strx()], "$ld$", 4) != 0) ) {
                        macho_nlist<P>* newSymbolEntry = &newSymbolTableStart[symbolIndex];
                        *newSymbolEntry = *entry;
                                                && (strncmp(&fStrings[entry->n_strx()], "$ld$", 4) != 0) ) {
                        macho_nlist<P>* newSymbolEntry = &newSymbolTableStart[symbolIndex];
                        *newSymbolEntry = *entry;
-                       newSymbolEntry->set_n_strx(fNewStringPool.add(&fStrings[entry->n_strx()]));
+                       newSymbolEntry->set_n_strx(fNewStringPool.addUnique(&fStrings[entry->n_strx()]));
                        fOldToNewSymbolIndexes[oldIndex] = symbolIndex-fLocalSymbolsStartIndexInNewLinkEdit;
                        ++symbolIndex;
                }
                        fOldToNewSymbolIndexes[oldIndex] = symbolIndex-fLocalSymbolsStartIndexInNewLinkEdit;
                        ++symbolIndex;
                }
@@ -1395,6 +1664,16 @@ void LinkEditOptimizer<A>::copyExternalRelocations(uint32_t& offset)
        }
 }
 
        }
 }
 
+template <typename A>
+void LinkEditOptimizer<A>::copyFunctionStarts(uint32_t& offset)
+{      
+       if ( fFunctionStarts != NULL ) {
+               fFunctionStartsOffsetInNewLinkEdit = offset;
+               memcpy(&fNewLinkEditStart[offset], &fLinkEditBase[fFunctionStarts->dataoff()], fFunctionStarts->datasize());
+               offset += fFunctionStarts->datasize();
+       }
+}
+
 template <typename A>
 void LinkEditOptimizer<A>::copyIndirectSymbolTable(uint32_t& offset)
 {      
 template <typename A>
 void LinkEditOptimizer<A>::copyIndirectSymbolTable(uint32_t& offset)
 {      
@@ -1431,6 +1710,20 @@ void LinkEditOptimizer<A>::updateLoadCommands(uint64_t newVMAddress, uint64_t si
                                seg->set_filesize(size);
                                seg->set_fileoff(linkEditsFileOffset);
                        }
                                seg->set_filesize(size);
                                seg->set_fileoff(linkEditsFileOffset);
                        }
+                       // don't alter __TEXT until <rdar://problem/7022345> is fixed
+                       else if ( strcmp(seg->segname(), "__TEXT") != 0 ) {
+                               // update all other segments fileoff to be offset from start of cache file
+                               pint_t oldFileOff = seg->fileoff();
+                               seg->set_fileoff(fSharedCache.cacheFileOffsetForVMAddress(seg->vmaddr()));
+                               pint_t fileOffsetDelta = seg->fileoff() - oldFileOff;
+                               // update all sections in this segment
+                               macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)seg + sizeof(macho_segment_command<P>));
+                               macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
+                               for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+                                       if ( sect->offset() != 0 )
+                                               sect->set_offset(sect->offset()+fileOffsetDelta);
+                               }
+                       }
                }
                cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
        }       
                }
                cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
        }       
@@ -1475,6 +1768,11 @@ void LinkEditOptimizer<A>::updateLoadCommands(uint64_t newVMAddress, uint64_t si
        fDynamicSymbolTable->set_locreloff(0);
        fDynamicSymbolTable->set_nlocrel(0);
 
        fDynamicSymbolTable->set_locreloff(0);
        fDynamicSymbolTable->set_nlocrel(0);
 
+       // update function starts
+       if ( fFunctionStarts != NULL ) {
+               fFunctionStarts->set_dataoff(linkEditsFileOffset+fFunctionStartsOffsetInNewLinkEdit);
+       }
+       
        // now remove load commands no longer needed
        const macho_load_command<P>* srcCmd = cmds;
        macho_load_command<P>* dstCmd = (macho_load_command<P>*)cmds;
        // now remove load commands no longer needed
        const macho_load_command<P>* srcCmd = cmds;
        macho_load_command<P>* dstCmd = (macho_load_command<P>*)cmds;
@@ -1528,7 +1826,7 @@ uint8_t* SharedCache<A>::optimizeLINKEDIT(bool keepSignatures)
        // create optimizer object for each LINKEDIT segment
        std::vector<LinkEditOptimizer<A>*> optimizers;
        for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
        // create optimizer object for each LINKEDIT segment
        std::vector<LinkEditOptimizer<A>*> optimizers;
        for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
-               optimizers.push_back(new LinkEditOptimizer<A>(*it->layout, newLinkEdit, stringPool));
+               optimizers.push_back(new LinkEditOptimizer<A>(*it->layout, *this, newLinkEdit, stringPool));
        }
 
        // rebase info is not copied because images in shared cache are never rebased
        }
 
        // rebase info is not copied because images in shared cache are never rebased
@@ -1567,33 +1865,45 @@ uint8_t* SharedCache<A>::optimizeLINKEDIT(bool keepSignatures)
                (*it)->copyExportedSymbols(symbolTableOffset, symbolTableIndex);
                (*it)->copyImportedSymbols(symbolTableOffset, symbolTableIndex);
        }
                (*it)->copyExportedSymbols(symbolTableOffset, symbolTableIndex);
                (*it)->copyImportedSymbols(symbolTableOffset, symbolTableIndex);
        }
+       fSizeOfOldSymbolTableInfoInCombinedLinkedit =  symbolTableIndex * sizeof(macho_nlist<typename A::P>);
+       offset = symbolTableOffset + fSizeOfOldSymbolTableInfoInCombinedLinkedit & (-8);
        
        // copy external relocations, 8-byte aligned after end of symbol table
        
        // copy external relocations, 8-byte aligned after end of symbol table
-       uint32_t externalRelocsOffset = symbolTableOffset + (symbolTableIndex * sizeof(macho_nlist<typename A::P>) + 7) & (-8);
-       //uint32_t externalRelocsStartOffset = externalRelocsOffset;
+       fOffsetOfOldExternalRelocationsInCombinedLinkedit = offset;
        for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
        for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
-               (*it)->copyExternalRelocations(externalRelocsOffset);
+               (*it)->copyExternalRelocations(offset);
        }
        }
+       fSizeOfOldExternalRelocationsInCombinedLinkedit = offset - fOffsetOfOldExternalRelocationsInCombinedLinkedit;
        
        
+       // copy function starts
+       fOffsetOfFunctionStartsInCombinedLinkedit = offset;
+       for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
+               (*it)->copyFunctionStarts(offset);
+       }
+       fSizeOfFunctionStartsInCombinedLinkedit = offset - fOffsetOfFunctionStartsInCombinedLinkedit;
+
        // copy indirect symbol tables
        // copy indirect symbol tables
-       uint32_t indirectSymbolTableOffset = externalRelocsOffset;
+       fOffsetOfOldIndirectSymbolsInCombinedLinkedit = offset;
        for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
        for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
-               (*it)->copyIndirectSymbolTable(indirectSymbolTableOffset);
+               (*it)->copyIndirectSymbolTable(offset);
        }
        }
-       
+       fSizeOfOldIndirectSymbolsInCombinedLinkedit = offset - fOffsetOfOldIndirectSymbolsInCombinedLinkedit;
+               
        // copy string pool
        // copy string pool
-       uint32_t stringPoolOffset = indirectSymbolTableOffset;
-       memcpy(&newLinkEdit[stringPoolOffset], stringPool.getBuffer(), stringPool.size());
+       fOffsetOfOldStringPoolInCombinedLinkedit = offset;
+       memcpy(&newLinkEdit[offset], stringPool.getBuffer(), stringPool.size());
+       fSizeOfOldStringPoolInCombinedLinkedit = stringPool.size();
        
        
-       // find new size
-       fLinkEditsTotalOptimizedSize = (stringPoolOffset + stringPool.size() + 4095) & (-4096);
-       
-       // choose new linkedit file  offset 
-       uint32_t linkEditsFileOffset = fLinkEditsStartAddress - sharedRegionReadOnlyStartAddress();
+       // total new size round up to page size
+       fLinkEditsTotalOptimizedSize = (fOffsetOfOldStringPoolInCombinedLinkedit + fSizeOfOldStringPoolInCombinedLinkedit + 4095) & (-4096);
        
        
+       // choose new linkedit file offset 
+       uint32_t linkEditsFileOffset = cacheFileOffsetForVMAddress(fLinkEditsStartAddress);
+//     uint32_t linkEditsFileOffset = fLinkEditsStartAddress - sharedRegionReadOnlyStartAddress();     
+
        // 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) {
        // update load commands so that all dylibs shared different areas of the same LINKEDIT segment
        for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
-               (*it)->updateLoadCommands(fLinkEditsStartAddress, fLinkEditsTotalUnoptimizedSize, stringPoolOffset, linkEditsFileOffset, keepSignatures);
+               (*it)->updateLoadCommands(fLinkEditsStartAddress, fLinkEditsTotalUnoptimizedSize, fOffsetOfOldStringPoolInCombinedLinkedit, linkEditsFileOffset, keepSignatures);
        }
 
        //fprintf(stderr, "fLinkEditsTotalUnoptimizedSize=%llu, fLinkEditsTotalOptimizedSize=%u\n", fLinkEditsTotalUnoptimizedSize, fLinkEditsTotalOptimizedSize);
        }
 
        //fprintf(stderr, "fLinkEditsTotalUnoptimizedSize=%llu, fLinkEditsTotalOptimizedSize=%u\n", fLinkEditsTotalUnoptimizedSize, fLinkEditsTotalOptimizedSize);
@@ -1627,7 +1937,7 @@ template <typename A>
 class ObjCSelectorUniquer
 {
 private:
 class ObjCSelectorUniquer
 {
 private:
-    objc_selopt::string_map fSelectorStrings;
+    objc_opt::string_map fSelectorStrings;
     SharedCache<A> *fCache;
     size_t fCount;
 
     SharedCache<A> *fCache;
     size_t fCount;
 
@@ -1643,97 +1953,164 @@ public:
     {
         fCount++;
         const char *s = (const char *)
     {
         fCount++;
         const char *s = (const char *)
-            fCache->mappedCacheAddressForAddress(oldValue);
-        objc_selopt::string_map::iterator element = 
-            fSelectorStrings.insert(objc_selopt::string_map::value_type(s, oldValue)).first;
+            fCache->mappedAddressForVMAddress(oldValue);
+        objc_opt::string_map::iterator element = 
+            fSelectorStrings.insert(objc_opt::string_map::value_type(s, oldValue)).first;
         return (typename A::P::uint_t)element->second;
     }
 
         return (typename A::P::uint_t)element->second;
     }
 
-    objc_selopt::string_map& strings() { 
+    objc_opt::string_map& strings() { 
         return fSelectorStrings;
     }
 
     size_t count() const { return fCount; }
 };
 
         return fSelectorStrings;
     }
 
     size_t count() const { return fCount; }
 };
 
-template <>
-void SharedCache<arm>::optimizeObjC()
-{
-       // objc optimizations on arm not yet supported
-}
-
 template <typename A>
 template <typename A>
-void SharedCache<A>::optimizeObjC()
+void SharedCache<A>::optimizeObjC(std::vector<void*>& pointersInData)
 {
 {
+    const char *err;
+    size_t headerSize = sizeof(objc_opt::objc_opt_t);
+
     if ( verbose ) {
     if ( verbose ) {
-        fprintf(stderr, "update_dyld_shared_cache: for %s, uniquing objc selectors\n", archName());
+        fprintf(stderr, "update_dyld_shared_cache: for %s, optimizing objc metadata\n", archName());
     }
 
     }
 
-    // Find libobjc's __TEXT,__objc_selopt section
-    const macho_section<P> *seloptSection = NULL;
+    // Find libobjc's empty sections to fill in
+    const macho_section<P> *optROSection = NULL;
+    const macho_section<P> *optRWSection = NULL;
        for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
        for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
-        if (0 == strstr(it->layout->getFilePath(), "libobjc")) continue;
-        const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
-        if ((seloptSection = mh->getSection("__TEXT", "__objc_selopt"))) break;
+        if ( strstr(it->layout->getFilePath(), "libobjc") != NULL ) {
+                       const macho_header<P>* mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
+                       optROSection = mh->getSection("__TEXT", "__objc_opt_ro");
+                       // __objc_selopt is old name for __objc_opt_ro
+                       if ( optROSection == NULL )
+                               optROSection = mh->getSection("__TEXT", "__objc_selopt");
+                       optRWSection = mh->getSection("__DATA", "__objc_opt_rw");
+                       break;
+               }
        }
     
        }
     
-    if (!seloptSection) {
-        warn(archName(), "couldn't find libobjc's unique selector section (selectors not optimized)");
-        return;
-    }
-
-    objc_selopt::objc_selopt_t *seloptData = (objc_selopt::objc_selopt_t *)
-        mappedCacheAddressForAddress(seloptSection->addr());
-    if (seloptSection->size() < sizeof(seloptData->version)) {
-        warn(archName(), "libobjc's unique selector section is too small (selectors not optimized)");
-        return;
-    }
-
-    if (E::get32(seloptData->version) != objc_selopt::VERSION) {
-        warn(archName(), "libobjc's unique selector section version is unrecognized (selectors not optimized)");
-        return;
-    }
+       if ( optROSection == NULL ) {
+               warn(archName(), "libobjc's read-only section missing (metadata not optimized)");
+               return;
+       }
+       
+       objc_opt::objc_opt_t* optROHeader = (objc_opt::objc_opt_t*)mappedAddressForVMAddress(optROSection->addr());
+       if (optROSection->size() < headerSize) {
+               warn(archName(), "libobjc's read-only section is too small (metadata not optimized)");
+               return;
+       }
 
 
+       if (E::get32(optROHeader->version) != objc_opt::VERSION) {
+               warn(archName(), "libobjc's read-only section version is unrecognized (metadata not optimized)");
+               return;
+       }
 
     // Update selector references and build selector list
 
     // Update selector references and build selector list
-    ObjCSelectorUniquer<A> uniq(this);
+
+    // This is SAFE: if we run out of room for the selector table, 
+    // the modified binaries are still usable.
 
     // Heuristic: choose selectors from libraries with more cstring data first.
     // This tries to localize selector cstring memory.
 
     // Heuristic: choose selectors from libraries with more cstring data first.
     // This tries to localize selector cstring memory.
+    ObjCSelectorUniquer<A> uniq(this);
     std::vector<LayoutInfo> sortedDylibs = fDylibs;
     std::sort(sortedDylibs.begin(), sortedDylibs.end(), ByCStringSectionSizeSorter());
 
     std::vector<LayoutInfo> sortedDylibs = fDylibs;
     std::sort(sortedDylibs.begin(), sortedDylibs.end(), ByCStringSectionSizeSorter());
 
+    SelectorOptimizer<A, ObjCSelectorUniquer<A> > selOptimizer(uniq);
        for(typename std::vector<LayoutInfo>::const_iterator it = sortedDylibs.begin(); it != sortedDylibs.end(); ++it) {
         const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
         LegacySelectorUpdater<A, ObjCSelectorUniquer<A> >::update(this, mh, uniq);
        for(typename std::vector<LayoutInfo>::const_iterator it = sortedDylibs.begin(); it != sortedDylibs.end(); ++it) {
         const macho_header<P> *mh = (const macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
         LegacySelectorUpdater<A, ObjCSelectorUniquer<A> >::update(this, mh, uniq);
-        SelectorUpdater<A, ObjCSelectorUniquer<A> >::update(this, mh, uniq);
+        selOptimizer.optimize(this, mh);
        }
 
     if ( verbose ) {
         fprintf(stderr, "update_dyld_shared_cache: for %s, found %zu unique objc selectors\n", archName(), uniq.strings().size());
     }
 
        }
 
     if ( verbose ) {
         fprintf(stderr, "update_dyld_shared_cache: for %s, found %zu unique objc selectors\n", archName(), uniq.strings().size());
     }
 
-    // Write selector hash table to libobjc's __TEXT,__objc_selopt section
-    size_t bytesUsed;
-    const char *err = 
-        objc_selopt::write_selopt(seloptData, seloptSection->addr(), 
-                                  seloptSection->size(), uniq.strings(), 
-                                  E::little_endian, &bytesUsed);
+    // Write selector table in read-only data.
+    size_t selTableOffset = P::round_up(headerSize);
+    size_t selTableSize;
+    objc_opt::objc_selopt_t *seloptData = (objc_opt::objc_selopt_t *)
+        mappedAddressForVMAddress(optROSection->addr() + selTableOffset);
+    err = objc_opt::write_selopt(seloptData, 
+                                 optROSection->addr() + selTableOffset, 
+                                 optROSection->size() - selTableOffset, 
+                                 uniq.strings(), 
+                                 E::little_endian, &selTableSize);
     if (err) {
         warn(archName(), err);
         return;
     }
 
     if ( verbose ) {
     if (err) {
         warn(archName(), err);
         return;
     }
 
     if ( verbose ) {
+        size_t totalSize = headerSize + selTableSize;
         fprintf(stderr, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
         fprintf(stderr, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
-                "(%d%%) used in libobjc unique selector section\n", 
-                archName(), bytesUsed, seloptSection->size(), 
-                (int)(bytesUsed / (double)seloptSection->size() * 100));
+                "(%d%%) used in libobjc read-only optimization section\n", 
+                archName(), totalSize, optROSection->size(), 
+                (int)(totalSize / (double)optROSection->size() * 100));
         fprintf(stderr, "update_dyld_shared_cache: for %s, "
                 "updated %zu selector references\n", 
                 archName(), uniq.count());
         fprintf(stderr, "update_dyld_shared_cache: for %s, "
                 "updated %zu selector references\n", 
                 archName(), uniq.count());
+        fprintf(stderr, "update_dyld_shared_cache: for %s, "
+                "wrote objc metadata optimization version %d\n", 
+                archName(), objc_opt::VERSION);
     }
 
     }
 
+       // if r/w section exists in libojc attempt to optimize categories into classes
+       if ( optRWSection != NULL ) {
+               // Attach categories to classes in the same framework. 
+               // Build aggregated (but unsorted) method lists in read-write data.
+
+               // This is SAFE: if we run out of room while attaching categories in 
+               // a binary then previously-edited binaries are still valid. (This assumes 
+               // each binary is processed all-or-nothing, which CategoryAttacher does.)
+               // This must be done AFTER uniquing selectors.
+               // This must be done BEFORE sorting method lists.
+               
+               size_t categoryOffset = 0;
+               uint8_t *categoryData = (uint8_t*)mappedAddressForVMAddress(optRWSection->addr() + categoryOffset);
+               CategoryAttacher<A> categoryAttacher(categoryData, optRWSection->size() - categoryOffset);
+               for(typename std::vector<LayoutInfo>::const_iterator it = sortedDylibs.begin(); it != sortedDylibs.end(); ++it) {
+                       macho_header<P> *mh = (macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
+                       err = categoryAttacher.optimize(this, mh, pointersInData);
+                       if (err) {
+                               warn(archName(), err);
+                               return;
+                       }
+               }    
+               size_t categorySize = categoryAttacher.bytesUsed();
+
+
+               // Sort method lists.
+               
+               // This is SAFE: modified binaries are still usable as unsorted lists.
+               // This must be done AFTER uniquing selectors.
+               // This must be done AFTER attaching categories.
+
+               MethodListSorter<A> methodSorter;
+               for(typename std::vector<LayoutInfo>::const_iterator it = sortedDylibs.begin(); it != sortedDylibs.end(); ++it) {
+                       macho_header<P> *mh = (macho_header<P>*)(*it->layout).getSegments()[0].mappedAddress();
+                       methodSorter.optimize(this, mh);
+               }
+
+               if ( verbose ) {
+                       size_t totalRWSize = categorySize;
+                       fprintf(stderr, "update_dyld_shared_cache: for %s, %zu/%llu bytes "
+                "(%d%%) used in libobjc read-write optimization section\n", 
+                archName(), totalRWSize, optRWSection->size(), 
+                (int)(totalRWSize / (double)optRWSection->size() * 100));
+                       fprintf(stderr, "update_dyld_shared_cache: for %s, "
+                "attached %zu categories (%zd bytes used)\n", 
+                archName(), categoryAttacher.count(), 
+                categoryAttacher.bytesUsed());
+               }
+       }
+
+    // Success. Update RO header last
+    E::set32(optROHeader->selopt_offset, headerSize);
+
     return;
 }
 
     return;
 }
 
@@ -1751,6 +2128,14 @@ static void cleanup(int sig)
 }
 
 
 }
 
 
+
+template <>     bool   SharedCache<x86_64>::addCacheSlideInfo(){ return true; }
+template <>     bool   SharedCache<arm>::addCacheSlideInfo()   { return true; }
+template <>     bool   SharedCache<x86>::addCacheSlideInfo()   { return false; }
+template <>     bool   SharedCache<ppc>::addCacheSlideInfo()   { return false; }
+
+
+
 template <typename A>
 bool SharedCache<A>::update(bool usesOverlay, bool force, bool optimize, bool deleteExistingFirst, int archIndex,
                                                                int archCount, bool keepSignatures)
 template <typename A>
 bool SharedCache<A>::update(bool usesOverlay, bool force, bool optimize, bool deleteExistingFirst, int archIndex,
                                                                int archCount, bool keepSignatures)
@@ -1778,7 +2163,7 @@ bool SharedCache<A>::update(bool usesOverlay, bool force, bool optimize, bool de
                        uint32_t cacheFileSize = 0;
                        for(std::vector<shared_file_mapping_np>::iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
                                uint32_t end = it->sfm_file_offset + it->sfm_size;
                        uint32_t cacheFileSize = 0;
                        for(std::vector<shared_file_mapping_np>::iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
                                uint32_t end = it->sfm_file_offset + it->sfm_size;
-                               if ( end > cacheFileSize )
+                               if ( end > cacheFileSize ) 
                                        cacheFileSize = end;
                        }
                        if ( vm_allocate(mach_task_self(), (vm_address_t*)(&inMemoryCache), cacheFileSize, VM_FLAGS_ANYWHERE) != KERN_SUCCESS )
                                        cacheFileSize = end;
                        }
                        if ( vm_allocate(mach_task_self(), (vm_address_t*)(&inMemoryCache), cacheFileSize, VM_FLAGS_ANYWHERE) != KERN_SUCCESS )
@@ -1797,10 +2182,12 @@ bool SharedCache<A>::update(bool usesOverlay, bool force, bool optimize, bool de
                        header->set_mappingOffset(sizeof(dyldCacheHeader<E>)); 
                        header->set_mappingCount(fMappings.size());
                        header->set_imagesOffset(header->mappingOffset() + fMappings.size()*sizeof(dyldCacheFileMapping<E>));   
                        header->set_mappingOffset(sizeof(dyldCacheHeader<E>)); 
                        header->set_mappingCount(fMappings.size());
                        header->set_imagesOffset(header->mappingOffset() + fMappings.size()*sizeof(dyldCacheFileMapping<E>));   
-                       header->set_imagesCount(fDylibs.size());
+                       header->set_imagesCount(fDylibs.size()+fDylibAliases.size());
                        header->set_dyldBaseAddress(fDyldBaseAddress);
                        header->set_dyldBaseAddress(fDyldBaseAddress);
-                       //header->set_dependenciesOffset(sizeof(dyldCacheHeader<E>) + fMappings.size()*sizeof(dyldCacheFileMapping<E>) + fDylibs.size()*sizeof(dyldCacheImageInfo<E>)); 
-                       //header->set_dependenciesCount(fDependencyPool.size());
+                       header->set_codeSignatureOffset(cacheFileSize);
+                       header->set_codeSignatureSize(0);
+                       header->set_slideInfoOffset(0);
+                       header->set_slideInfoSize(0);
                        
                        // fill in mappings
                        dyldCacheFileMapping<E>* mapping = (dyldCacheFileMapping<E>*)&inMemoryCache[sizeof(dyldCacheHeader<E>)];
                        
                        // fill in mappings
                        dyldCacheFileMapping<E>* mapping = (dyldCacheFileMapping<E>*)&inMemoryCache[sizeof(dyldCacheHeader<E>)];
@@ -1822,8 +2209,18 @@ bool SharedCache<A>::update(bool usesOverlay, bool force, bool optimize, bool de
                                image->set_address(it->info.address);
                                image->set_modTime(it->info.modTime);
                                image->set_inode(it->info.inode);
                                image->set_address(it->info.address);
                                image->set_modTime(it->info.modTime);
                                image->set_inode(it->info.inode);
-                               image->set_pathFileOffset(cacheFileOffsetForAddress(it->info.address+it->info.pathFileOffset));
-                               //image->set_dependenciesStartOffset(it->info.dependenciesStartOffset);
+                               image->set_pathFileOffset(cacheFileOffsetForVMAddress(it->info.address+it->info.pathFileOffset));
+                               ++image;
+                       }
+                       
+                       // add aliases to end of image table
+                       for(typename std::vector<LayoutInfo>::iterator it = fDylibAliases.begin(); it != fDylibAliases.end(); ++it) {
+                               image->set_address(it->info.address);
+                               image->set_modTime(it->info.modTime);
+                               image->set_inode(it->info.inode);
+                               image->set_pathFileOffset(it->info.pathFileOffset);
+                               strcpy((char*)inMemoryCache+it->info.pathFileOffset, it->aliases[0]);
+                               //fprintf(stderr, "adding alias to offset 0x%08X %s\n", it->info.pathFileOffset, it->aliases[0]);
                                ++image;
                        }
                                                
                                ++image;
                        }
                                                
@@ -1856,7 +2253,7 @@ bool SharedCache<A>::update(bool usesOverlay, bool force, bool optimize, bool de
                                                if ( seg.size() > 0 ) {
                                                        const uint64_t segmentSrcStartOffset = it->layout->getOffsetInUniversalFile()+seg.fileOffset();
                                                        const uint64_t segmentSize = seg.fileSize();
                                                if ( seg.size() > 0 ) {
                                                        const uint64_t segmentSrcStartOffset = it->layout->getOffsetInUniversalFile()+seg.fileOffset();
                                                        const uint64_t segmentSize = seg.fileSize();
-                                                       const uint64_t segmentDstStartOffset = cacheFileOffsetForAddress(seg.newAddress());
+                                                       const uint64_t segmentDstStartOffset = cacheFileOffsetForVMAddress(seg.newAddress());
                                                        ssize_t readResult = ::pread(src, &inMemoryCache[segmentDstStartOffset], segmentSize, segmentSrcStartOffset);
                                                        if ( readResult != segmentSize ) {
                                                                if ( readResult == -1 )
                                                        ssize_t readResult = ::pread(src, &inMemoryCache[segmentDstStartOffset], segmentSize, segmentSrcStartOffset);
                                                        if ( readResult != segmentSize ) {
                                                                if ( readResult == -1 )
@@ -1887,16 +2284,24 @@ bool SharedCache<A>::update(bool usesOverlay, bool force, bool optimize, bool de
                                for (int i=0; i < segs.size(); ++i) {
                                        MachOLayoutAbstraction::Segment& seg = segs[i];
                                        if ( seg.size() > 0 )
                                for (int i=0; i < segs.size(); ++i) {
                                        MachOLayoutAbstraction::Segment& seg = segs[i];
                                        if ( seg.size() > 0 )
-                                               seg.setMappedAddress(inMemoryCache + cacheFileOffsetForAddress(seg.newAddress()));
+                                               seg.setMappedAddress(inMemoryCache + cacheFileOffsetForVMAddress(seg.newAddress()));
                                        //fprintf(stderr, "%s at %p to %p for %s\n", seg.name(), seg.mappedAddress(), (char*)seg.mappedAddress()+ seg.size(), it->layout->getID().name);
                                }
                        }
                                        //fprintf(stderr, "%s at %p to %p for %s\n", seg.name(), seg.mappedAddress(), (char*)seg.mappedAddress()+ seg.size(), it->layout->getID().name);
                                }
                        }
+       
+                       // also construct list of all pointers in cache to other things in cache
+                       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 {
                                        Rebaser<A> r(*it->layout);
 
                        // rebase each dylib in shared cache
                        for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
                                try {
                                        Rebaser<A> r(*it->layout);
-                                       r.rebase();
+                                       r.rebase(pointersInData);
                                        //if ( verbose )
                                        //      fprintf(stderr, "update_dyld_shared_cache: for %s, rebasing dylib into cache for %s\n", archName(), it->layout->getID().name);
                                }
                                        //if ( verbose )
                                        //      fprintf(stderr, "update_dyld_shared_cache: for %s, rebasing dylib into cache for %s\n", archName(), it->layout->getID().name);
                                }
@@ -1905,20 +2310,6 @@ bool SharedCache<A>::update(bool usesOverlay, bool force, bool optimize, bool de
                                }
                        }
                        
                                }
                        }
                        
-                       // 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);
-                               //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;
-                               dyldCacheFileMapping<E>* mappings = (dyldCacheFileMapping<E>*)&inMemoryCache[sizeof(dyldCacheHeader<E>)];
-                               dyldCacheFileMapping<E>* lastMapping = &mappings[cacheHeader->mappingCount()-1];
-                               lastMapping->set_size(cacheFileSize-lastMapping->file_offset());
-                               // update fMappings so .map file will print correctly
-                               fMappings.back().sfm_size = cacheFileSize-fMappings.back().sfm_file_offset;
-                       }
-                       
                        if ( verbose )
                                fprintf(stderr, "update_dyld_shared_cache: for %s, updating binding information for %lu files:\n", archName(), fDylibs.size());
                        // instantiate a Binder for each image and add to map
                        if ( verbose )
                                fprintf(stderr, "update_dyld_shared_cache: for %s, updating binding information for %lu files:\n", archName(), fDylibs.size());
                        // instantiate a Binder for each image and add to map
@@ -1942,7 +2333,16 @@ bool SharedCache<A>::update(bool usesOverlay, bool force, bool optimize, bool de
                                if ( verbose )
                                        fprintf(stderr, "update_dyld_shared_cache: for %s, updating binding information in cache for %s\n", archName(), (*it)->getDylibID());
                                try {
                                if ( verbose )
                                        fprintf(stderr, "update_dyld_shared_cache: for %s, updating binding information in cache for %s\n", archName(), (*it)->getDylibID());
                                try {
-                                       (*it)->bind();
+                                       (*it)->bind(pointersInData);
+                               }
+                               catch (const char* msg) {
+                                       throwf("%s in %s", msg, (*it)->getDylibID());
+                               }
+                       }
+                       // optimize binding
+                       for(typename std::vector<Binder<A>*>::iterator it = binders.begin(); it != binders.end(); ++it) {
+                               try {
+                                       (*it)->optimize();
                                }
                                catch (const char* msg) {
                                        throwf("%s in %s", msg, (*it)->getDylibID());
                                }
                                catch (const char* msg) {
                                        throwf("%s in %s", msg, (*it)->getDylibID());
@@ -1953,16 +2353,118 @@ bool SharedCache<A>::update(bool usesOverlay, bool force, bool optimize, bool de
                                delete *it;
                        }
        
                                delete *it;
                        }
        
+                       // 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);
+                               //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;
+                               dyldCacheFileMapping<E>* mappings = (dyldCacheFileMapping<E>*)&inMemoryCache[sizeof(dyldCacheHeader<E>)];
+                               dyldCacheFileMapping<E>* lastMapping = &mappings[cacheHeader->mappingCount()-1];
+                               lastMapping->set_size(cacheFileSize-lastMapping->file_offset());
+                               // update fMappings so .map file will print correctly
+                               fMappings.back().sfm_size = cacheFileSize-fMappings.back().sfm_file_offset;
+                               // update header
+                               //fprintf(stderr, "update_dyld_shared_cache: changing end of cache address from 0x%08llX to 0x%08llX\n", 
+                               //              header->codeSignatureOffset(), fMappings.back().sfm_address + fMappings.back().sfm_size);
+                               header->set_codeSignatureOffset(fMappings.back().sfm_file_offset + fMappings.back().sfm_size);
+                       }
+                       
                        // unique objc selectors and update other objc metadata
                        // unique objc selectors and update other objc metadata
-            if (optimize) {
-                optimizeObjC();
-            }
-                       if ( progress ) {
-                               // assuming objc optimizations takes 15% of time
-                               fprintf(stdout, "%3u/%u\n", (archIndex+1)*55, archCount*100);
+            if ( optimize ) {
+                               optimizeObjC(pointersInData);
+                               if ( progress ) {
+                                       // assuming objc optimizations takes 15% of time
+                                       fprintf(stdout, "%3u/%u\n", (archIndex+1)*55, archCount*100);
+                               }
                        }
 
                        }
 
+                       if ( addCacheSlideInfo() ) {
+                               // build bitmap of which pointers need sliding
+                               uint8_t* const dataStart = &inMemoryCache[fMappings[1].sfm_file_offset]; // R/W mapping is always second
+                               uint8_t* const dataEnd   = &inMemoryCache[fMappings[1].sfm_file_offset+fMappings[1].sfm_size];
+                               const int bitmapSize = (dataEnd - dataStart)/(4*8);
+                               uint8_t* bitmap = (uint8_t*)calloc(bitmapSize, 1);
+                               void* lastPointer = inMemoryCache;
+                               for(std::vector<void*>::iterator pit=pointersInData.begin(); pit != pointersInData.end(); ++pit) {
+                                       if ( *pit != lastPointer ) {
+                                               void* p = *pit;
+                                               if ( (p < dataStart) || ( p > dataEnd) )
+                                                       throwf("DATA pointer for sliding, out of range 0x%08lX\n", (long)((uint8_t*)p-inMemoryCache));
+                                               long offset = (long)((uint8_t*)p - dataStart);
+                                               if ( (offset % 4) != 0 )
+                                                       throwf("pointer not 4-byte aligned in DATA offset 0x%08lX\n", offset);
+                                               long byteIndex = offset / (4*8);
+                                               long bitInByte =  (offset % 32) >> 2;
+                                               bitmap[byteIndex] |= (1 << bitInByte);
+                                               lastPointer = p;
+                                       }
+                               }
+
+                               // allocate worst case size block of all slide info
+                               const int entry_size = 4096/(8*4); // 8 bits per byte, possible pointer every 4 bytes.
+                               const int toc_count = bitmapSize/entry_size;
+                               int slideInfoSize = sizeof(dyldCacheSlideInfo<E>) + 2*toc_count + entry_size*(toc_count+1);
+                               dyldCacheSlideInfo<E>* slideInfo = (dyldCacheSlideInfo<E>*)calloc(slideInfoSize, 1);
+                               slideInfo->set_version(1);
+                               slideInfo->set_toc_offset(sizeof(dyldCacheSlideInfo<E>));
+                               slideInfo->set_toc_count(toc_count);
+                               slideInfo->set_entries_offset((slideInfo->toc_offset()+2*toc_count+127)&(-128));
+                               slideInfo->set_entries_count(0);
+                               slideInfo->set_entries_size(entry_size);
+                               // append each unique entry 
+                               const dyldCacheSlideInfoEntry* bitmapAsEntries = (dyldCacheSlideInfoEntry*)bitmap;
+                               dyldCacheSlideInfoEntry* const entriesInSlidInfo = (dyldCacheSlideInfoEntry*)((char*)slideInfo+slideInfo->entries_offset());
+                               int entry_count = 0;
+                               for (int i=0; i < toc_count; ++i) {
+                                       const dyldCacheSlideInfoEntry* thisEntry = &bitmapAsEntries[i];
+                                       // see if it is same as one already added
+                                       bool found = false;
+                                       for (int j=0; j < entry_count; ++j) {
+                                               if ( memcmp(thisEntry, &entriesInSlidInfo[j], entry_size) == 0 ) {
+                                                       //fprintf(stderr, "toc[%d] optimized to %d\n", i, j);
+                                                       slideInfo->set_toc(i, j);
+                                                       found = true;
+                                                       break;
+                                               }       
+                                       }
+                                       if ( ! found ) {
+                                               // append to end
+                                               memcpy(&entriesInSlidInfo[entry_count], thisEntry, entry_size);
+                                               slideInfo->set_toc(i, entry_count++);
+                                       }
+                               }
+                               slideInfo->set_entries_count(entry_count);
+       
+                               int slideInfoPageSize = (slideInfo->entries_offset() + entry_count*entry_size + 4095) & (-4096);
+                               cacheFileSize += slideInfoPageSize;
+                       
+                               // update mappings to increase RO size
+                               dyldCacheHeader<E>* cacheHeader = (dyldCacheHeader<E>*)inMemoryCache;
+                               dyldCacheFileMapping<E>* mappings = (dyldCacheFileMapping<E>*)&inMemoryCache[sizeof(dyldCacheHeader<E>)];
+                               dyldCacheFileMapping<E>* lastMapping = &mappings[cacheHeader->mappingCount()-1];
+                               lastMapping->set_size(lastMapping->size()+slideInfoPageSize);
+                               
+                               // update header to show location of slidePointers
+                               cacheHeader->set_slideInfoOffset(cacheHeader->codeSignatureOffset());
+                               cacheHeader->set_slideInfoSize(slideInfoPageSize);
+                               cacheHeader->set_codeSignatureOffset(cacheHeader->codeSignatureOffset()+slideInfoPageSize);
+                               
+                               // update fMappings so .map file will print correctly
+                               fMappings.back().sfm_size = cacheFileSize-fMappings.back().sfm_file_offset;
+                               
+                               // copy compressed into into buffer
+                               memcpy(&inMemoryCache[cacheHeader->slideInfoOffset()], slideInfo, slideInfoPageSize);   
+                       }
+                       
+                       
                        if ( fVerify ) {
                        if ( fVerify ) {
+                               // 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());
+                               }
                                // new cache is built, compare header entries
                                const dyldCacheHeader<E>* newHeader = (dyldCacheHeader<E>*)inMemoryCache;
                                const dyldCacheHeader<E>* oldHeader = (dyldCacheHeader<E>*)fExistingCacheForVerification;
                                // new cache is built, compare header entries
                                const dyldCacheHeader<E>* newHeader = (dyldCacheHeader<E>*)inMemoryCache;
                                const dyldCacheHeader<E>* oldHeader = (dyldCacheHeader<E>*)fExistingCacheForVerification;
@@ -2070,11 +2572,33 @@ bool SharedCache<A>::update(bool usesOverlay, bool force, bool optimize, bool de
                                if ( result != 0 ) 
                                        fprintf(stderr, "update_dyld_shared_cache: warning, close() failed with errno=%d for %s\n", errno, tempCachePath);
                                
                                if ( result != 0 ) 
                                        fprintf(stderr, "update_dyld_shared_cache: warning, close() failed with errno=%d for %s\n", errno, tempCachePath);
                                
-                               // atomically swap in new cache file, do this after F_FULLFSYNC
+                               // <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
+                               // may be mapped into the shared region, it cannot be deleted
+                               // until all user processes are terminated.  That leaves are
+                               // small to non-existent window for the kernel to delete the
+                               // old cache file.
+                               if ( fCacheFileInFinalLocation ) {
+                                       char tmpDirPath[64];
+                                       const char* pathLastSlash = strrchr(fCacheFilePath, '/');
+                                       if ( pathLastSlash != NULL ) {
+                                               sprintf(tmpDirPath, "/var/run%s.old.%u", pathLastSlash, getpid());
+                                               // move existing cache file to /var/run to be clean up next boot
+                                               result = ::rename(fCacheFilePath, tmpDirPath);
+                                               if ( result != 0 ) {
+                                                       if ( errno != ENOENT )
+                                                               fprintf(stderr, "update_dyld_shared_cache: warning, unable to move existing cache to %s errno=%d for %s\n", tmpDirPath, errno, fCacheFilePath);
+                                               }
+                                       }
+                               }
+                               
+                               // move new cache file to correct location for use after reboot
                                result = ::rename(tempCachePath, fCacheFilePath);
                                if ( result != 0 ) 
                                        throwf("can't swap newly create dyld shared cache file: rename(%s,%s) returned errno=%d", tempCachePath, fCacheFilePath, errno);
                                result = ::rename(tempCachePath, fCacheFilePath);
                                if ( result != 0 ) 
                                        throwf("can't swap newly create dyld shared cache file: rename(%s,%s) returned errno=%d", tempCachePath, fCacheFilePath, errno);
-                                       
+                               
+                               
                                // flush everything to disk to assure rename() gets recorded
                                ::sync();
                                didUpdate = true;
                                // flush everything to disk to assure rename() gets recorded
                                ::sync();
                                didUpdate = true;
@@ -2128,13 +2652,33 @@ bool SharedCache<A>::update(bool usesOverlay, bool force, bool optimize, bool de
                                                                (fOffsetOfOldSymbolTableInfoInCombinedLinkedit-fOffsetOfLazyBindInfoInCombinedLinkedit)/1024,
                                                                fLinkEditsStartAddress+fOffsetOfLazyBindInfoInCombinedLinkedit,
                                                                fLinkEditsStartAddress+fOffsetOfOldSymbolTableInfoInCombinedLinkedit);
                                                                (fOffsetOfOldSymbolTableInfoInCombinedLinkedit-fOffsetOfLazyBindInfoInCombinedLinkedit)/1024,
                                                                fLinkEditsStartAddress+fOffsetOfLazyBindInfoInCombinedLinkedit,
                                                                fLinkEditsStartAddress+fOffsetOfOldSymbolTableInfoInCombinedLinkedit);
-                                       fprintf(fmap, "linkedit   %4uMB 0x%0llX -> 0x%0llX non-dyld symbol table info\n",               
-                                                               (fLinkEditsTotalOptimizedSize-fOffsetOfOldSymbolTableInfoInCombinedLinkedit)/(1024*1024),
+                                       fprintf(fmap, "linkedit   %4uMB 0x%0llX -> 0x%0llX non-dyld symbol table size\n",               
+                                                               (fSizeOfOldSymbolTableInfoInCombinedLinkedit)/(1024*1024),
                                                                fLinkEditsStartAddress+fOffsetOfOldSymbolTableInfoInCombinedLinkedit,
                                                                fLinkEditsStartAddress+fOffsetOfOldSymbolTableInfoInCombinedLinkedit,
-                                                               fLinkEditsStartAddress+fLinkEditsTotalOptimizedSize);                           
+                                                               fLinkEditsStartAddress+fOffsetOfOldSymbolTableInfoInCombinedLinkedit+fSizeOfOldSymbolTableInfoInCombinedLinkedit);                              
+                                       if ( fSizeOfFunctionStartsInCombinedLinkedit != 0 )
+                                               fprintf(fmap, "linkedit   %4uKB 0x%0llX -> 0x%0llX non-dyld functions starts size\n",           
+                                                               fSizeOfFunctionStartsInCombinedLinkedit/1024,
+                                                               fLinkEditsStartAddress+fOffsetOfFunctionStartsInCombinedLinkedit,
+                                                               fLinkEditsStartAddress+fOffsetOfFunctionStartsInCombinedLinkedit+fSizeOfFunctionStartsInCombinedLinkedit);                              
+                                       if ( fSizeOfOldExternalRelocationsInCombinedLinkedit != 0 )
+                                               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",              
+                                                               fSizeOfOldIndirectSymbolsInCombinedLinkedit/1024,
+                                                               fLinkEditsStartAddress+fOffsetOfOldIndirectSymbolsInCombinedLinkedit,
+                                                               fLinkEditsStartAddress+fOffsetOfOldIndirectSymbolsInCombinedLinkedit+fSizeOfOldIndirectSymbolsInCombinedLinkedit);                              
+                                       fprintf(fmap, "linkedit   %4uMB 0x%0llX -> 0x%0llX non-dyld string pool\n",             
+                                                               (fSizeOfOldStringPoolInCombinedLinkedit)/(1024*1024),
+                                                               fLinkEditsStartAddress+fOffsetOfOldStringPoolInCombinedLinkedit,
+                                                               fLinkEditsStartAddress+fOffsetOfOldStringPoolInCombinedLinkedit+fSizeOfOldStringPoolInCombinedLinkedit);                                
                                        
                                        for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
                                                fprintf(fmap, "%s\n", it->layout->getID().name);
                                        
                                        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) 
+                                                       fprintf(fmap, "%s\n", *ait);
                                                const std::vector<MachOLayoutAbstraction::Segment>&     segs = it->layout->getSegments();
                                                for (int i=0; i < segs.size(); ++i) {
                                                        const MachOLayoutAbstraction::Segment& seg = segs[i];
                                                const std::vector<MachOLayoutAbstraction::Segment>&     segs = it->layout->getSegments();
                                                for (int i=0; i < segs.size(); ++i) {
                                                        const MachOLayoutAbstraction::Segment& seg = segs[i];
@@ -2227,7 +2771,15 @@ static void parsePathsFile(const char* filePath, std::vector<const char*>& paths
                                                *last = '\0';
                                                --last;
                                        }
                                                *last = '\0';
                                                --last;
                                        }
-                                       paths.push_back(symbolStart);
+                                       // <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");
+                                       }
+                                       else {
+                                               paths.push_back(symbolStart);
+                                       }
                                        symbolStart = NULL;
                                        state = lineStart;
                                }
                                        symbolStart = NULL;
                                        state = lineStart;
                                }
@@ -2281,14 +2833,23 @@ static void scanForSharedDylibs(const char* rootPath, bool usesOverlay, const ch
        if ( dir == NULL )
                throwf("%s does not exist, errno=%d\n", dirOfPathFiles, errno);
        for (dirent* entry = ::readdir(dir); entry != NULL; entry = ::readdir(dir)) {
        if ( dir == NULL )
                throwf("%s does not exist, errno=%d\n", dirOfPathFiles, errno);
        for (dirent* entry = ::readdir(dir); entry != NULL; entry = ::readdir(dir)) {
-               if ( entry->d_type == DT_REG ) {
-                       // only look at files ending in .paths
+               if ( entry->d_type == DT_REG || entry->d_type == DT_UNKNOWN ) {
+                       // only look at regular files ending in .paths
                        if ( strcmp(&entry->d_name[entry->d_namlen-6], ".paths") == 0 ) {
                        if ( strcmp(&entry->d_name[entry->d_namlen-6], ".paths") == 0 ) {
+                               struct stat tmpStatPathsFile;
                                char fullPath[strlen(dirOfPathFiles)+entry->d_namlen+2];
                                strcpy(fullPath, dirOfPathFiles);
                                strcat(fullPath, "/");
                                strcat(fullPath, entry->d_name);
                                char fullPath[strlen(dirOfPathFiles)+entry->d_namlen+2];
                                strcpy(fullPath, dirOfPathFiles);
                                strcat(fullPath, "/");
                                strcat(fullPath, entry->d_name);
-                               parsePathsFile(fullPath, rootsPaths);
+                               if ( lstat(fullPath, &tmpStatPathsFile) == -1 ) {
+                                       fprintf(stderr, "update_dyld_shared_cache: can't access %s\n", fullPath);
+                               } 
+                               else if ( S_ISREG(tmpStatPathsFile.st_mode) ) {
+                                       parsePathsFile(fullPath, rootsPaths);
+                               } 
+                               else {
+                                       fprintf(stderr, "update_dyld_shared_cache: wrong file type for %s\n", fullPath);
+                               }
                        }
                        else {
                                fprintf(stderr, "update_dyld_shared_cache: warning, ignore file with wrong extension: %s\n", entry->d_name);
                        }
                        else {
                                fprintf(stderr, "update_dyld_shared_cache: warning, ignore file with wrong extension: %s\n", entry->d_name);
@@ -2317,15 +2878,15 @@ static void setSharedDylibs(const char* rootPath, bool usesOverlay, const char*
 // creation time was before the last restart of this machine.
 static void deleteOrphanTempCacheFiles()
 {
 // creation time was before the last restart of this machine.
 static void deleteOrphanTempCacheFiles()
 {
-       DIR* dir = ::opendir(DYLD_SHARED_CACHE_DIR);
+       DIR* dir = ::opendir(MACOSX_DYLD_SHARED_CACHE_DIR);
        if ( dir != NULL ) {
                std::vector<const char*> filesToDelete;
                for (dirent* entry = ::readdir(dir); entry != NULL; entry = ::readdir(dir)) {
                        if ( entry->d_type == DT_REG ) {
                                // only look at files with .tmp in name
                                if ( strstr(entry->d_name, ".tmp") != NULL ) {
        if ( dir != NULL ) {
                std::vector<const char*> filesToDelete;
                for (dirent* entry = ::readdir(dir); entry != NULL; entry = ::readdir(dir)) {
                        if ( entry->d_type == DT_REG ) {
                                // only look at files with .tmp in name
                                if ( strstr(entry->d_name, ".tmp") != NULL ) {
-                                       char fullPath[strlen(DYLD_SHARED_CACHE_DIR)+entry->d_namlen+2];
-                                       strcpy(fullPath, DYLD_SHARED_CACHE_DIR);
+                                       char fullPath[strlen(MACOSX_DYLD_SHARED_CACHE_DIR)+entry->d_namlen+2];
+                                       strcpy(fullPath, MACOSX_DYLD_SHARED_CACHE_DIR);
                                        strcat(fullPath, "/");
                                        strcat(fullPath, entry->d_name);
                                        struct stat tmpFileStatInfo;
                                        strcat(fullPath, "/");
                                        strcat(fullPath, entry->d_name);
                                        struct stat tmpFileStatInfo;
@@ -2383,36 +2944,37 @@ static bool updateSharedeCacheFile(const char* rootPath, bool usesOverlay, const
                                {
                #if __i386__ || __x86_64__
                                        // <rdar://problem/5217377> Rosetta does not work with optimized dyld shared cache
                                {
                #if __i386__ || __x86_64__
                                        // <rdar://problem/5217377> Rosetta does not work with optimized dyld shared cache
-                                       SharedCache<ppc> cache(ArchGraph::graphForArchPair(*a), rootPath, alphaSort, verify, false, usesOverlay, dyldBaseAddress);
+                                       SharedCache<ppc> cache(ArchGraph::graphForArchPair(*a), rootPath, cacheDir, alphaSort, verify, false, usesOverlay, dyldBaseAddress);
                                        didUpdate |= cache.update(usesOverlay, force, false, deleteExistingFirst, index, archCount, keepSignatures);
                #else
                                        didUpdate |= cache.update(usesOverlay, force, false, deleteExistingFirst, index, archCount, keepSignatures);
                #else
-                                       SharedCache<ppc> cache(ArchGraph::graphForArchPair(*a), rootPath, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress);
+                                       SharedCache<ppc> cache(ArchGraph::graphForArchPair(*a), rootPath, cacheDir, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress);
                                        didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
                #endif
                                }
                                break;
                        case CPU_TYPE_I386:
                                {
                                        didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
                #endif
                                }
                                break;
                        case CPU_TYPE_I386:
                                {
-                                       SharedCache<x86> cache(ArchGraph::graphForArchPair(*a), rootPath, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress);
+                                       SharedCache<x86> cache(ArchGraph::graphForArchPair(*a), rootPath, cacheDir, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress);
                                        didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
                                }
                                break;
                        case CPU_TYPE_X86_64:
                                {
                                        didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
                                }
                                break;
                        case CPU_TYPE_X86_64:
                                {
-                                       SharedCache<x86_64> cache(ArchGraph::graphForArchPair(*a), rootPath, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress);
+                                       SharedCache<x86_64> cache(ArchGraph::graphForArchPair(*a), rootPath, cacheDir, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress);
                                        didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
                                }
                                break;
                        case CPU_TYPE_ARM:
                                {
                                        didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
                                }
                                break;
                        case CPU_TYPE_ARM:
                                {
-                                       SharedCache<arm> cache(ArchGraph::graphForArchPair(*a), rootPath, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress);
+                                       SharedCache<arm> cache(ArchGraph::graphForArchPair(*a), rootPath, cacheDir, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress);
                                        didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
                                }
                                break;
                }
        }
        
                                        didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
                                }
                                break;
                }
        }
        
-       deleteOrphanTempCacheFiles();
+       if ( !iPhoneOS )
+               deleteOrphanTempCacheFiles();
        
        return didUpdate;
 }
        
        return didUpdate;
 }
@@ -2436,6 +2998,7 @@ int main(int argc, const char* argv[])
        bool hasOverlay = false;
        bool verify = false;
        bool keepSignatures = false;
        bool hasOverlay = false;
        bool verify = false;
        bool keepSignatures = false;
+       const char* cacheDir = NULL;
        
        try {
                // parse command line options
        
        try {
                // parse command line options
@@ -2463,11 +3026,13 @@ int main(int argc, const char* argv[])
                                else if ( strcmp(arg, "-no_opt") == 0 ) {
                                        optimize = false;
                                }
                                else if ( strcmp(arg, "-no_opt") == 0 ) {
                                        optimize = false;
                                }
+                               else if ( strcmp(arg, "-iPhone") == 0 ) {
+                                       iPhoneOS = true;
+                               }
                                else if ( strcmp(arg, "-dylib_list") == 0 ) {
                                        dylibListFile = argv[++i];
                                        if ( dylibListFile == NULL )
                                                throw "-dylib_list missing path argument";
                                else if ( strcmp(arg, "-dylib_list") == 0 ) {
                                        dylibListFile = argv[++i];
                                        if ( dylibListFile == NULL )
                                                throw "-dylib_list missing path argument";
-                                       keepSignatures = true;
                                }
                                else if ( (strcmp(arg, "-root") == 0) || (strcmp(arg, "--root") == 0) ) {
                                        if ( hasOverlay )
                                }
                                else if ( (strcmp(arg, "-root") == 0) || (strcmp(arg, "--root") == 0) ) {
                                        if ( hasOverlay )
@@ -2485,6 +3050,11 @@ int main(int argc, const char* argv[])
                                                throw "-root missing path argument";
                                        hasOverlay = true;
                                }
                                                throw "-root missing path argument";
                                        hasOverlay = true;
                                }
+                               else if ( strcmp(arg, "-cache_dir") == 0 ) {
+                                       cacheDir = argv[++i];
+                                       if ( cacheDir == NULL )
+                                               throw "-cache_dir missing path argument";
+                               }
                                else if ( strcmp(arg, "-arch") == 0 ) {
                                        const char* arch = argv[++i];
                                        if ( strcmp(arch, "ppc") == 0 ) 
                                else if ( strcmp(arg, "-arch") == 0 ) {
                                        const char* arch = argv[++i];
                                        if ( strcmp(arch, "ppc") == 0 ) 
@@ -2523,41 +3093,55 @@ int main(int argc, const char* argv[])
                }
                                
                // strip tailing slashes on -root or -overlay
                }
                                
                // strip tailing slashes on -root or -overlay
+               // make it a real path so as to not make all dylibs look like symlink aliases
                if ( rootPath[0] != '\0' ) {
                if ( rootPath[0] != '\0' ) {
-                       int len = strlen(rootPath)-1;
-                       if (  rootPath[len] == '/' ) {
-                               char* newRootPath = strdup(rootPath);
-                               while ( newRootPath[len] == '/' )       
-                                       newRootPath[len--] = '\0';
-                               rootPath = newRootPath;
-                       }
+                       char realRootPath[MAXPATHLEN];
+                       if ( realpath(rootPath, realRootPath) == NULL )
+                               throwf("realpath() failed on %s\n", rootPath);
+                       rootPath = strdup(realRootPath);
                }
                
                }
                
+               // set location to write cache dir
+               if ( cacheDir == NULL ) {
+                       if ( (rootPath[0] == '\0') || hasOverlay ) {
+                               cacheDir =  (iPhoneOS ? IPHONE_DYLD_SHARED_CACHE_DIR : MACOSX_DYLD_SHARED_CACHE_DIR);
+                       }
+                       else {
+                               asprintf((char**)&cacheDir, "%s/%s", rootPath, (iPhoneOS ? IPHONE_DYLD_SHARED_CACHE_DIR : MACOSX_DYLD_SHARED_CACHE_DIR));
+                       }
+               }
+
                // if no restrictions specified, use architectures that work on this machine
                if ( onlyArchs.size() == 0 ) {
                // if no restrictions specified, use architectures that work on this machine
                if ( onlyArchs.size() == 0 ) {
-                       int available;
-                       size_t len = sizeof(int);
-               #if __i386__ || __x86_64__
-                       onlyArchs.insert(ArchPair(CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL));
-                       // check rosetta is installed
-                       char rosettaPath[1024];
-                       strlcpy(rosettaPath, rootPath, 1024);
-                       strlcat(rosettaPath, "/usr/libexec/oah/translate", 1024);
-                       struct stat stat_buf;
-                       if ( stat(rosettaPath, &stat_buf) == 0 ) {
-                               onlyArchs.insert(ArchPair(CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL));
+                       if ( iPhoneOS ) {
+                               onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6));
+                               onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7));
                        }
                        }
-                       else if ( hasOverlay ) {
-                               // in overlay mode, rosetta may be installed on base system, but is not in update root
-                               if ( stat("/usr/libexec/oah/translate", &stat_buf) == 0 ) 
+                       else {
+                               int available;
+                               size_t len = sizeof(int);
+                       #if __i386__ || __x86_64__
+                               onlyArchs.insert(ArchPair(CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL));
+                               // check rosetta is installed
+                               char rosettaPath[1024];
+                               strlcpy(rosettaPath, rootPath, 1024);
+                               strlcat(rosettaPath, "/usr/libexec/oah/translate", 1024);
+                               struct stat stat_buf;
+                               if ( stat(rosettaPath, &stat_buf) == 0 ) {
                                        onlyArchs.insert(ArchPair(CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL));
                                        onlyArchs.insert(ArchPair(CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL));
+                               }
+                               else if ( hasOverlay ) {
+                                       // in overlay mode, rosetta may be installed on base system, but is not in update root
+                                       if ( stat("/usr/libexec/oah/translate", &stat_buf) == 0 ) 
+                                               onlyArchs.insert(ArchPair(CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL));
+                               }
+                               // check system is capable of running 64-bit programs
+                               if ( (sysctlbyname("hw.optional.x86_64", &available, &len, NULL, 0) == 0) && available )
+                                       onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL));
+                       #else
+                               #error unsupported architecture
+                       #endif
                        }
                        }
-                       // check system is capable of running 64-bit programs
-                       if ( (sysctlbyname("hw.optional.x86_64", &available, &len, NULL, 0) == 0) && available )
-                               onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL));
-               #else
-                       #error unknown architecture
-               #endif
                }
                
                if ( !verify && (geteuid() != 0) )
                }
                
                if ( !verify && (geteuid() != 0) )
@@ -2568,7 +3152,7 @@ int main(int argc, const char* argv[])
                        setSharedDylibs(rootPath, hasOverlay, dylibListFile, onlyArchs);
                else
                        scanForSharedDylibs(rootPath, hasOverlay, "/var/db/dyld/shared_region_roots/", onlyArchs);
                        setSharedDylibs(rootPath, hasOverlay, dylibListFile, onlyArchs);
                else
                        scanForSharedDylibs(rootPath, hasOverlay, "/var/db/dyld/shared_region_roots/", onlyArchs);
-               updateSharedeCacheFile(rootPath, hasOverlay, DYLD_SHARED_CACHE_DIR, onlyArchs, force, alphaSort, optimize, 
+               updateSharedeCacheFile(rootPath, hasOverlay, cacheDir, onlyArchs, force, alphaSort, optimize, 
                                                                false, verify, keepSignatures);
        }
        catch (const char* msg) {
                                                                false, verify, keepSignatures);
        }
        catch (const char* msg) {
index 23f89cbde1341333932f7daea3e7164f2576421b..3b0e8242155f1c6829f64b00821761a329866ddc 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2004-2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -40,7 +40,6 @@
 
 uint32_t                                                               ImageLoader::fgImagesUsedFromSharedCache = 0;
 uint32_t                                                               ImageLoader::fgImagesWithUsedPrebinding = 0;
 
 uint32_t                                                               ImageLoader::fgImagesUsedFromSharedCache = 0;
 uint32_t                                                               ImageLoader::fgImagesWithUsedPrebinding = 0;
-uint32_t                                                               ImageLoader::fgImagesRequiringNoFixups = 0;
 uint32_t                                                               ImageLoader::fgImagesRequiringCoalescing = 0;
 uint32_t                                                               ImageLoader::fgImagesHasWeakDefinitions = 0;
 uint32_t                                                               ImageLoader::fgTotalRebaseFixups = 0;
 uint32_t                                                               ImageLoader::fgImagesRequiringCoalescing = 0;
 uint32_t                                                               ImageLoader::fgImagesHasWeakDefinitions = 0;
 uint32_t                                                               ImageLoader::fgTotalRebaseFixups = 0;
@@ -59,6 +58,7 @@ uint64_t                                                              ImageLoader::fgTotalWeakBindTime;
 uint64_t                                                               ImageLoader::fgTotalDOF;
 uint64_t                                                               ImageLoader::fgTotalInitTime;
 uint16_t                                                               ImageLoader::fgLoadOrdinal = 0;
 uint64_t                                                               ImageLoader::fgTotalDOF;
 uint64_t                                                               ImageLoader::fgTotalInitTime;
 uint16_t                                                               ImageLoader::fgLoadOrdinal = 0;
+std::vector<ImageLoader::InterposeTuple>ImageLoader::fgInterposingTuples;
 uintptr_t                                                              ImageLoader::fgNextPIEDylibAddress = 0;
 
 
 uintptr_t                                                              ImageLoader::fgNextPIEDylibAddress = 0;
 
 
@@ -67,10 +67,11 @@ ImageLoader::ImageLoader(const char* path, unsigned int libCount)
        : fPath(path), fDevice(0), fInode(0), fLastModified(0), 
        fPathHash(0), fDlopenReferenceCount(0), fStaticReferenceCount(0),
        fDynamicReferenceCount(0), fDynamicReferences(NULL), fInitializerRecursiveLock(NULL), 
        : fPath(path), fDevice(0), fInode(0), fLastModified(0), 
        fPathHash(0), fDlopenReferenceCount(0), fStaticReferenceCount(0),
        fDynamicReferenceCount(0), fDynamicReferences(NULL), fInitializerRecursiveLock(NULL), 
-       fDepth(0), fLoadOrder(0), fState(0), fLibraryCount(libCount), 
+       fDepth(0), fLoadOrder(fgLoadOrdinal++), fState(0), fLibraryCount(libCount), 
        fAllLibraryChecksumsAndLoadAddressesMatch(false), fLeaveMapped(false), fNeverUnload(false),
        fHideSymbols(false), fMatchByInstallName(false),
        fAllLibraryChecksumsAndLoadAddressesMatch(false), fLeaveMapped(false), fNeverUnload(false),
        fHideSymbols(false), fMatchByInstallName(false),
-       fRegisteredDOF(false), fAllLazyPointersBound(false), fBeingRemoved(false), fAddFuncNotified(false),
+       fInterposed(false), fRegisteredDOF(false), fAllLazyPointersBound(false), 
+    fBeingRemoved(false), fAddFuncNotified(false),
        fPathOwnedByImage(false), fWeakSymbolsBound(false)
 {
        if ( fPath != NULL )
        fPathOwnedByImage(false), fWeakSymbolsBound(false)
 {
        if ( fPath != NULL )
@@ -82,9 +83,11 @@ void ImageLoader::deleteImage(ImageLoader* image)
 {
        // this cannot be done in destructor because libImage() is implemented
        // in a subclass
 {
        // 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);
        for(unsigned int i=0; i < image->libraryCount(); ++i) {
                ImageLoader* lib = image->libImage(i);
-               if ( lib != NULL )
+               if ( (lib != NULL) && ! libraryInfos[i].upward )
                        lib->fStaticReferenceCount--;
        }
        delete image;
                        lib->fStaticReferenceCount--;
        }
        delete image;
@@ -96,7 +99,7 @@ ImageLoader::~ImageLoader()
        if ( fPathOwnedByImage && (fPath != NULL) ) 
                delete [] fPath;
        if ( fDynamicReferences != NULL ) {
        if ( fPathOwnedByImage && (fPath != NULL) ) 
                delete [] fPath;
        if ( fDynamicReferences != NULL ) {
-               for (std::set<const ImageLoader*>::iterator it = fDynamicReferences->begin(); it != fDynamicReferences->end(); ++it ) {
+               for (std::vector<const ImageLoader*>::iterator it = fDynamicReferences->begin(); it != fDynamicReferences->end(); ++it ) {
                        const_cast<ImageLoader*>(*it)->fDynamicReferenceCount--;
                }
                delete fDynamicReferences;
                        const_cast<ImageLoader*>(*it)->fDynamicReferenceCount--;
                }
                delete fDynamicReferences;
@@ -118,10 +121,20 @@ void ImageLoader::setMapped(const LinkContext& context)
 
 void ImageLoader::addDynamicReference(const ImageLoader* target)
 {
 
 void ImageLoader::addDynamicReference(const ImageLoader* target)
 {
-       if ( fDynamicReferences == NULL )
-               fDynamicReferences = new std::set<const ImageLoader*>();
-       if ( fDynamicReferences->count(target) == 0 ) { 
-               fDynamicReferences->insert(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());
                const_cast<ImageLoader*>(target)->fDynamicReferenceCount++;
        }
        //dyld::log("dyld: addDynamicReference() from %s to %s, fDynamicReferences->size()=%lu\n", this->getPath(), target->getPath(), fDynamicReferences->size());
@@ -246,6 +259,13 @@ bool ImageLoader::overlapsWithAddressRange(const void* start, const void* end) c
        for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
                const uint8_t* segStart = (const uint8_t*)segActualLoadAddress(i);
                const uint8_t* segEnd = (const uint8_t*)segActualEndAddress(i);
        for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
                const uint8_t* segStart = (const uint8_t*)segActualLoadAddress(i);
                const uint8_t* segEnd = (const uint8_t*)segActualEndAddress(i);
+               if ( strcmp(segName(i), "__UNIXSTACK") == 0 ) {
+                       // __UNIXSTACK never slides.  This is the only place that cares
+                       // and checking for that segment name in segActualLoadAddress()
+                       // is too expensive.
+                       segStart -= getSlide();
+                       segEnd -= getSlide();
+               }
                if ( (start <= segStart) && (segStart < end) )
                        return true;
                if ( (start <= segEnd) && (segEnd < end) )
                if ( (start <= segStart) && (segStart < end) )
                        return true;
                if ( (start <= segEnd) && (segEnd < end) )
@@ -332,11 +352,20 @@ const ImageLoader::Symbol* ImageLoader::findExportedSymbolInImageOrDependentImag
        return this->findExportedSymbolInDependentImagesExcept(name, &dontSearchImages[0], cur, &dontSearchImages[imageCount], foundIn);
 }
 
        return this->findExportedSymbolInDependentImagesExcept(name, &dontSearchImages[0], cur, &dontSearchImages[imageCount], foundIn);
 }
 
+// this is called by initializeMainExecutable() to interpose on the initial set of images
+void ImageLoader::applyInterposing(const LinkContext& context)
+{
+       if ( fgInterposingTuples.size() != 0 )
+               this->recursiveApplyInterposing(context);
+}
 
 void ImageLoader::link(const LinkContext& context, bool forceLazysBound, bool preflightOnly, const RPathChain& loaderRPaths)
 {
        //dyld::log("ImageLoader::link(%s) refCount=%d, neverUnload=%d\n", this->getPath(), fStaticReferenceCount, fNeverUnload);
        
 
 void ImageLoader::link(const LinkContext& context, bool forceLazysBound, bool preflightOnly, const RPathChain& loaderRPaths)
 {
        //dyld::log("ImageLoader::link(%s) refCount=%d, neverUnload=%d\n", this->getPath(), fStaticReferenceCount, fNeverUnload);
        
+       // clear error strings
+       (*context.setErrorStrings)(dyld_error_kind_none, NULL, NULL, NULL);
+
        uint64_t t0 = mach_absolute_time();
        this->recursiveLoadLibraries(context, preflightOnly, loaderRPaths);
        context.notifyBatch(dyld_image_state_dependents_mapped);
        uint64_t t0 = mach_absolute_time();
        this->recursiveLoadLibraries(context, preflightOnly, loaderRPaths);
        context.notifyBatch(dyld_image_state_dependents_mapped);
@@ -358,20 +387,29 @@ void ImageLoader::link(const LinkContext& context, bool forceLazysBound, bool pr
 
        uint64_t t4 = mach_absolute_time();
        this->weakBind(context);
 
        uint64_t t4 = mach_absolute_time();
        this->weakBind(context);
+       uint64_t t5 = mach_absolute_time();     
+
        context.notifyBatch(dyld_image_state_bound);
        context.notifyBatch(dyld_image_state_bound);
+       uint64_t t6 = mach_absolute_time();     
 
 
-       uint64_t t5 = mach_absolute_time();     
        std::vector<DOFInfo> dofs;
        this->recursiveGetDOFSections(context, dofs);
        context.registerDOFs(dofs);
        std::vector<DOFInfo> dofs;
        this->recursiveGetDOFSections(context, dofs);
        context.registerDOFs(dofs);
-       uint64_t t6 = mach_absolute_time();     
+       uint64_t t7 = mach_absolute_time();     
 
 
+       // interpose any dynamically loaded images
+       if ( !context.linkingMainExecutable && (fgInterposingTuples.size() != 0) ) {
+               this->recursiveApplyInterposing(context);
+       }
        
        
+       // clear error strings
+       (*context.setErrorStrings)(dyld_error_kind_none, NULL, NULL, NULL);
+
        fgTotalLoadLibrariesTime += t1 - t0;
        fgTotalRebaseTime += t3 - t2;
        fgTotalBindTime += t4 - t3;
        fgTotalWeakBindTime += t5 - t4;
        fgTotalLoadLibrariesTime += t1 - t0;
        fgTotalRebaseTime += t3 - t2;
        fgTotalBindTime += t4 - t3;
        fgTotalWeakBindTime += t5 - t4;
-       fgTotalDOF += t6 - t5;
+       fgTotalDOF += t7 - t6;
        
        // done with initial dylib loads
        fgNextPIEDylibAddress = 0;
        
        // done with initial dylib loads
        fgNextPIEDylibAddress = 0;
@@ -393,11 +431,11 @@ bool ImageLoader::decrementDlopenReferenceCount()
        return false;
 }
 
        return false;
 }
 
-void ImageLoader::runInitializers(const LinkContext& context)
+void ImageLoader::runInitializers(const LinkContext& context, InitializerTimingList& timingInfo)
 {
        uint64_t t1 = mach_absolute_time();
        mach_port_t this_thread = mach_thread_self();
 {
        uint64_t t1 = mach_absolute_time();
        mach_port_t this_thread = mach_thread_self();
-       this->recursiveInitialization(context, this_thread);
+       this->recursiveInitialization(context, this_thread, timingInfo);
        context.notifyBatch(dyld_image_state_initialized);
        mach_port_deallocate(mach_task_self(), this_thread);
        uint64_t t2 = mach_absolute_time();
        context.notifyBatch(dyld_image_state_initialized);
        mach_port_deallocate(mach_task_self(), this_thread);
        uint64_t t2 = mach_absolute_time();
@@ -486,7 +524,7 @@ void ImageLoader::recursiveLoadLibraries(const LinkContext& context, bool prefli
                        if ( preflightOnly && context.inSharedCache(requiredLibInfo.name) ) {
                                // <rdar://problem/5910137> dlopen_preflight() on image in shared cache leaves it loaded but not objc initialized
                                // in preflight mode, don't even load dylib that are in the shared cache because they will never be unloaded
                        if ( preflightOnly && context.inSharedCache(requiredLibInfo.name) ) {
                                // <rdar://problem/5910137> dlopen_preflight() on image in shared cache leaves it loaded but not objc initialized
                                // in preflight mode, don't even load dylib that are in the shared cache because they will never be unloaded
-                               setLibImage(i, NULL, false);
+                               setLibImage(i, NULL, false, false);
                                continue;
                        }
 #endif
                                continue;
                        }
 #endif
@@ -500,7 +538,8 @@ void ImageLoader::recursiveLoadLibraries(const LinkContext& context, bool prefli
                                }
                                if ( fNeverUnload )
                                        dependentLib->setNeverUnload();
                                }
                                if ( fNeverUnload )
                                        dependentLib->setNeverUnload();
-                               dependentLib->fStaticReferenceCount += 1;
+                               if ( ! requiredLibInfo.upward )
+                                       dependentLib->fStaticReferenceCount += 1;
                                LibraryInfo actualInfo = dependentLib->doGetLibraryInfo();
                                depLibReRequired = requiredLibInfo.required;
                                depLibCheckSumsMatch = ( actualInfo.checksum == requiredLibInfo.info.checksum );
                                LibraryInfo actualInfo = dependentLib->doGetLibraryInfo();
                                depLibReRequired = requiredLibInfo.required;
                                depLibCheckSumsMatch = ( actualInfo.checksum == requiredLibInfo.info.checksum );
@@ -511,13 +550,18 @@ void ImageLoader::recursiveLoadLibraries(const LinkContext& context, bool prefli
                                }
                                // check found library version is compatible
                                if ( actualInfo.minVersion < requiredLibInfo.info.minVersion ) {
                                }
                                // check found library version is compatible
                                if ( actualInfo.minVersion < requiredLibInfo.info.minVersion ) {
+                                       // record values for possible use by CrashReporter or Finder
                                        dyld::throwf("Incompatible library version: %s requires version %d.%d.%d or later, but %s provides version %d.%d.%d",
                                                        this->getShortName(), requiredLibInfo.info.minVersion >> 16, (requiredLibInfo.info.minVersion >> 8) & 0xff, requiredLibInfo.info.minVersion & 0xff,
                                                        dependentLib->getShortName(), actualInfo.minVersion >> 16, (actualInfo.minVersion >> 8) & 0xff, actualInfo.minVersion & 0xff);
                                }
                                        dyld::throwf("Incompatible library version: %s requires version %d.%d.%d or later, but %s provides version %d.%d.%d",
                                                        this->getShortName(), requiredLibInfo.info.minVersion >> 16, (requiredLibInfo.info.minVersion >> 8) & 0xff, requiredLibInfo.info.minVersion & 0xff,
                                                        dependentLib->getShortName(), actualInfo.minVersion >> 16, (actualInfo.minVersion >> 8) & 0xff, actualInfo.minVersion & 0xff);
                                }
-                               // prebinding for this image disabled if any dependent library changed or slid
-                               if ( !depLibCheckSumsMatch || (dependentLib->getSlide() != 0) )
+                               // prebinding for this image disabled if any dependent library changed
+                               if ( !depLibCheckSumsMatch ) 
+                                       canUsePrelinkingInfo = false;
+                               // prebinding for this image disabled unless both this and dependent are in the shared cache
+                               if ( !dependentLib->inSharedCache() || !this->inSharedCache() )
                                        canUsePrelinkingInfo = false;
                                        canUsePrelinkingInfo = false;
+                                       
                                //if ( context.verbosePrebinding ) {
                                //      if ( !requiredLib.checksumMatches )
                                //              fprintf(stderr, "dyld: checksum mismatch, (%u v %u) for %s referencing %s\n", 
                                //if ( context.verbosePrebinding ) {
                                //      if ( !requiredLib.checksumMatches )
                                //              fprintf(stderr, "dyld: checksum mismatch, (%u v %u) for %s referencing %s\n", 
@@ -531,13 +575,20 @@ void ImageLoader::recursiveLoadLibraries(const LinkContext& context, bool prefli
                                //      fprintf(stderr, "dyld: exception during processing for %s referencing %s\n", this->getPath(), dependentLib->getPath());         
                                if ( requiredLibInfo.required ) {
                                        fState = dyld_image_state_mapped;
                                //      fprintf(stderr, "dyld: exception during processing for %s referencing %s\n", this->getPath(), dependentLib->getPath());         
                                if ( requiredLibInfo.required ) {
                                        fState = dyld_image_state_mapped;
+                                       // record values for possible use by CrashReporter or Finder
+                                       if ( strstr(msg, "Incompatible") != NULL )
+                                               (*context.setErrorStrings)(dyld_error_kind_dylib_version, this->getPath(), requiredLibInfo.name, NULL);
+                                       else if ( strstr(msg, "architecture") != NULL )
+                                               (*context.setErrorStrings)(dyld_error_kind_dylib_wrong_arch, this->getPath(), requiredLibInfo.name, NULL);
+                                       else
+                                               (*context.setErrorStrings)(dyld_error_kind_dylib_missing, this->getPath(), requiredLibInfo.name, NULL);
                                        dyld::throwf("Library not loaded: %s\n  Referenced from: %s\n  Reason: %s", requiredLibInfo.name, this->getPath(), msg);
                                }
                                // ok if weak library not found
                                dependentLib = NULL;
                                canUsePrelinkingInfo = false;  // this disables all prebinding, we may want to just slam import vectors for this lib to zero
                        }
                                        dyld::throwf("Library not loaded: %s\n  Referenced from: %s\n  Reason: %s", requiredLibInfo.name, this->getPath(), msg);
                                }
                                // ok if weak library not found
                                dependentLib = NULL;
                                canUsePrelinkingInfo = false;  // this disables all prebinding, we may want to just slam import vectors for this lib to zero
                        }
-                       setLibImage(i, dependentLib, depLibReExported);
+                       setLibImage(i, dependentLib, depLibReExported, requiredLibInfo.upward);
                }
                fAllLibraryChecksumsAndLoadAddressesMatch = canUsePrelinkingInfo;
 
                }
                fAllLibraryChecksumsAndLoadAddressesMatch = canUsePrelinkingInfo;
 
@@ -592,11 +643,36 @@ void ImageLoader::recursiveRebase(const LinkContext& context)
                catch (const char* msg) {
                        // this image is not rebased
                        fState = dyld_image_state_dependents_mapped;
                catch (const char* msg) {
                        // this image is not rebased
                        fState = dyld_image_state_dependents_mapped;
+            CRSetCrashLogMessage2(NULL);
                        throw;
                }
        }
 }
 
                        throw;
                }
        }
 }
 
+void ImageLoader::recursiveApplyInterposing(const LinkContext& context)
+{ 
+       if ( ! fInterposed ) {
+               // break cycles
+               fInterposed = true;
+               
+               try {
+                       // interpose lower level libraries first
+                       for(unsigned int i=0; i < libraryCount(); ++i) {
+                               ImageLoader* dependentImage = libImage(i);
+                               if ( dependentImage != NULL )
+                                       dependentImage->recursiveApplyInterposing(context);
+                       }
+                               
+                       // interpose this image
+                       doInterpose(context);
+               }
+               catch (const char* msg) {
+                       // this image is not interposed
+                       fInterposed = false;
+                       throw;
+               }
+       }
+}
 
 
 
 
 
 
@@ -628,6 +704,7 @@ void ImageLoader::recursiveBind(const LinkContext& context, bool forceLazysBound
                catch (const char* msg) {
                        // restore state
                        fState = dyld_image_state_rebased;
                catch (const char* msg) {
                        // restore state
                        fState = dyld_image_state_rebased;
+            CRSetCrashLogMessage2(NULL);
                        throw;
                }
        }
                        throw;
                }
        }
@@ -644,15 +721,19 @@ void ImageLoader::weakBind(const LinkContext& context)
        // count how many have not already had weakbinding done
        int countNotYetWeakBound = 0;
        int countOfImagesWithWeakDefinitions = 0;
        // count how many have not already had weakbinding done
        int countNotYetWeakBound = 0;
        int countOfImagesWithWeakDefinitions = 0;
+       int countOfImagesWithWeakDefinitionsNotInSharedCache = 0;
        for(int i=0; i < count; ++i) {
                if ( ! imagesNeedingCoalescing[i]->fWeakSymbolsBound )
                        ++countNotYetWeakBound;
        for(int i=0; i < count; ++i) {
                if ( ! imagesNeedingCoalescing[i]->fWeakSymbolsBound )
                        ++countNotYetWeakBound;
-               if ( imagesNeedingCoalescing[i]->hasCoalescedExports() )
+               if ( imagesNeedingCoalescing[i]->hasCoalescedExports() ) {
                        ++countOfImagesWithWeakDefinitions;
                        ++countOfImagesWithWeakDefinitions;
+                       if ( ! imagesNeedingCoalescing[i]->inSharedCache() ) 
+                               ++countOfImagesWithWeakDefinitionsNotInSharedCache;
+               }
        }
 
        // don't need to do any coalescing if only one image has overrides, or all have already been done
        }
 
        // don't need to do any coalescing if only one image has overrides, or all have already been done
-       if ( (countOfImagesWithWeakDefinitions > 1) && (countNotYetWeakBound > 0) ) {
+       if ( (countOfImagesWithWeakDefinitionsNotInSharedCache > 0) && (countNotYetWeakBound > 0) ) {
                // make symbol iterators for each
                ImageLoader::CoalIterator iterators[count];
                ImageLoader::CoalIterator* sortedIts[count];
                // make symbol iterators for each
                ImageLoader::CoalIterator iterators[count];
                ImageLoader::CoalIterator* sortedIts[count];
@@ -781,7 +862,7 @@ void ImageLoader::recursiveSpinUnLock()
 }
 
 
 }
 
 
-void ImageLoader::recursiveInitialization(const LinkContext& context, mach_port_t this_thread)
+void ImageLoader::recursiveInitialization(const LinkContext& context, mach_port_t this_thread, InitializerTimingList& timingInfo)
 {
        recursive_lock lock_info(this_thread);
        recursiveSpinLock(lock_info);
 {
        recursive_lock lock_info(this_thread);
        recursiveSpinLock(lock_info);
@@ -796,8 +877,8 @@ void ImageLoader::recursiveInitialization(const LinkContext& context, mach_port_
                                ImageLoader* dependentImage = libImage(i);
                                if ( dependentImage != NULL )
                                // don't try to initialize stuff "above" me
                                ImageLoader* dependentImage = libImage(i);
                                if ( dependentImage != NULL )
                                // don't try to initialize stuff "above" me
-                               if ( (dependentImage != NULL) && (dependentImage->fDepth >= fDepth) )
-                                       dependentImage->recursiveInitialization(context, this_thread);
+                               if ( (dependentImage != NULL) && (dependentImage->fDepth >= fDepth) && !libIsUpward(i) )
+                                       dependentImage->recursiveInitialization(context, this_thread, timingInfo);
                        }
                        
                        // record termination order
                        }
                        
                        // record termination order
@@ -805,17 +886,25 @@ void ImageLoader::recursiveInitialization(const LinkContext& context, mach_port_
                                context.terminationRecorder(this);
                        
                        // let objc know we are about to initalize this image
                                context.terminationRecorder(this);
                        
                        // let objc know we are about to initalize this image
+                       uint64_t t1 = mach_absolute_time();
                        fState = dyld_image_state_dependents_initialized;
                        oldState = fState;
                        context.notifySingle(dyld_image_state_dependents_initialized, this);
                        fState = dyld_image_state_dependents_initialized;
                        oldState = fState;
                        context.notifySingle(dyld_image_state_dependents_initialized, this);
-
+                       
                        // initialize this image
                        // initialize this image
-                       this->doInitialization(context);
-
+                       bool hasInitializers = this->doInitialization(context);
+                       
                        // let anyone know we finished initalizing this image
                        fState = dyld_image_state_initialized;
                        oldState = fState;
                        context.notifySingle(dyld_image_state_initialized, this);
                        // let anyone know we finished initalizing this image
                        fState = dyld_image_state_initialized;
                        oldState = fState;
                        context.notifySingle(dyld_image_state_initialized, this);
+                       
+                       if ( hasInitializers ) {
+                               uint64_t t2 = mach_absolute_time();
+                               timingInfo.images[timingInfo.count].image = this;
+                               timingInfo.images[timingInfo.count].initTime = (t2-t1);
+                               timingInfo.count++;
+                       }
                }
                catch (const char* msg) {
                        // this image is not initialized
                }
                catch (const char* msg) {
                        // this image is not initialized
@@ -876,14 +965,21 @@ static char* commatize(uint64_t in, char* out)
 }
 
 
 }
 
 
-void ImageLoader::printStatistics(unsigned int imageCount)
+void ImageLoader::printStatistics(unsigned int imageCount, const InitializerTimingList& timingInfo)
 {
        uint64_t totalTime = fgTotalLoadLibrariesTime + fgTotalRebaseTime + fgTotalBindTime + fgTotalWeakBindTime + fgTotalDOF + fgTotalInitTime;
        char commaNum1[40];
        char commaNum2[40];
 
        printTime("total time", totalTime, totalTime);
 {
        uint64_t totalTime = fgTotalLoadLibrariesTime + fgTotalRebaseTime + fgTotalBindTime + fgTotalWeakBindTime + fgTotalDOF + fgTotalInitTime;
        char commaNum1[40];
        char commaNum2[40];
 
        printTime("total time", totalTime, totalTime);
-       dyld::log("total images loaded:  %d (%u from dyld shared cache, %u needed no fixups)\n", imageCount, fgImagesUsedFromSharedCache, fgImagesRequiringNoFixups);
+#if __IPHONE_OS_VERSION_MIN_REQUIRED   
+       if ( fgImagesUsedFromSharedCache != 0 )
+               dyld::log("total images loaded:  %d (%u from dyld shared cache)\n", imageCount, fgImagesUsedFromSharedCache);
+       else
+               dyld::log("total images loaded:  %d\n", imageCount);
+#else
+       dyld::log("total images loaded:  %d (%u from dyld shared cache)\n", imageCount, fgImagesUsedFromSharedCache);
+#endif
        dyld::log("total segments mapped: %u, into %llu pages with %llu pages pre-fetched\n", fgTotalSegmentsMapped, fgTotalBytesMapped/4096, fgTotalBytesPreFetched/4096);
        printTime("total images loading time", fgTotalLoadLibrariesTime, totalTime);
        printTime("total dtrace DOF registration time", fgTotalDOF, totalTime);
        dyld::log("total segments mapped: %u, into %llu pages with %llu pages pre-fetched\n", fgTotalSegmentsMapped, fgTotalBytesMapped/4096, fgTotalBytesPreFetched/4096);
        printTime("total images loading time", fgTotalLoadLibrariesTime, totalTime);
        printTime("total dtrace DOF registration time", fgTotalDOF, totalTime);
@@ -901,6 +997,11 @@ void ImageLoader::printStatistics(unsigned int imageCount)
        printTime("total weak binding fixups time", fgTotalWeakBindTime, totalTime);
        dyld::log("total bindings lazily fixed up: %s of %s\n", commatize(fgTotalLazyBindFixups, commaNum1), commatize(fgTotalPossibleLazyBindFixups, commaNum2));
        printTime("total initializer time", fgTotalInitTime, totalTime);
        printTime("total weak binding fixups time", fgTotalWeakBindTime, totalTime);
        dyld::log("total bindings lazily fixed up: %s of %s\n", commatize(fgTotalLazyBindFixups, commaNum1), commatize(fgTotalPossibleLazyBindFixups, commaNum2));
        printTime("total initializer time", fgTotalInitTime, totalTime);
+       for (uintptr_t i=0; i < timingInfo.count; ++i) {
+               dyld::log("%21s ", timingInfo.images[i].image->getShortName());
+               printTime("", timingInfo.images[i].initTime, totalTime);
+       }
+       
 }
 
 
 }
 
 
index 587a339d2b83612eb64b00d105ddcb0011b7a49b..582e60c0e1961f805130dd6e0a753e84caffc623 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2004-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <mach-o/nlist.h> 
 #include <stdint.h>
 #include <vector>
 #include <mach-o/nlist.h> 
 #include <stdint.h>
 #include <vector>
-#include <set>
 #include <new>
 
 #include <new>
 
+#if (__i386__ || __x86_64__)
+       #include <CrashReporterClient.h>
+#else
+       // work around until iOS has CrashReporterClient.h
+       #define CRSetCrashLogMessage(x)
+       #define CRSetCrashLogMessage2(x)
+#endif
+
+#define LOG_BINDINGS 0
+
 #include "mach-o/dyld_images.h"
 #include "mach-o/dyld_priv.h"
 
 #include "mach-o/dyld_images.h"
 #include "mach-o/dyld_priv.h"
 
        #define SHARED_REGION_SIZE SHARED_REGION_SIZE_ARM
 #endif
 
        #define SHARED_REGION_SIZE SHARED_REGION_SIZE_ARM
 #endif
 
+#ifndef EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
+       #define EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER 0x10
+#endif
+#ifndef EXPORT_SYMBOL_FLAGS_REEXPORT
+       #define EXPORT_SYMBOL_FLAGS_REEXPORT 0x08
+#endif
 
 
 #define SPLIT_SEG_SHARED_REGION_SUPPORT __arm__
 #define SPLIT_SEG_DYLIB_SUPPORT (__ppc__ || __i386__ || __arm__)
 #define PREBOUND_IMAGE_SUPPORT (__ppc__ || __i386__ || __arm__)
 
 
 #define SPLIT_SEG_SHARED_REGION_SUPPORT __arm__
 #define SPLIT_SEG_DYLIB_SUPPORT (__ppc__ || __i386__ || __arm__)
 #define PREBOUND_IMAGE_SUPPORT (__ppc__ || __i386__ || __arm__)
-#define TEXT_RELOC_SUPPORT (__ppc__ || __i386__)
-#define DYLD_SHARED_CACHE_SUPPORT (__ppc__ || __i386__ || __ppc64__ || __x86_64__)
+#define TEXT_RELOC_SUPPORT (__ppc__ || __i386__ || __arm__)
+#define DYLD_SHARED_CACHE_SUPPORT (__ppc__ || __i386__ || __ppc64__ || __x86_64__ || __arm__)
 #define SUPPORT_OLD_CRT_INITIALIZATION (__ppc__ || __i386__)
 #define SUPPORT_OLD_CRT_INITIALIZATION (__ppc__ || __i386__)
-#define COMPRESSED_DYLD_INFO_SUPPORT (__i386__ || __x86_64__)
-#define CORESYMBOLICATION_SUPPORT   (__i386__ || __x86_64__)
+#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
+#else
+       #define CORESYMBOLICATION_SUPPORT   (__i386__ || __x86_64__)
+#endif
 #if __arm__
        #define INITIAL_IMAGE_COUNT 100
 #else
 #if __arm__
        #define INITIAL_IMAGE_COUNT 100
 #else
@@ -82,6 +102,9 @@ namespace dyld {
        extern void log(const char* format, ...)  __attribute__((format(printf, 1, 2)));
        extern void warn(const char* format, ...)  __attribute__((format(printf, 1, 2)));
        extern const char* mkstringf(const char* format, ...)  __attribute__((format(printf, 1, 2)));
        extern void log(const char* format, ...)  __attribute__((format(printf, 1, 2)));
        extern void warn(const char* format, ...)  __attribute__((format(printf, 1, 2)));
        extern const char* mkstringf(const char* format, ...)  __attribute__((format(printf, 1, 2)));
+#if LOG_BINDINGS
+       extern void logBindings(const char* format, ...)  __attribute__((format(printf, 1, 2)));
+#endif
 };
 
 
 };
 
 
@@ -167,6 +190,8 @@ public:
                unsigned int    (*imageCount)();
                void                    (*setNewProgramVars)(const ProgramVars&);
                bool                    (*inSharedCache)(const char* path);
                unsigned int    (*imageCount)();
                void                    (*setNewProgramVars)(const ProgramVars&);
                bool                    (*inSharedCache)(const char* path);
+               void                    (*setErrorStrings)(unsigned errorCode, const char* errorClientOfDylibPath,
+                                                                               const char* errorTargetDylibPath, const char* errorSymbol);
 #if SUPPORT_OLD_CRT_INITIALIZATION
                void                    (*setRunInitialzersOldWay)();
 #endif
 #if SUPPORT_OLD_CRT_INITIALIZATION
                void                    (*setRunInitialzersOldWay)();
 #endif
@@ -188,7 +213,6 @@ public:
                bool                    bindFlat;
                bool                    linkingMainExecutable;
                bool                    startedInitializingMainExecutable;
                bool                    bindFlat;
                bool                    linkingMainExecutable;
                bool                    startedInitializingMainExecutable;
-               bool                    noPIE;
                bool                    processIsRestricted;
                bool                    verboseOpts;
                bool                    verboseEnv;
                bool                    processIsRestricted;
                bool                    verboseOpts;
                bool                    verboseEnv;
@@ -199,7 +223,10 @@ public:
                bool                    verboseInit;
                bool                    verboseDOF;
                bool                    verbosePrebinding;
                bool                    verboseInit;
                bool                    verboseDOF;
                bool                    verbosePrebinding;
+               bool                    verboseCoreSymbolication;
                bool                    verboseWarnings;
                bool                    verboseWarnings;
+               bool                    verboseRPaths;
+               bool                    verboseInterposing;
        };
        
        struct CoalIterator
        };
        
        struct CoalIterator
@@ -223,6 +250,14 @@ public:
        virtual uintptr_t               getAddressCoalIterator(CoalIterator&, const LinkContext& context) = 0;
        virtual void                    updateUsesCoalIterator(CoalIterator&, uintptr_t newAddr, ImageLoader* target, const LinkContext& context) = 0;
        
        virtual uintptr_t               getAddressCoalIterator(CoalIterator&, const LinkContext& context) = 0;
        virtual void                    updateUsesCoalIterator(CoalIterator&, uintptr_t newAddr, ImageLoader* target, const LinkContext& context) = 0;
        
+       struct InitializerTimingList
+       {
+               uintptr_t       count;
+               struct {
+                       ImageLoader*    image;
+                       uint64_t                initTime;
+               }                       images[1];
+       };
        
        
                                                                                // constructor is protected, but anyone can delete an image
        
        
                                                                                // constructor is protected, but anyone can delete an image
@@ -234,7 +269,7 @@ public:
        
                                                                                // runInitializers() is normally called in link() but the main executable must 
                                                                                // run crt code before initializers
        
                                                                                // runInitializers() is normally called in link() but the main executable must 
                                                                                // run crt code before initializers
-       void                                                            runInitializers(const LinkContext& context);
+       void                                                            runInitializers(const LinkContext& context, InitializerTimingList& timingInfo);
        
                                                                                // called after link() forces all lazy pointers to be bound
        void                                                            bindAllLazyPointers(const LinkContext& context, bool recursive);
        
                                                                                // called after link() forces all lazy pointers to be bound
        void                                                            bindAllLazyPointers(const LinkContext& context, bool recursive);
@@ -272,6 +307,9 @@ public:
                                                                                // even if image is deleted, leave segments mapped in
        bool                                                            leaveMapped() { return fLeaveMapped; }
 
                                                                                // even if image is deleted, leave segments mapped in
        bool                                                            leaveMapped() { return fLeaveMapped; }
 
+                                                                               // image resides in dyld shared cache
+       virtual bool                                            inSharedCache() const = 0;
+
                                                                                // checks if the specifed address is within one of this image's segments
        virtual bool                                            containsAddress(const void* addr) const;
 
                                                                                // checks if the specifed address is within one of this image's segments
        virtual bool                                            containsAddress(const void* addr) const;
 
@@ -306,7 +344,8 @@ public:
        virtual const Symbol*                           findExportedSymbol(const char* name, bool searchReExports, const ImageLoader** foundIn) const = 0;
        
                                                                                // gets address of implementation (code) of the specified exported symbol
        virtual const Symbol*                           findExportedSymbol(const char* name, bool searchReExports, const ImageLoader** foundIn) const = 0;
        
                                                                                // gets address of implementation (code) of the specified exported symbol
-       virtual uintptr_t                                       getExportedSymbolAddress(const Symbol* sym, const LinkContext& context, const ImageLoader* requestor=NULL) const = 0;
+       virtual uintptr_t                                       getExportedSymbolAddress(const Symbol* sym, const LinkContext& context, 
+                                                                                                       const ImageLoader* requestor=NULL, bool runResolver=false) const = 0;
        
                                                                                // gets attributes of the specified exported symbol
        virtual DefinitionFlags                         getExportedSymbolInfo(const Symbol* sym) const = 0;
        
                                                                                // gets attributes of the specified exported symbol
        virtual DefinitionFlags                         getExportedSymbolInfo(const Symbol* sym) const = 0;
@@ -362,7 +401,8 @@ public:
        virtual uintptr_t                                       doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context) = 0;
        
                                                                                // called at runtime when a fast lazily bound function is first called
        virtual uintptr_t                                       doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context) = 0;
        
                                                                                // called at runtime when a fast lazily bound function is first called
-       virtual uintptr_t                                       doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context) = 0;
+       virtual uintptr_t                                       doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context,
+                                                                                                                       void (*lock)(), void (*unlock)()) = 0;
 
                                                                                // calls termination routines (e.g. C++ static destructors for image)
        virtual void                                            doTermination(const LinkContext& context) = 0;
 
                                                                                // calls termination routines (e.g. C++ static destructors for image)
        virtual void                                            doTermination(const LinkContext& context) = 0;
@@ -414,6 +454,13 @@ public:
        virtual uintptr_t                                       segActualEndAddress(unsigned int) const = 0;
 
        
        virtual uintptr_t                                       segActualEndAddress(unsigned int) 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                                                            applyInterposing(const LinkContext& context);
 
        dyld_image_states                                       getState() { return (dyld_image_states)fState; }
        
 
        dyld_image_states                                       getState() { return (dyld_image_states)fState; }
        
@@ -433,7 +480,7 @@ public:
        void                                                            setNeverUnload() { fNeverUnload = true; fLeaveMapped = true; }
 
                                                                                // triggered by DYLD_PRINT_STATISTICS to write info on work done and how fast
        void                                                            setNeverUnload() { fNeverUnload = true; fLeaveMapped = true; }
 
                                                                                // triggered by DYLD_PRINT_STATISTICS to write info on work done and how fast
-       static void                                                     printStatistics(unsigned int imageCount);
+       static void                                                     printStatistics(unsigned int imageCount, const InitializerTimingList& timingInfo);
                                
                                                                                // used with DYLD_IMAGE_SUFFIX
        static void                                                     addSuffix(const char* path, const char* suffix, char* result);
                                
                                                                                // used with DYLD_IMAGE_SUFFIX
        static void                                                     addSuffix(const char* path, const char* suffix, char* result);
@@ -481,9 +528,16 @@ protected:
                LibraryInfo                     info;
                bool                            required;
                bool                            reExported;
                LibraryInfo                     info;
                bool                            required;
                bool                            reExported;
+               bool                            upward;
        };
 
 
        };
 
 
+       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);
        
        typedef void (*Initializer)(int argc, const char* argv[], const char* envp[], const char* apple[], const ProgramVars* vars);
        typedef void (*Terminator)(void);
        
@@ -492,7 +546,8 @@ protected:
        unsigned int                    libraryCount() const { return fLibraryCount; }
        virtual ImageLoader*    libImage(unsigned int) const = 0;
        virtual bool                    libReExported(unsigned int) const = 0;
        unsigned int                    libraryCount() const { return fLibraryCount; }
        virtual ImageLoader*    libImage(unsigned int) const = 0;
        virtual bool                    libReExported(unsigned int) const = 0;
-       virtual void                    setLibImage(unsigned int, ImageLoader*, bool) = 0;
+       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.
 
 
                                                // To link() an image, its dependent libraries are loaded, it is rebased, bound, and initialized.
@@ -504,8 +559,9 @@ protected:
        void                            recursiveRebase(const LinkContext& context);
        void                            recursiveBind(const LinkContext& context, bool forceLazysBound);
        void                            weakBind(const LinkContext& context);
        void                            recursiveRebase(const LinkContext& context);
        void                            recursiveBind(const LinkContext& context, bool forceLazysBound);
        void                            weakBind(const LinkContext& context);
+       void                            recursiveApplyInterposing(const LinkContext& context);
        void                            recursiveGetDOFSections(const LinkContext& context, std::vector<DOFInfo>& dofs);
        void                            recursiveGetDOFSections(const LinkContext& context, std::vector<DOFInfo>& dofs);
-       void                            recursiveInitialization(const LinkContext& context, mach_port_t this_thread);
+       void                            recursiveInitialization(const LinkContext& context, mach_port_t this_thread, ImageLoader::InitializerTimingList&);
 
                                                                // fill in information about dependent libraries (array length is fLibraryCount)
        virtual void                            doGetDependentLibraries(DependentLibraryInfo libs[]) = 0;
 
                                                                // fill in information about dependent libraries (array length is fLibraryCount)
        virtual void                            doGetDependentLibraries(DependentLibraryInfo libs[]) = 0;
@@ -525,8 +581,11 @@ protected:
                                                                // if image has any dtrace DOF sections, append them to list to be registered
        virtual void                            doGetDOFSections(const LinkContext& context, std::vector<DOFInfo>& dofs) = 0;
        
                                                                // if image has any dtrace DOF sections, append them to list to be registered
        virtual void                            doGetDOFSections(const LinkContext& context, std::vector<DOFInfo>& dofs) = 0;
        
+                                                               // do interpose
+       virtual void                            doInterpose(const LinkContext& context) = 0;
+
                                                                // run any initialization routines in this image
                                                                // run any initialization routines in this image
-       virtual void                            doInitialization(const LinkContext& context) = 0;
+       virtual bool                            doInitialization(const LinkContext& context) = 0;
        
                                                                // return if this image has termination routines
        virtual bool                            needsTermination() = 0;
        
                                                                // return if this image has termination routines
        virtual bool                            needsTermination() = 0;
@@ -560,7 +619,6 @@ protected:
        static uintptr_t                        fgNextPIEDylibAddress;
        static uint32_t                         fgImagesWithUsedPrebinding;
        static uint32_t                         fgImagesUsedFromSharedCache;
        static uintptr_t                        fgNextPIEDylibAddress;
        static uint32_t                         fgImagesWithUsedPrebinding;
        static uint32_t                         fgImagesUsedFromSharedCache;
-       static uint32_t                         fgImagesRequiringNoFixups;
        static uint32_t                         fgImagesHasWeakDefinitions;
        static uint32_t                         fgImagesRequiringCoalescing;
        static uint32_t                         fgTotalRebaseFixups;
        static uint32_t                         fgImagesHasWeakDefinitions;
        static uint32_t                         fgImagesRequiringCoalescing;
        static uint32_t                         fgTotalRebaseFixups;
@@ -578,6 +636,7 @@ protected:
        static uint64_t                         fgTotalWeakBindTime;
        static uint64_t                         fgTotalDOF;
        static uint64_t                         fgTotalInitTime;
        static uint64_t                         fgTotalWeakBindTime;
        static uint64_t                         fgTotalDOF;
        static uint64_t                         fgTotalInitTime;
+       static std::vector<InterposeTuple>      fgInterposingTuples;
        const char*                                     fPath;
        dev_t                                           fDevice;
        ino_t                                           fInode;
        const char*                                     fPath;
        dev_t                                           fDevice;
        ino_t                                           fInode;
@@ -586,7 +645,7 @@ protected:
        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
        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::set<const ImageLoader*>* fDynamicReferences;       // list of all images this image used because of a flat/coalesced lookup
+       std::vector<const ImageLoader*>* fDynamicReferences;    // list of all images this image used because of a flat/coalesced lookup
 
 private:
        struct recursive_lock {
 
 private:
        struct recursive_lock {
@@ -612,6 +671,7 @@ private:
                                                                fNeverUnload : 1,               // image was statically loaded by main executable
                                                                fHideSymbols : 1,               // ignore this image's exported symbols when linking other images
                                                                fMatchByInstallName : 1,// look at image's install-path not its load path
                                                                fNeverUnload : 1,               // image was statically loaded by main executable
                                                                fHideSymbols : 1,               // ignore this image's exported symbols when linking other images
                                                                fMatchByInstallName : 1,// look at image's install-path not its load path
+                                                               fInterposed : 1,
                                                                fRegisteredDOF : 1,
                                                                fAllLazyPointersBound : 1,
                                                                fBeingRemoved : 1,
                                                                fRegisteredDOF : 1,
                                                                fAllLazyPointersBound : 1,
                                                                fBeingRemoved : 1,
index 094d56d2ae2cfc68260ad8ca42af893ccb221d25..b068b7a03779efb0bfba4f7c656c5076d002f071 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2004-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -27,7 +27,7 @@
 #define __eip  eip 
 #define __rip  rip 
 
 #define __eip  eip 
 #define __rip  rip 
 
-
+#define __STDC_LIMIT_MACROS
 #include <string.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <string.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <sys/sysctl.h>
 #include <libkern/OSAtomic.h>
 #include <libkern/OSCacheControl.h>
 #include <sys/sysctl.h>
 #include <libkern/OSAtomic.h>
 #include <libkern/OSCacheControl.h>
+#include <stdint.h>
 
 #include "ImageLoaderMachO.h"
 #include "ImageLoaderMachOCompressed.h"
 #include "ImageLoaderMachOClassic.h"
 #include "mach-o/dyld_images.h"
 
 
 #include "ImageLoaderMachO.h"
 #include "ImageLoaderMachOCompressed.h"
 #include "ImageLoaderMachOClassic.h"
 #include "mach-o/dyld_images.h"
 
+// <rdar://problem/8718137> use stack guard random value to add padding between dylibs
+extern "C" long __stack_chk_guard;
 
 
+#ifndef LC_LOAD_UPWARD_DYLIB
+       #define LC_LOAD_UPWARD_DYLIB (0x23|LC_REQ_DYLD) /* load of dylib whose initializers run later */
+#endif
 
 // relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables
 #if __LP64__
 
 // relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables
 #if __LP64__
@@ -82,7 +88,7 @@ ImageLoaderMachO::ImageLoaderMachO(const macho_header* mh, const char* path, uns
        fReadOnlyImportSegment(false),
 #endif
        fHasSubLibraries(false), fHasSubUmbrella(false), fInUmbrella(false), fHasDOFSections(false), fHasDashInit(false),
        fReadOnlyImportSegment(false),
 #endif
        fHasSubLibraries(false), fHasSubUmbrella(false), fInUmbrella(false), fHasDOFSections(false), fHasDashInit(false),
-       fHasInitializers(false), fHasTerminators(false)
+       fHasInitializers(false), fHasTerminators(false), fGoodFirstSegment(false), fRegisteredAsRequiresCoalescing(false)
 {
        fIsSplitSeg = ((mh->flags & MH_SPLIT_SEGS) != 0);        
 
 {
        fIsSplitSeg = ((mh->flags & MH_SPLIT_SEGS) != 0);        
 
@@ -108,11 +114,13 @@ 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, 
 
 // 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 linkedit_data_command** codeSigCmd)
 {
        *compressed = false;
        *segCount = 0;
        *libCount = 0;
 {
        *compressed = false;
        *segCount = 0;
        *libCount = 0;
+       *codeSigCmd = NULL;
        const uint32_t cmd_count = mh->ncmds;
        const struct load_command* const cmds    = (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);
        const uint32_t cmd_count = mh->ncmds;
        const struct load_command* const cmds    = (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);
@@ -131,8 +139,12 @@ void ImageLoaderMachO::sniffLoadCommands(const macho_header* mh, const char* pat
                        case LC_LOAD_DYLIB:
                        case LC_LOAD_WEAK_DYLIB:
                        case LC_REEXPORT_DYLIB:
                        case LC_LOAD_DYLIB:
                        case LC_LOAD_WEAK_DYLIB:
                        case LC_REEXPORT_DYLIB:
+                       case LC_LOAD_UPWARD_DYLIB:
                                *libCount += 1;
                                break;
                                *libCount += 1;
                                break;
+                       case LC_CODE_SIGNATURE:
+                               *codeSigCmd = (struct linkedit_data_command*)cmd; // only support one LC_CODE_SIGNATURE per image
+                               break;
                }
                uint32_t cmdLength = cmd->cmdsize;
                cmd = (const struct load_command*)(((char*)cmd)+cmdLength);
                }
                uint32_t cmdLength = cmd->cmdsize;
                cmd = (const struct load_command*)(((char*)cmd)+cmdLength);
@@ -163,7 +175,8 @@ ImageLoader* ImageLoaderMachO::instantiateMainExecutable(const macho_header* mh,
        bool compressed;
        unsigned int segCount;
        unsigned int libCount;
        bool compressed;
        unsigned int segCount;
        unsigned int libCount;
-       sniffLoadCommands(mh, path, &compressed, &segCount, &libCount);
+       const linkedit_data_command* codeSigCmd;
+       sniffLoadCommands(mh, path, &compressed, &segCount, &libCount, &codeSigCmd);
        // instantiate concrete class based on content of load commands
        if ( compressed ) 
                return ImageLoaderMachOCompressed::instantiateMainExecutable(mh, slide, path, segCount, libCount, context);
        // instantiate concrete class based on content of load commands
        if ( compressed ) 
                return ImageLoaderMachOCompressed::instantiateMainExecutable(mh, slide, path, segCount, libCount, context);
@@ -190,27 +203,29 @@ ImageLoader* ImageLoaderMachO::instantiateFromFile(const char* path, int fd, con
        bool compressed;
        unsigned int segCount;
        unsigned int libCount;
        bool compressed;
        unsigned int segCount;
        unsigned int libCount;
-       sniffLoadCommands((const macho_header*)fileData, path, &compressed, &segCount, &libCount);
+       const linkedit_data_command* codeSigCmd;
+       sniffLoadCommands((const macho_header*)fileData, path, &compressed, &segCount, &libCount, &codeSigCmd);
        // instantiate concrete class based on content of load commands
        if ( compressed ) 
        // instantiate concrete class based on content of load commands
        if ( compressed ) 
-               return ImageLoaderMachOCompressed::instantiateFromFile(path, fd, fileData, offsetInFat, lenInFat, info, segCount, libCount, context);
+               return ImageLoaderMachOCompressed::instantiateFromFile(path, fd, fileData, offsetInFat, lenInFat, info, segCount, libCount, codeSigCmd, context);
        else
        else
-               return ImageLoaderMachOClassic::instantiateFromFile(path, fd, fileData, offsetInFat, lenInFat, info, segCount, libCount, context);
+               return ImageLoaderMachOClassic::instantiateFromFile(path, fd, fileData, offsetInFat, lenInFat, info, segCount, libCount, codeSigCmd, context);
 }
 
 // create image by using cached mach-o file
 }
 
 // create image by using cached mach-o file
-ImageLoader* ImageLoaderMachO::instantiateFromCache(const macho_header* mh, const char* path, const struct stat& info, const LinkContext& context)
+ImageLoader* ImageLoaderMachO::instantiateFromCache(const macho_header* mh, const char* path, long slide, const struct stat& info, const LinkContext& context)
 {
        // instantiate right concrete class
        bool compressed;
        unsigned int segCount;
        unsigned int libCount;
 {
        // instantiate right concrete class
        bool compressed;
        unsigned int segCount;
        unsigned int libCount;
-       sniffLoadCommands(mh, path, &compressed, &segCount, &libCount);
+       const linkedit_data_command* codeSigCmd;
+       sniffLoadCommands(mh, path, &compressed, &segCount, &libCount, &codeSigCmd);
        // instantiate concrete class based on content of load commands
        if ( compressed ) 
        // instantiate concrete class based on content of load commands
        if ( compressed ) 
-               return ImageLoaderMachOCompressed::instantiateFromCache(mh, path, info, segCount, libCount, context);
+               return ImageLoaderMachOCompressed::instantiateFromCache(mh, path, slide, info, segCount, libCount, context);
        else
        else
-               return ImageLoaderMachOClassic::instantiateFromCache(mh, path, info, segCount, libCount, context);
+               return ImageLoaderMachOClassic::instantiateFromCache(mh, path, slide, info, segCount, libCount, context);
 }
 
 // create image by copying an in-memory mach-o file
 }
 
 // create image by copying an in-memory mach-o file
@@ -219,7 +234,8 @@ ImageLoader* ImageLoaderMachO::instantiateFromMemory(const char* moduleName, con
        bool compressed;
        unsigned int segCount;
        unsigned int libCount;
        bool compressed;
        unsigned int segCount;
        unsigned int libCount;
-       sniffLoadCommands(mh, moduleName, &compressed, &segCount, &libCount);
+       const linkedit_data_command* sigcmd;
+       sniffLoadCommands(mh, moduleName, &compressed, &segCount, &libCount, &sigcmd);
        // instantiate concrete class based on content of load commands
        if ( compressed ) 
                return ImageLoaderMachOCompressed::instantiateFromMemory(moduleName, mh, len, segCount, libCount, context);
        // instantiate concrete class based on content of load commands
        if ( compressed ) 
                return ImageLoaderMachOCompressed::instantiateFromMemory(moduleName, mh, len, segCount, libCount, context);
@@ -239,7 +255,7 @@ void ImageLoaderMachO::parseLoadCmds()
 #if TEXT_RELOC_SUPPORT
                // __TEXT segment always starts at beginning of file and contains mach_header and load commands
                if ( strcmp(segName(i),"__TEXT") == 0 ) {
 #if TEXT_RELOC_SUPPORT
                // __TEXT segment always starts at beginning of file and contains mach_header and load commands
                if ( strcmp(segName(i),"__TEXT") == 0 ) {
-                       if ( segHasRebaseFixUps(i) )
+                       if ( segHasRebaseFixUps(i) && (fSlide != 0) )
                                fTextSegmentRebases = true;
                        if ( segHasBindFixUps(i) )
                                fTextSegmentBinds = true;
                                fTextSegmentRebases = true;
                        if ( segHasBindFixUps(i) )
                                fTextSegmentBinds = true;
@@ -258,6 +274,7 @@ void ImageLoaderMachO::parseLoadCmds()
        // keep count of prebound images with weak exports
        if ( this->participatesInCoalescing() ) {
                ++fgImagesRequiringCoalescing;
        // keep count of prebound images with weak exports
        if ( this->participatesInCoalescing() ) {
                ++fgImagesRequiringCoalescing;
+               fRegisteredAsRequiresCoalescing = true;
                if ( this->hasCoalescedExports() ) 
                        ++fgImagesHasWeakDefinitions;
        }
                if ( this->hasCoalescedExports() ) 
                        ++fgImagesHasWeakDefinitions;
        }
@@ -334,6 +351,7 @@ void ImageLoaderMachO::parseLoadCmds()
                        case LC_RPATH:
                        case LC_LOAD_WEAK_DYLIB:
                    case LC_REEXPORT_DYLIB:
                        case LC_RPATH:
                        case LC_LOAD_WEAK_DYLIB:
                    case LC_REEXPORT_DYLIB:
+                       case LC_LOAD_UPWARD_DYLIB:
                                // do nothing, just prevent LC_REQ_DYLD exception from occuring
                                break;
                        default:
                                // do nothing, just prevent LC_REQ_DYLD exception from occuring
                                break;
                        default:
@@ -354,8 +372,8 @@ void ImageLoaderMachO::parseLoadCmds()
 // for UnmapSegments() to work
 void ImageLoaderMachO::destroy()
 {
 // for UnmapSegments() to work
 void ImageLoaderMachO::destroy()
 {
-       // keep count of images with weak exports
-       if ( this->participatesInCoalescing() ) {
+       // update count of images with weak exports
+       if ( fRegisteredAsRequiresCoalescing ) {
                --fgImagesRequiringCoalescing;
                if ( this->hasCoalescedExports() ) 
                        --fgImagesHasWeakDefinitions;
                --fgImagesRequiringCoalescing;
                if ( this->hasCoalescedExports() ) 
                        --fgImagesHasWeakDefinitions;
@@ -629,36 +647,16 @@ void ImageLoaderMachO::setSlide(intptr_t slide)
 }
 
 #if CODESIGNING_SUPPORT
 }
 
 #if CODESIGNING_SUPPORT
-void ImageLoaderMachO::loadCodeSignature(const uint8_t* fileData, int fd,  uint64_t offsetInFatFile)
+void ImageLoaderMachO::loadCodeSignature(const struct linkedit_data_command* codeSigCmd, int fd,  uint64_t offsetInFatFile)
 {
 {
-       // look for code signature load command
-       // do this in the read() memory buffer - not in the mapped __TEXT segment
-       const uint32_t cmd_count = ((macho_header*)fileData)->ncmds;
-       const struct load_command* const cmds = (struct load_command*)&fileData[sizeof(macho_header)];
-       const struct load_command* cmd = cmds;
-       for (uint32_t i = 0; i < cmd_count; ++i) {
-               if ( cmd->cmd == LC_CODE_SIGNATURE ) {
-                       const struct linkedit_data_command *sigcmd = (struct linkedit_data_command*) cmd;
-                       // fLinkEditBase is not set up yet, so compute it
-                       const uint8_t* linkEditBase = NULL;
-                       for(unsigned int i=0; i < fSegmentsCount; ++i) {
-                               // set up pointer to __LINKEDIT segment
-                               if ( strcmp(segName(i),"__LINKEDIT") == 0 ) {
-                                       linkEditBase = (uint8_t*)(segActualLoadAddress(i) - segFileOffset(i));
-                                       break;
-                               }
-                       }
-                       fsignatures_t siginfo;
-                       siginfo.fs_file_start=offsetInFatFile;                          // CD coverage offset 
-                       siginfo.fs_blob_start=(void*)(linkEditBase+sigcmd->dataoff);    // start of CD in file
-                       siginfo.fs_blob_size=sigcmd->datasize;                  // size of CD
-                       int result = fcntl(fd, F_ADDSIGS, &siginfo);
-                       if ( result == -1 ) 
-                               dyld::log("dyld: code signature failed for %s with errno=%d\n", this->getPath(), errno);
-                       break; // only support one LC_CODE_SIGNATURE
-               }
-               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
-       }
+       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());
 }
 #endif
 
 }
 #endif
 
@@ -672,6 +670,52 @@ const char* ImageLoaderMachO::getInstallPath() const
        return NULL;
 }
 
        return NULL;
 }
 
+void ImageLoaderMachO::registerInterposing()
+{
+       // mach-o files advertise interposing by having a __DATA __interpose section
+       uintptr_t textStart = this->segActualLoadAddress(0);
+       uintptr_t textEnd = this->segActualEndAddress(0);
+       // <rdar://problem/8268602> verify that the first segment load command is for a read-only segment
+       if ( ! fGoodFirstSegment )
+               return;
+       struct InterposeData { uintptr_t replacement; uintptr_t replacee; };
+       const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
+       const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
+       const struct load_command* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               switch (cmd->cmd) {
+                       case LC_SEGMENT_COMMAND:
+                               {
+                                       const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
+                                       const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
+                                       const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
+                                       for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+                                               if ( ((sect->flags & SECTION_TYPE) == S_INTERPOSING) || ((strcmp(sect->sectname, "__interpose") == 0) && (strcmp(seg->segname, "__DATA") == 0)) ) {
+                                                       const InterposeData* interposeArray = (InterposeData*)(sect->addr + fSlide);
+                                                       const unsigned int count = sect->size / sizeof(InterposeData);
+                                                       for (uint32_t i=0; i < count; ++i) {
+                                                               ImageLoader::InterposeTuple tuple;
+                                                               tuple.replacement               = interposeArray[i].replacement;
+                                                               tuple.replacementImage  = this;
+                                                               tuple.replacee                  = interposeArray[i].replacee;
+                                                               // <rdar://problem/7937695> verify that replacement is in this image
+                                                               if ( (tuple.replacement >= textStart) && (tuple.replacement < textEnd) ) {
+                                                                       for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
+                                                                               if ( it->replacee == tuple.replacee ) {
+                                                                                       tuple.replacee = it->replacement;
+                                                                               }
+                                                                       }
+                                                                       ImageLoader::fgInterposingTuples.push_back(tuple);
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                               break;
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+       }
+}
 
 
 void* ImageLoaderMachO::getMain() const
 
 
 void* ImageLoaderMachO::getMain() const
@@ -728,6 +772,7 @@ bool ImageLoaderMachO::needsAddedLibSystemDepency(unsigned int libCount, const m
                        case LC_LOAD_DYLIB:
                        case LC_LOAD_WEAK_DYLIB:
                        case LC_REEXPORT_DYLIB:
                        case LC_LOAD_DYLIB:
                        case LC_LOAD_WEAK_DYLIB:
                        case LC_REEXPORT_DYLIB:
+                       case LC_LOAD_UPWARD_DYLIB:
                                return false;
                        case LC_ID_DYLIB:
                                {
                                return false;
                        case LC_ID_DYLIB:
                                {
@@ -756,6 +801,7 @@ void ImageLoaderMachO::doGetDependentLibraries(DependentLibraryInfo libs[])
                lib->info.maxVersion = 0;
                lib->required = false;
                lib->reExported = false;
                lib->info.maxVersion = 0;
                lib->required = false;
                lib->reExported = false;
+               lib->upward = false;
        }
        else {
                uint32_t index = 0;
        }
        else {
                uint32_t index = 0;
@@ -767,6 +813,7 @@ void ImageLoaderMachO::doGetDependentLibraries(DependentLibraryInfo libs[])
                                case LC_LOAD_DYLIB:
                                case LC_LOAD_WEAK_DYLIB:
                                case LC_REEXPORT_DYLIB:
                                case LC_LOAD_DYLIB:
                                case LC_LOAD_WEAK_DYLIB:
                                case LC_REEXPORT_DYLIB:
+                               case LC_LOAD_UPWARD_DYLIB:
                                {
                                        const struct dylib_command* dylib = (struct dylib_command*)cmd;
                                        DependentLibraryInfo* lib = &libs[index++];
                                {
                                        const struct dylib_command* dylib = (struct dylib_command*)cmd;
                                        DependentLibraryInfo* lib = &libs[index++];
@@ -777,6 +824,7 @@ void ImageLoaderMachO::doGetDependentLibraries(DependentLibraryInfo libs[])
                                        lib->info.maxVersion = dylib->dylib.current_version;
                                        lib->required = (cmd->cmd != LC_LOAD_WEAK_DYLIB);
                                        lib->reExported = (cmd->cmd == LC_REEXPORT_DYLIB);
                                        lib->info.maxVersion = dylib->dylib.current_version;
                                        lib->required = (cmd->cmd != LC_LOAD_WEAK_DYLIB);
                                        lib->reExported = (cmd->cmd == LC_REEXPORT_DYLIB);
+                                       lib->upward = (cmd->cmd == LC_LOAD_UPWARD_DYLIB);
                                }
                                break;
                        }
                                }
                                break;
                        }
@@ -810,6 +858,7 @@ void ImageLoaderMachO::getRPaths(const LinkContext& context, std::vector<const c
        for (uint32_t i = 0; i < cmd_count; ++i) {
                switch (cmd->cmd) {
                        case LC_RPATH:
        for (uint32_t i = 0; i < cmd_count; ++i) {
                switch (cmd->cmd) {
                        case LC_RPATH:
+                               const char* pathToAdd = NULL;
                                const char* path = (char*)cmd + ((struct rpath_command*)cmd)->path.offset;
                                if ( strncmp(path, "@loader_path/", 13) == 0 ) {
                                        if ( context.processIsRestricted  && (context.mainExecutable == this) ) {
                                const char* path = (char*)cmd + ((struct rpath_command*)cmd)->path.offset;
                                if ( strncmp(path, "@loader_path/", 13) == 0 ) {
                                        if ( context.processIsRestricted  && (context.mainExecutable == this) ) {
@@ -825,7 +874,7 @@ void ImageLoaderMachO::getRPaths(const LinkContext& context, std::vector<const c
                                                        strcpy(&addPoint[1], &path[13]);
                                                else
                                                        strcpy(newRealPath, &path[13]);
                                                        strcpy(&addPoint[1], &path[13]);
                                                else
                                                        strcpy(newRealPath, &path[13]);
-                                               path = strdup(newRealPath);
+                                               pathToAdd = strdup(newRealPath);
                                        }
                                }
                                else if ( strncmp(path, "@executable_path/", 17) == 0 ) {
                                        }
                                }
                                else if ( strncmp(path, "@executable_path/", 17) == 0 ) {
@@ -842,7 +891,7 @@ void ImageLoaderMachO::getRPaths(const LinkContext& context, std::vector<const c
                                                        strcpy(&addPoint[1], &path[17]);
                                                else
                                                        strcpy(newRealPath, &path[17]);
                                                        strcpy(&addPoint[1], &path[17]);
                                                else
                                                        strcpy(newRealPath, &path[17]);
-                                               path = strdup(newRealPath);
+                                               pathToAdd = strdup(newRealPath);
                                        }
                                }
                                else if ( (path[0] != '/') && context.processIsRestricted ) {
                                        }
                                }
                                else if ( (path[0] != '/') && context.processIsRestricted ) {
@@ -860,21 +909,22 @@ void ImageLoaderMachO::getRPaths(const LinkContext& context, std::vector<const c
                                                struct stat stat_buf;
                                                if ( stat(newPath, &stat_buf) != -1 ) {
                                                        //dyld::log("combined DYLD_ROOT_PATH and LC_RPATH: %s\n", newPath);
                                                struct stat stat_buf;
                                                if ( stat(newPath, &stat_buf) != -1 ) {
                                                        //dyld::log("combined DYLD_ROOT_PATH and LC_RPATH: %s\n", newPath);
-                                                       path = strdup(newPath);
+                                                       pathToAdd = strdup(newPath);
                                                        found = true;
                                                        break;
                                                }
                                        }
                                        if ( ! found ) {
                                                // make copy so that all elements of 'paths' can be freed
                                                        found = true;
                                                        break;
                                                }
                                        }
                                        if ( ! found ) {
                                                // make copy so that all elements of 'paths' can be freed
-                                               path = strdup(path);
+                                               pathToAdd = strdup(path);
                                        }
                                }
                                else {
                                        // make copy so that all elements of 'paths' can be freed
                                        }
                                }
                                else {
                                        // make copy so that all elements of 'paths' can be freed
-                                       path = strdup(path);
+                                       pathToAdd = strdup(path);
                                }
                                }
-                               paths.push_back(path);
+                               if ( pathToAdd != NULL )
+                                       paths.push_back(pathToAdd);
                                break;
                }
                cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
                                break;
                }
                cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
@@ -972,8 +1022,9 @@ void ImageLoaderMachO::makeTextSegmentWritable(const LinkContext& context, bool
                segMakeWritable(textSegmentIndex, context);
        }
        else {
                segMakeWritable(textSegmentIndex, context);
        }
        else {
-               segProtect(textSegmentIndex, context);
+               // iPhoneOS requires range to be invalidated before it is made executable
                sys_icache_invalidate((void*)segActualLoadAddress(textSegmentIndex), segSize(textSegmentIndex));
                sys_icache_invalidate((void*)segActualLoadAddress(textSegmentIndex), segSize(textSegmentIndex));
+               segProtect(textSegmentIndex, context);
        }
 }
 #endif
        }
 }
 #endif
@@ -1004,14 +1055,27 @@ const ImageLoader::Symbol* ImageLoaderMachO::findExportedSymbol(const char* name
 
 
 
 
 
 
-uintptr_t ImageLoaderMachO::getExportedSymbolAddress(const Symbol* sym, const LinkContext& context, const ImageLoader* requestor) const
+uintptr_t ImageLoaderMachO::getExportedSymbolAddress(const Symbol* sym, const LinkContext& context, 
+                                                                                       const ImageLoader* requestor, bool runResolver) const
 {
 {
-       return this->getSymbolAddress(sym, requestor, context);
+       return this->getSymbolAddress(sym, requestor, context, runResolver);
 }
 
 }
 
-uintptr_t ImageLoaderMachO::getSymbolAddress(const Symbol* sym, const ImageLoader* requestor, const LinkContext& context) const
+uintptr_t ImageLoaderMachO::getSymbolAddress(const Symbol* sym, const ImageLoader* requestor, 
+                                                                                               const LinkContext& context, bool runResolver) const
 {
 {
-       uintptr_t result = exportedSymbolAddress(sym);
+       uintptr_t result = exportedSymbolAddress(context, sym, runResolver);
+       // check for interposing overrides
+       for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
+               // replace all references to 'replacee' with 'replacement'
+               if ( (result == it->replacee) && (requestor != it->replacementImage) ) {
+                       if ( context.verboseInterposing ) {
+                               dyld::log("dyld interposing: replace 0x%lX with 0x%lX in %s\n", 
+                                       it->replacee, it->replacement, this->getPath());
+                       }
+                       result = it->replacement;
+               }
+       }
        return result;
 }
 
        return result;
 }
 
@@ -1149,8 +1213,11 @@ bool ImageLoaderMachO::findSection(const void* imageInterior, const char** segme
 }
 
 
 }
 
 
-void __attribute__((noreturn)) ImageLoaderMachO::throwSymbolNotFound(const char* symbol, const char* referencedFrom, const char* expectedIn)
+void __attribute__((noreturn)) ImageLoaderMachO::throwSymbolNotFound(const LinkContext& context, const char* symbol, 
+                                                                                                                                       const char* referencedFrom, const char* expectedIn)
 {
 {
+       // record values for possible use by CrashReporter or Finder
+       (*context.setErrorStrings)(dyld_error_kind_symbol_missing, referencedFrom, expectedIn, symbol);
        dyld::throwf("Symbol not found: %s\n  Referenced from: %s\n  Expected in: %s\n", symbol, referencedFrom, expectedIn); 
 }
 
        dyld::throwf("Symbol not found: %s\n  Referenced from: %s\n  Expected in: %s\n", symbol, referencedFrom, expectedIn); 
 }
 
@@ -1196,6 +1263,9 @@ uintptr_t ImageLoaderMachO::bindLocation(const LinkContext& context, uintptr_t l
                                                ((targetImage != NULL) ? targetImage->getShortName() : "<weak>import-missing>"),
                                                 symbolName, (uintptr_t)location, value);
        }
                                                ((targetImage != NULL) ? targetImage->getShortName() : "<weak>import-missing>"),
                                                 symbolName, (uintptr_t)location, value);
        }
+#if LOG_BINDINGS
+//     dyld::logBindings("%s: %s\n", targetImage->getShortName(), symbolName);
+#endif
        
        // do actual update
        uintptr_t* locationToFix = (uintptr_t*)location;
        
        // do actual update
        uintptr_t* locationToFix = (uintptr_t*)location;
@@ -1333,22 +1403,22 @@ void ImageLoaderMachO::lookupProgramVars(const LinkContext& context) const
        // lookup _NXArgc
        sym = this->findExportedSymbol("_NXArgc", false, NULL);
        if ( sym != NULL )
        // lookup _NXArgc
        sym = this->findExportedSymbol("_NXArgc", false, NULL);
        if ( sym != NULL )
-               vars.NXArgcPtr = (int*)this->getExportedSymbolAddress(sym, context, this);
+               vars.NXArgcPtr = (int*)this->getExportedSymbolAddress(sym, context, this, false);
                
        // lookup _NXArgv
        sym = this->findExportedSymbol("_NXArgv", false, NULL);
        if ( sym != NULL )
                
        // lookup _NXArgv
        sym = this->findExportedSymbol("_NXArgv", false, NULL);
        if ( sym != NULL )
-               vars.NXArgvPtr = (const char***)this->getExportedSymbolAddress(sym, context, this);
+               vars.NXArgvPtr = (const char***)this->getExportedSymbolAddress(sym, context, this, false);
                
        // lookup _environ
        sym = this->findExportedSymbol("_environ", false, NULL);
        if ( sym != NULL )
                
        // lookup _environ
        sym = this->findExportedSymbol("_environ", false, NULL);
        if ( sym != NULL )
-               vars.environPtr = (const char***)this->getExportedSymbolAddress(sym, context, this);
+               vars.environPtr = (const char***)this->getExportedSymbolAddress(sym, context, this, false);
                
        // lookup __progname
        sym = this->findExportedSymbol("___progname", false, NULL);
        if ( sym != NULL )
                
        // lookup __progname
        sym = this->findExportedSymbol("___progname", false, NULL);
        if ( sym != NULL )
-               vars.__prognamePtr = (const char**)this->getExportedSymbolAddress(sym, context, this);
+               vars.__prognamePtr = (const char**)this->getExportedSymbolAddress(sym, context, this, false);
                
        context.setNewProgramVars(vars);
 }
                
        context.setNewProgramVars(vars);
 }
@@ -1357,8 +1427,7 @@ void ImageLoaderMachO::lookupProgramVars(const LinkContext& context) const
 bool ImageLoaderMachO::usablePrebinding(const LinkContext& context) const
 {
        // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
 bool ImageLoaderMachO::usablePrebinding(const LinkContext& context) const
 {
        // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
-       if ( (this->isPrebindable() || fInSharedCache)
-               && (this->getSlide() == 0) 
+       if ( ((this->isPrebindable() && (this->getSlide() == 0)) || fInSharedCache)
                && this->usesTwoLevelNameSpace()
                && this->allDependentLibrariesAsWhenPreBound() ) {
                // allow environment variables to disable prebinding
                && this->usesTwoLevelNameSpace()
                && this->allDependentLibrariesAsWhenPreBound() ) {
                // allow environment variables to disable prebinding
@@ -1382,6 +1451,16 @@ bool ImageLoaderMachO::usablePrebinding(const LinkContext& context) const
 void ImageLoaderMachO::doImageInit(const LinkContext& context)
 {
        if ( fHasDashInit ) {
 void ImageLoaderMachO::doImageInit(const LinkContext& context)
 {
        if ( fHasDashInit ) {
+#if __IPHONE_OS_VERSION_MIN_REQUIRED   
+               // <rdar://problem/8543820> verify initializers are in first segment for dylibs
+               if ( this->isDylib() && !fGoodFirstSegment ) {
+                       if ( context.verboseInit )
+                               dyld::log("dyld: ignoring -init in %s\n", this->getPath());
+                       return;
+               }
+               uintptr_t textStart = this->segActualLoadAddress(0);
+               uintptr_t textEnd = this->segActualEndAddress(0);
+#endif
                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 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;
@@ -1389,9 +1468,20 @@ void ImageLoaderMachO::doImageInit(const LinkContext& context)
                        switch (cmd->cmd) {
                                case LC_ROUTINES_COMMAND:
                                        Initializer func = (Initializer)(((struct macho_routines_command*)cmd)->init_address + fSlide);
                        switch (cmd->cmd) {
                                case LC_ROUTINES_COMMAND:
                                        Initializer func = (Initializer)(((struct macho_routines_command*)cmd)->init_address + fSlide);
-                                       if ( context.verboseInit )
-                                               dyld::log("dyld: calling -init function 0x%p in %s\n", func, this->getPath());
-                                       func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
+#if __IPHONE_OS_VERSION_MIN_REQUIRED   
+                                       // <rdar://problem/8543820> verify initializers are in first segment for dylibs
+                                       if ( this->isDylib() && (((uintptr_t)func >= textEnd) || ((uintptr_t)func < textStart)) ) {
+                                               if ( context.verboseInit )
+                                                       dyld::log("dyld: ignoring out of bounds initializer function %p in %s\n", func, this->getPath());
+                                       }
+                                       else {
+#endif
+                                               if ( context.verboseInit )
+                                                       dyld::log("dyld: calling -init function 0x%p in %s\n", func, this->getPath());
+                                               func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
+#if __IPHONE_OS_VERSION_MIN_REQUIRED   
+                                       }
+#endif
                                        break;
                        }
                        cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
                                        break;
                        }
                        cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
@@ -1402,6 +1492,16 @@ void ImageLoaderMachO::doImageInit(const LinkContext& context)
 void ImageLoaderMachO::doModInitFunctions(const LinkContext& context)
 {
        if ( fHasInitializers ) {
 void ImageLoaderMachO::doModInitFunctions(const LinkContext& context)
 {
        if ( fHasInitializers ) {
+#if __IPHONE_OS_VERSION_MIN_REQUIRED   
+               // <rdar://problem/8543820> verify initializers are in first segment for dylibs
+               if ( this->isDylib() && !fGoodFirstSegment ) {
+                       if ( context.verboseInit )
+                               dyld::log("dyld: ignoring all initializers in %s\n", this->getPath());
+                       return;
+               }
+               uintptr_t textStart = this->segActualLoadAddress(0);
+               uintptr_t textEnd = this->segActualEndAddress(0);
+#endif
                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 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;
@@ -1417,14 +1517,25 @@ void ImageLoaderMachO::doModInitFunctions(const LinkContext& context)
                                                const uint32_t count = sect->size / sizeof(uintptr_t);
                                                for (uint32_t i=0; i < count; ++i) {
                                                        Initializer func = inits[i];
                                                const uint32_t count = sect->size / sizeof(uintptr_t);
                                                for (uint32_t i=0; i < count; ++i) {
                                                        Initializer func = inits[i];
-                                                       if ( context.verboseInit )
-                                                               dyld::log("dyld: calling initializer function %p in %s\n", func, this->getPath());
-                                                       func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
+#if __IPHONE_OS_VERSION_MIN_REQUIRED   
+                                                       // <rdar://problem/8543820> verify initializers are in first segment for dylibs
+                                                       if ( this->isDylib() && (((uintptr_t)func >= textEnd) || ((uintptr_t)func < textStart)) ) {
+                                                               if ( context.verboseInit )
+                                                                       dyld::log("dyld: ignoring out of bounds initializer function %p in %s\n", func, this->getPath());
+                                                       }
+                                                       else {
+#endif                                         
+                                                               if ( context.verboseInit )
+                                                                       dyld::log("dyld: calling initializer function %p in %s\n", func, this->getPath());
+                                                               func(context.argc, context.argv, context.envp, context.apple, &context.programVars);
+#if __IPHONE_OS_VERSION_MIN_REQUIRED   
+                                                       }
+#endif
                                                }
                                        }
                                }
                                                }
                                        }
                                }
-                               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
                        }
                        }
+                       cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
                }
        }
 }
                }
        }
 }
@@ -1466,11 +1577,17 @@ void ImageLoaderMachO::doGetDOFSections(const LinkContext& context, std::vector<
 }      
 
 
 }      
 
 
-void ImageLoaderMachO::doInitialization(const LinkContext& context)
+bool ImageLoaderMachO::doInitialization(const LinkContext& context)
 {
 {
+       CRSetCrashLogMessage2(this->getPath());
+
        // mach-o has -init and static initializers
        doImageInit(context);
        doModInitFunctions(context);
        // mach-o has -init and static initializers
        doImageInit(context);
        doModInitFunctions(context);
+       
+       CRSetCrashLogMessage2(NULL);
+       
+       return (fHasDashInit || fHasInitializers);
 }
 
 bool ImageLoaderMachO::needsInitialization()
 }
 
 bool ImageLoaderMachO::needsInitialization()
@@ -1516,12 +1633,13 @@ void ImageLoaderMachO::doTermination(const LinkContext& context)
 }
 
 
 }
 
 
-void ImageLoaderMachO::printStatistics(unsigned int imageCount)
+void ImageLoaderMachO::printStatistics(unsigned int imageCount, const InitializerTimingList& timingInfo)
 {
 {
-       ImageLoader::printStatistics(imageCount);
+       ImageLoader::printStatistics(imageCount, timingInfo);
        dyld::log("total symbol trie searches:    %d\n", fgSymbolTrieSearchs);
        dyld::log("total symbol table binary searches:    %d\n", fgSymbolTableBinarySearchs);
        dyld::log("total symbol trie searches:    %d\n", fgSymbolTrieSearchs);
        dyld::log("total symbol table binary searches:    %d\n", fgSymbolTableBinarySearchs);
-       dyld::log("total images defining/using weak symbols:  %u/%u\n", fgImagesHasWeakDefinitions, fgImagesRequiringCoalescing);
+       dyld::log("total images defining weak symbols:  %u\n", fgImagesHasWeakDefinitions);
+       dyld::log("total images using weak symbols:  %u\n", fgImagesRequiringCoalescing);
 }
 
 
 }
 
 
@@ -1557,7 +1675,7 @@ intptr_t ImageLoaderMachO::assignSegmentAddresses(const LinkContext& context)
                        if ( strcmp(segName(i), "__PAGEZERO") == 0 )
                                continue;
                        if ( !reserveAddressRange(segPreferredLoadAddress(i), segSize(i)) )
                        if ( strcmp(segName(i), "__PAGEZERO") == 0 )
                                continue;
                        if ( !reserveAddressRange(segPreferredLoadAddress(i), segSize(i)) )
-                               throw "can't map";
+                               dyld::throwf("can't map unslidable segment %s to 0x%lX with size 0x%lX", segName(i), segPreferredLoadAddress(i), segSize(i));
                }
        }
        else {
                }
        }
        else {
@@ -1573,7 +1691,9 @@ uintptr_t ImageLoaderMachO::reserveAnAddressRange(size_t length, const ImageLoad
        vm_size_t size = length;
        // in PIE programs, load initial dylibs after main executable so they don't have fixed addresses either
        if ( fgNextPIEDylibAddress != 0 ) {
        vm_size_t size = length;
        // in PIE programs, load initial dylibs after main executable so they don't have fixed addresses either
        if ( fgNextPIEDylibAddress != 0 ) {
-               addr = fgNextPIEDylibAddress + (arc4random() & 0x3) * 4096; // add small random padding between dylibs
+                // 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);
                if ( r == KERN_SUCCESS ) {
                        fgNextPIEDylibAddress = addr + size;
                kern_return_t r = vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_FIXED);
                if ( r == KERN_SUCCESS ) {
                        fgNextPIEDylibAddress = addr + size;
@@ -1606,14 +1726,30 @@ void ImageLoaderMachO::mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInF
        intptr_t slide = this->assignSegmentAddresses(context);
        if ( context.verboseMapping )
                dyld::log("dyld: Mapping %s\n", this->getPath());
        intptr_t slide = this->assignSegmentAddresses(context);
        if ( context.verboseMapping )
                dyld::log("dyld: Mapping %s\n", this->getPath());
+       // <rdar://problem/8268602> verify that the first segment load command is for a r-x segment
+       // that starts at begining of file and is larger than all load commands
+       uintptr_t firstSegMappedStart = segPreferredLoadAddress(0) + slide;
+       uintptr_t firstSegMappedEnd = firstSegMappedStart + this->segSize(0);
+       if ( (this->segLoadCommand(0)->initprot == (VM_PROT_EXECUTE|VM_PROT_READ)) 
+               && (this->segFileOffset(0) == 0) 
+               && (this->segFileSize(0) != 0) 
+               && (this->segSize(0) > ((macho_header*)fMachOData)->sizeofcmds) ) {
+                       fGoodFirstSegment = true;
+       }
        // map in all segments
        for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
                vm_offset_t fileOffset = segFileOffset(i) + offsetInFat;
                vm_size_t size = segFileSize(i);
        // map in all segments
        for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
                vm_offset_t fileOffset = segFileOffset(i) + offsetInFat;
                vm_size_t size = segFileSize(i);
-               void* requestedLoadAddress = (void*)(segPreferredLoadAddress(i) + slide);
+               uintptr_t requestedLoadAddress = segPreferredLoadAddress(i) + slide;
+               // <rdar://problem/8268602> verify other segments map after first
+               if ( (i != 0) && (requestedLoadAddress < firstSegMappedEnd) )
+                       fGoodFirstSegment = false;
                int protection = 0;
                if ( !segUnaccessible(i) ) {
                int protection = 0;
                if ( !segUnaccessible(i) ) {
-                       if ( segExecutable(i) )
+                       // If has text-relocs, don't set x-bit initially.
+                       // Instead set it later after text-relocs have been done.
+                       // The iPhone OS does not like it when you make executable code writable.
+                       if ( segExecutable(i) && !(segHasRebaseFixUps(i) && (slide != 0)) )
                                protection   |= PROT_EXEC;
                        if ( segReadable(i) )
                                protection   |= PROT_READ;
                                protection   |= PROT_EXEC;
                        if ( segReadable(i) )
                                protection   |= PROT_READ;
@@ -1631,19 +1767,20 @@ 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);
                        }
                                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(requestedLoadAddress, size, protection, MAP_FIXED | MAP_PRIVATE, fd, fileOffset);
+                       void* loadAddress = mmap((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", 
                        if ( loadAddress == ((void*)(-1)) ) {
                                dyld::throwf("mmap() error %d at address=0x%08lX, size=0x%08lX segment=%s in Segment::map() mapping %s", 
-                                       errno, (uintptr_t)requestedLoadAddress, (uintptr_t)size, segName(i), getPath());
+                                       errno, requestedLoadAddress, (uintptr_t)size, segName(i), getPath());
                        }
                }
                // update stats
                ++ImageLoader::fgTotalSegmentsMapped;
                ImageLoader::fgTotalBytesMapped += size;
                if ( context.verboseMapping )
                        }
                }
                // update stats
                ++ImageLoader::fgTotalSegmentsMapped;
                ImageLoader::fgTotalBytesMapped += size;
                if ( context.verboseMapping )
-                       dyld::log("%18s at 0x%08lX->0x%08lX with permissions %c%c%c\n", segName(i), (uintptr_t)requestedLoadAddress, (uintptr_t)((char*)requestedLoadAddress+size-1),
+                       dyld::log("%18s at 0x%08lX->0x%08lX with permissions %c%c%c\n", segName(i), requestedLoadAddress, requestedLoadAddress+size-1,
                                (protection & PROT_READ) ? 'r' : '.',  (protection & PROT_WRITE) ? 'w' : '.',  (protection & PROT_EXEC) ? 'x' : '.' );
        }
                                (protection & PROT_READ) ? 'r' : '.',  (protection & PROT_WRITE) ? 'w' : '.',  (protection & PROT_EXEC) ? 'x' : '.' );
        }
+
        // update slide to reflect load location                        
        this->setSlide(slide);
 }
        // update slide to reflect load location                        
        this->setSlide(slide);
 }
@@ -1689,8 +1826,10 @@ void ImageLoaderMachO::segProtect(unsigned int segIndex, const ImageLoader::Link
        vm_size_t size = segSize(segIndex);
        const bool setCurrentPermissions = false;
        kern_return_t r = vm_protect(mach_task_self(), addr, size, setCurrentPermissions, protection);
        vm_size_t size = segSize(segIndex);
        const bool setCurrentPermissions = false;
        kern_return_t r = vm_protect(mach_task_self(), addr, size, setCurrentPermissions, protection);
-       if ( r != KERN_SUCCESS ) 
-               throw "can't set vm permissions for mapped segment";
+       if ( r != KERN_SUCCESS ) {
+        dyld::throwf("vm_protect(0x%08llX, 0x%08llX, false, 0x%02X) failed, result=%d for segment %s in %s",
+            (long long)addr, (long long)size, protection, r, segName(segIndex), this->getPath());
+    }
        if ( context.verboseMapping ) {
                dyld::log("%18s at 0x%08lX->0x%08lX altered permissions to %c%c%c\n", segName(segIndex), (uintptr_t)addr, (uintptr_t)addr+size-1,
                        (protection & PROT_READ) ? 'r' : '.',  (protection & PROT_WRITE) ? 'w' : '.',  (protection & PROT_EXEC) ? 'x' : '.' );
        if ( context.verboseMapping ) {
                dyld::log("%18s at 0x%08lX->0x%08lX altered permissions to %c%c%c\n", segName(segIndex), (uintptr_t)addr, (uintptr_t)addr+size-1,
                        (protection & PROT_READ) ? 'r' : '.',  (protection & PROT_WRITE) ? 'w' : '.',  (protection & PROT_EXEC) ? 'x' : '.' );
@@ -1703,11 +1842,13 @@ void ImageLoaderMachO::segMakeWritable(unsigned int segIndex, const ImageLoader:
        vm_size_t size = segSize(segIndex);
        const bool setCurrentPermissions = false;
        vm_prot_t protection = VM_PROT_WRITE | VM_PROT_READ;
        vm_size_t size = segSize(segIndex);
        const bool setCurrentPermissions = false;
        vm_prot_t protection = VM_PROT_WRITE | VM_PROT_READ;
-       if ( segExecutable(segIndex) )
+       if ( segExecutable(segIndex) && !segHasRebaseFixUps(segIndex) )
                protection |= VM_PROT_EXECUTE;
        kern_return_t r = vm_protect(mach_task_self(), addr, size, setCurrentPermissions, protection);
                protection |= VM_PROT_EXECUTE;
        kern_return_t r = vm_protect(mach_task_self(), addr, size, setCurrentPermissions, protection);
-       if ( r != KERN_SUCCESS ) 
-               throw "can't set vm permissions for mapped segment";
+       if ( r != KERN_SUCCESS ) {
+        dyld::throwf("vm_protect(0x%08llX, 0x%08llX, false, 0x%02X) failed, result=%d for segment %s in %s",
+            (long long)addr, (long long)size, protection, r, segName(segIndex), this->getPath());
+    }
        if ( context.verboseMapping ) {
                dyld::log("%18s at 0x%08lX->0x%08lX altered permissions to %c%c%c\n", segName(segIndex), (uintptr_t)addr, (uintptr_t)addr+size-1,
                        (protection & PROT_READ) ? 'r' : '.',  (protection & PROT_WRITE) ? 'w' : '.',  (protection & PROT_EXEC) ? 'x' : '.' );
        if ( context.verboseMapping ) {
                dyld::log("%18s at 0x%08lX->0x%08lX altered permissions to %c%c%c\n", segName(segIndex), (uintptr_t)addr, (uintptr_t)addr+size-1,
                        (protection & PROT_READ) ? 'r' : '.',  (protection & PROT_WRITE) ? 'w' : '.',  (protection & PROT_EXEC) ? 'x' : '.' );
index 5d735bfc764a9b03a0b80578939ea461b4e0c4cb..a2b657a9c554aa9b426daf5202cf732030f9f7c2 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2004-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -43,10 +43,11 @@ public:
        static ImageLoader*                                     instantiateMainExecutable(const macho_header* mh, uintptr_t slide, const char* path, const LinkContext& context);
        static ImageLoader*                                     instantiateFromFile(const char* path, int fd, const uint8_t firstPage[4096], uint64_t offsetInFat, 
                                                                                                                        uint64_t lenInFat, const struct stat& info, const LinkContext& context);
        static ImageLoader*                                     instantiateMainExecutable(const macho_header* mh, uintptr_t slide, const char* path, const LinkContext& context);
        static ImageLoader*                                     instantiateFromFile(const char* path, int fd, const uint8_t firstPage[4096], uint64_t offsetInFat, 
                                                                                                                        uint64_t lenInFat, const struct stat& info, const LinkContext& context);
-       static ImageLoader*                                     instantiateFromCache(const macho_header* mh, const char* path, const struct stat& info, const LinkContext& context);
+       static ImageLoader*                                     instantiateFromCache(const macho_header* mh, const char* path, long slide, const struct stat& info, const LinkContext& context);
        static ImageLoader*                                     instantiateFromMemory(const char* moduleName, const macho_header* mh, uint64_t len, const LinkContext& context);
 
 
        static ImageLoader*                                     instantiateFromMemory(const char* moduleName, const macho_header* mh, uint64_t len, const LinkContext& context);
 
 
+       bool                                                            inSharedCache() const { return fInSharedCache; }
        const char*                                                     getInstallPath() const;
        virtual void*                                           getMain() const;
        virtual const struct mach_header*   machHeader() const;
        const char*                                                     getInstallPath() const;
        virtual void*                                           getMain() const;
        virtual const struct mach_header*   machHeader() const;
@@ -54,7 +55,8 @@ public:
        virtual const void*                                     getEnd() const;
        virtual bool                                            hasCoalescedExports() const;
        virtual const Symbol*                           findExportedSymbol(const char* name, bool searchReExports, const ImageLoader** foundIn) const;
        virtual const void*                                     getEnd() const;
        virtual bool                                            hasCoalescedExports() const;
        virtual const Symbol*                           findExportedSymbol(const char* name, bool searchReExports, const ImageLoader** foundIn) const;
-       virtual uintptr_t                                       getExportedSymbolAddress(const Symbol* sym, const LinkContext& context, const ImageLoader* requestor) const;
+       virtual uintptr_t                                       getExportedSymbolAddress(const Symbol* sym, const LinkContext& context, 
+                                                                                                                               const ImageLoader* requestor, bool runResolver) const;
        virtual DefinitionFlags                         getExportedSymbolInfo(const Symbol* sym) const;
        virtual const char*                                     getExportedSymbolName(const Symbol* sym) const;
        virtual uint32_t                                        getExportedSymbolCount() const;
        virtual DefinitionFlags                         getExportedSymbolInfo(const Symbol* sym) const;
        virtual const char*                                     getExportedSymbolName(const Symbol* sym) const;
        virtual uint32_t                                        getExportedSymbolCount() const;
@@ -75,7 +77,7 @@ public:
        virtual uintptr_t                                       getAddressCoalIterator(CoalIterator&, const LinkContext& contex) = 0;
        virtual void                                            updateUsesCoalIterator(CoalIterator&, uintptr_t newAddr, ImageLoader* target, const LinkContext& context) = 0;
        virtual uintptr_t                                       doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context) = 0;
        virtual uintptr_t                                       getAddressCoalIterator(CoalIterator&, const LinkContext& contex) = 0;
        virtual void                                            updateUsesCoalIterator(CoalIterator&, uintptr_t newAddr, ImageLoader* target, const LinkContext& context) = 0;
        virtual uintptr_t                                       doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context) = 0;
-       virtual uintptr_t                                       doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context) = 0;
+       virtual uintptr_t                                       doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context, void (*lock)(), void (*unlock)()) = 0;
        virtual void                                            doTermination(const LinkContext& context);
        virtual bool                                            needsInitialization();
        virtual bool                                            getSectionContent(const char* segmentName, const char* sectionName, void** start, size_t* length);
        virtual void                                            doTermination(const LinkContext& context);
        virtual bool                                            needsInitialization();
        virtual bool                                            getSectionContent(const char* segmentName, const char* sectionName, void** start, size_t* length);
@@ -96,9 +98,10 @@ public:
        virtual uintptr_t                                       segActualLoadAddress(unsigned int) const;
        virtual uintptr_t                                       segPreferredLoadAddress(unsigned int) const;
        virtual uintptr_t                                       segActualEndAddress(unsigned int) const;
        virtual uintptr_t                                       segActualLoadAddress(unsigned int) const;
        virtual uintptr_t                                       segPreferredLoadAddress(unsigned int) const;
        virtual uintptr_t                                       segActualEndAddress(unsigned int) const;
+       virtual void                                            registerInterposing();
                        
        
                        
        
-       static void                                                     printStatistics(unsigned int imageCount);
+       static void                                                     printStatistics(unsigned int imageCount, const InitializerTimingList&);
        
 protected:
                                                ImageLoaderMachO(const ImageLoaderMachO&);
        
 protected:
                                                ImageLoaderMachO(const ImageLoaderMachO&);
@@ -108,7 +111,7 @@ protected:
 
        void                            operator=(const ImageLoaderMachO&);
 
 
        void                            operator=(const ImageLoaderMachO&);
 
-       virtual void                                            setDyldInfo(const dyld_info_command*) = 0;
+       virtual void                                            setDyldInfo(const struct dyld_info_command*) = 0;
        virtual void                                            setSymbolTableInfo(const macho_nlist*, const char*, const dysymtab_command*) = 0;
        virtual bool                                            isSubframeworkOf(const LinkContext& context, const ImageLoader* image) const = 0;
        virtual bool                                            hasSubLibrary(const LinkContext& context, const ImageLoader* child) const = 0;
        virtual void                                            setSymbolTableInfo(const macho_nlist*, const char*, const dysymtab_command*) = 0;
        virtual bool                                            isSubframeworkOf(const LinkContext& context, const ImageLoader* image) const = 0;
        virtual bool                                            hasSubLibrary(const LinkContext& context, const ImageLoader* child) const = 0;
@@ -116,7 +119,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 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 Symbol* symbol) const = 0;
+       virtual uintptr_t                                       exportedSymbolAddress(const LinkContext& context, const Symbol* symbol, 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;
        virtual bool                                            exportedSymbolIsWeakDefintion(const Symbol* symbol) const = 0;
        virtual const char*                                     exportedSymbolName(const Symbol* symbol) const = 0;
        virtual unsigned int                            exportedSymbolCount() const = 0;
@@ -136,7 +139,7 @@ protected:
        virtual void            doRebase(const LinkContext& context);
        virtual void            doBind(const LinkContext& context, bool forceLazysBound) = 0;
        virtual void            doBindJustLazies(const LinkContext& context) = 0;
        virtual void            doRebase(const LinkContext& context);
        virtual void            doBind(const LinkContext& context, bool forceLazysBound) = 0;
        virtual void            doBindJustLazies(const LinkContext& context) = 0;
-       virtual void            doInitialization(const LinkContext& context);
+       virtual bool            doInitialization(const LinkContext& context);
        virtual void            doGetDOFSections(const LinkContext& context, std::vector<ImageLoader::DOFInfo>& dofs);
        virtual bool            needsTermination();
        virtual bool            segmentsMustSlideTogether() const;      
        virtual void            doGetDOFSections(const LinkContext& context, std::vector<ImageLoader::DOFInfo>& dofs);
        virtual bool            needsTermination();
        virtual bool            segmentsMustSlideTogether() const;      
@@ -150,10 +153,11 @@ protected:
 
                        void            destroy();
        static void                     sniffLoadCommands(const macho_header* mh, const char* path, bool* compressed,
 
                        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 linkedit_data_command** codeSigCmd);
        static bool                     needsAddedLibSystemDepency(unsigned int libCount, const macho_header* mh);
 #if CODESIGNING_SUPPORT
        static bool                     needsAddedLibSystemDepency(unsigned int libCount, const macho_header* mh);
 #if CODESIGNING_SUPPORT
-                       void            loadCodeSignature(const uint8_t* fileData, int fd, uint64_t offsetInFatFile);
+                       void            loadCodeSignature(const struct linkedit_data_command* codeSigCmd, int fd, uint64_t offsetInFatFile);
 #endif
                        const struct macho_segment_command* segLoadCommand(unsigned int segIndex) const;
                        void            parseLoadCmds();
 #endif
                        const struct macho_segment_command* segLoadCommand(unsigned int segIndex) const;
                        void            parseLoadCmds();
@@ -170,7 +174,8 @@ protected:
                        void            mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context);
                        void            mapSegments(const void* memoryImage, uint64_t imageLen, const LinkContext& context);
                        void            UnmapSegments();
                        void            mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context);
                        void            mapSegments(const void* memoryImage, uint64_t imageLen, const LinkContext& context);
                        void            UnmapSegments();
-                       void            __attribute__((noreturn)) throwSymbolNotFound(const char* symbol, const char* referencedFrom, const char* expectedIn);
+                       void            __attribute__((noreturn)) throwSymbolNotFound(const LinkContext& context, const char* symbol, 
+                                                                                                                                       const char* referencedFrom, const char* expectedIn);
                        void            doImageInit(const LinkContext& context);
                        void            doModInitFunctions(const LinkContext& context);
                        void            setupLazyPointerHandler(const LinkContext& context);
                        void            doImageInit(const LinkContext& context);
                        void            doModInitFunctions(const LinkContext& context);
                        void            setupLazyPointerHandler(const LinkContext& context);
@@ -183,8 +188,10 @@ protected:
                        void            preFetchDATA(int fd, uint64_t offsetInFat, const LinkContext& context);
 
 
                        void            preFetchDATA(int fd, uint64_t offsetInFat, const LinkContext& context);
 
 
+                       void            doInterpose(const LinkContext& context) = 0;
                        bool            hasReferencesToWeakSymbols() const;
                        bool            hasReferencesToWeakSymbols() const;
-                       uintptr_t       getSymbolAddress(const Symbol* sym, const ImageLoader* requestor, const LinkContext& context) const;
+                       uintptr_t       getSymbolAddress(const Symbol* sym, const ImageLoader* requestor, 
+                                                                               const LinkContext& context, bool runResolver) const;
                        
        static uintptr_t                        bindLazySymbol(const mach_header*, uintptr_t* lazyPointer);
 protected:                     
                        
        static uintptr_t                        bindLazySymbol(const mach_header*, uintptr_t* lazyPointer);
 protected:                     
@@ -210,7 +217,9 @@ protected:
                                                                                        fHasDOFSections : 1,
                                                                                        fHasDashInit : 1,
                                                                                        fHasInitializers : 1,
                                                                                        fHasDOFSections : 1,
                                                                                        fHasDashInit : 1,
                                                                                        fHasInitializers : 1,
-                                                                                       fHasTerminators : 1;
+                                                                                       fHasTerminators : 1,
+                                                                                       fGoodFirstSegment : 1,
+                                                                                       fRegisteredAsRequiresCoalescing : 1;    // <rdar://problem/7886402> Loading MH_DYLIB_STUB causing coalescable miscount
                                                                                        
                                                                                        
        static uint32_t                                 fgSymbolTableBinarySearchs;
                                                                                        
                                                                                        
        static uint32_t                                 fgSymbolTableBinarySearchs;
index 182047e1df697115d5b166a96aa50f4605591fac..33b055d94bee273ef19a8d5c9a851f3de26d7171 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2004-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -106,11 +106,12 @@ ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateMainExecutable(cons
        image->setSlide(slide);
 
        // for PIE record end of program, to know where to start loading dylibs
        image->setSlide(slide);
 
        // for PIE record end of program, to know where to start loading dylibs
-       if ( (mh->flags & MH_PIE) && !context.noPIE )
+       if ( slide != 0 )
                fgNextPIEDylibAddress = (uintptr_t)image->getEnd();
        
        image->instantiateFinish(context);
                fgNextPIEDylibAddress = (uintptr_t)image->getEnd();
        
        image->instantiateFinish(context);
-       
+       image->setMapped(context);
+
 #if __i386__
        // kernel may have mapped in __IMPORT segment read-only, we need it read/write to do binding
        if ( image->fReadOnlyImportSegment ) {
 #if __i386__
        // kernel may have mapped in __IMPORT segment read-only, we need it read/write to do binding
        if ( image->fReadOnlyImportSegment ) {
@@ -138,21 +139,26 @@ ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateMainExecutable(cons
 // create image by mapping in a mach-o file
 ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateFromFile(const char* path, int fd, const uint8_t* fileData, 
                                                                                                                        uint64_t offsetInFat, uint64_t lenInFat, const struct stat& info, 
 // create image by mapping in a mach-o file
 ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateFromFile(const char* path, int fd, const uint8_t* fileData, 
                                                                                                                        uint64_t offsetInFat, uint64_t lenInFat, const struct stat& info, 
-                                                                                                                       unsigned int segCount, unsigned int libCount, const LinkContext& context)
+                                                                                                                       unsigned int segCount, unsigned int libCount, 
+                                                                                                                       const struct linkedit_data_command* codeSigCmd, const LinkContext& context)
 {
        ImageLoaderMachOClassic* image = ImageLoaderMachOClassic::instantiateStart((macho_header*)fileData, path, segCount, libCount);
        try {
                // record info about file  
                image->setFileInfo(info.st_dev, info.st_ino, info.st_mtime);
 
 {
        ImageLoaderMachOClassic* image = ImageLoaderMachOClassic::instantiateStart((macho_header*)fileData, path, segCount, libCount);
        try {
                // record info about file  
                image->setFileInfo(info.st_dev, info.st_ino, info.st_mtime);
 
-               // mmap segments
-               image->mapSegmentsClassic(fd, offsetInFat, lenInFat, info.st_size, context);
-
        #if CODESIGNING_SUPPORT
        #if CODESIGNING_SUPPORT
-               // if this code is signed, validate the signature before accessing any mapped pages
-               image->loadCodeSignature(fileData, fd, offsetInFat);
+               // 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
                
        #endif
                
+               // mmap segments
+               image->mapSegmentsClassic(fd, offsetInFat, lenInFat, info.st_size, context);
+
+               // finish up
+               image->instantiateFinish(context);
+
                // if path happens to be same as in LC_DYLIB_ID load command use that, otherwise malloc a copy of the path
                const char* installName = image->getInstallPath();
                if ( (installName != NULL) && (strcmp(installName, path) == 0) && (path[0] == '/') )
                // if path happens to be same as in LC_DYLIB_ID load command use that, otherwise malloc a copy of the path
                const char* installName = image->getInstallPath();
                if ( (installName != NULL) && (strcmp(installName, path) == 0) && (path[0] == '/') )
@@ -168,13 +174,14 @@ ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateFromFile(const char
                else 
                        image->setPath(path);
 
                else 
                        image->setPath(path);
 
+               // make sure path is stable before recording in dyld_all_image_infos
+               image->setMapped(context);
+
                // pre-fetch content of __DATA segment for faster launches
                // don't do this on prebound images or if prefetching is disabled
         if ( !context.preFetchDisabled && !image->isPrebindable())
                        image->preFetchDATA(fd, offsetInFat, context);
 
                // pre-fetch content of __DATA segment for faster launches
                // don't do this on prebound images or if prefetching is disabled
         if ( !context.preFetchDisabled && !image->isPrebindable())
                        image->preFetchDATA(fd, offsetInFat, context);
 
-               // finish up
-               image->instantiateFinish(context);
        }
        catch (...) {
                // ImageLoader::setMapped() can throw an exception to block loading of image
        }
        catch (...) {
                // ImageLoader::setMapped() can throw an exception to block loading of image
@@ -187,7 +194,7 @@ ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateFromFile(const char
 }
 
 // create image by using cached mach-o file
 }
 
 // create image by using cached mach-o file
-ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateFromCache(const macho_header* mh, const char* path, const struct stat& info,
+ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateFromCache(const macho_header* mh, const char* path, long slide, const struct stat& info,
                                                                                                                                unsigned int segCount, unsigned int libCount, const LinkContext& context)
 {
        ImageLoaderMachOClassic* image = ImageLoaderMachOClassic::instantiateStart(mh, path, segCount, libCount);
                                                                                                                                unsigned int segCount, unsigned int libCount, const LinkContext& context)
 {
        ImageLoaderMachOClassic* image = ImageLoaderMachOClassic::instantiateStart(mh, path, segCount, libCount);
@@ -208,6 +215,7 @@ ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateFromCache(const mac
                }
 
                image->instantiateFinish(context);
                }
 
                image->instantiateFinish(context);
+               image->setMapped(context);
        }
        catch (...) {
                // ImageLoader::setMapped() can throw an exception to block loading of image
        }
        catch (...) {
                // ImageLoader::setMapped() can throw an exception to block loading of image
@@ -240,6 +248,7 @@ ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateFromMemory(const ch
                        image->setPath(moduleName);
 
                image->instantiateFinish(context);
                        image->setPath(moduleName);
 
                image->instantiateFinish(context);
+               image->setMapped(context);
        }
        catch (...) {
                // ImageLoader::setMapped() can throw an exception to block loading of image
        }
        catch (...) {
                // ImageLoader::setMapped() can throw an exception to block loading of image
@@ -278,9 +287,6 @@ void ImageLoaderMachOClassic::instantiateFinish(const LinkContext& context)
 {
        // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
        this->parseLoadCmds();
 {
        // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
        this->parseLoadCmds();
-       
-       // notify state change
-       this->setMapped(context);
 }
 
 ImageLoaderMachOClassic::~ImageLoaderMachOClassic()
 }
 
 ImageLoaderMachOClassic::~ImageLoaderMachOClassic()
@@ -298,8 +304,8 @@ uint32_t* ImageLoaderMachOClassic::segmentCommandOffsets() const
 ImageLoader* ImageLoaderMachOClassic::libImage(unsigned int libIndex) const
 {
        const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic) + fSegmentsCount*sizeof(uint32_t)));
 ImageLoader* ImageLoaderMachOClassic::libImage(unsigned int libIndex) const
 {
        const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic) + fSegmentsCount*sizeof(uint32_t)));
-       // mask off low bit
-       return (ImageLoader*)(images[libIndex] & (-2));
+       // mask off low bits
+       return (ImageLoader*)(images[libIndex] & (-4));
 }
 
 bool ImageLoaderMachOClassic::libReExported(unsigned int libIndex) const
 }
 
 bool ImageLoaderMachOClassic::libReExported(unsigned int libIndex) const
@@ -309,13 +315,22 @@ bool ImageLoaderMachOClassic::libReExported(unsigned int libIndex) const
        return ((images[libIndex] & 1) != 0);
 }      
 
        return ((images[libIndex] & 1) != 0);
 }      
 
+bool ImageLoaderMachOClassic::libIsUpward(unsigned int libIndex) const
+{
+       const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic) + fSegmentsCount*sizeof(uint32_t)));
+       // upward flag is second bit
+       return ((images[libIndex] & 2) != 0);
+}      
+
 
 
-void ImageLoaderMachOClassic::setLibImage(unsigned int libIndex, ImageLoader* image, bool reExported)
+void ImageLoaderMachOClassic::setLibImage(unsigned int libIndex, ImageLoader* image, bool reExported, bool upward)
 {
        uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic) + fSegmentsCount*sizeof(uint32_t)));
        uintptr_t value = (uintptr_t)image;
        if ( reExported ) 
                value |= 1;
 {
        uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic) + fSegmentsCount*sizeof(uint32_t)));
        uintptr_t value = (uintptr_t)image;
        if ( reExported ) 
                value |= 1;
+       if ( upward ) 
+               value |= 2;
        images[libIndex] = value;
 }
 
        images[libIndex] = value;
 }
 
@@ -506,9 +521,12 @@ void ImageLoaderMachOClassic::mapSegmentsClassic(int fd, uint64_t offsetInFat, u
                return ImageLoaderMachO::mapSegments(fd, offsetInFat, lenInFat, fileLen, context);
 
 #if SPLIT_SEG_SHARED_REGION_SUPPORT    
                return ImageLoaderMachO::mapSegments(fd, offsetInFat, lenInFat, fileLen, context);
 
 #if SPLIT_SEG_SHARED_REGION_SUPPORT    
-       // try to map into shared region at preferred address
-       if ( mapSplitSegDylibInfoSharedRegion(fd, offsetInFat, lenInFat, fileLen, context) == 0) 
-               return;
+       // don't map split-seg dylibs into shared region if shared cache is in use
+       if ( ! context.dyldLoadedAtSameAddressNeededBySharedCache ) {
+               // try to map into shared region at preferred address
+               if ( mapSplitSegDylibInfoSharedRegion(fd, offsetInFat, lenInFat, fileLen, context) == 0) 
+                       return;
+       }
        // if there is a problem, fall into case where we map file somewhere outside the shared region
 #endif
 
        // if there is a problem, fall into case where we map file somewhere outside the shared region
 #endif
 
@@ -779,6 +797,7 @@ void ImageLoaderMachOClassic::resetPreboundLazyPointers(const LinkContext& conte
 
 void ImageLoaderMachOClassic::rebase(const LinkContext& context)
 {
 
 void ImageLoaderMachOClassic::rebase(const LinkContext& context)
 {
+       CRSetCrashLogMessage2(this->getPath());
        register const uintptr_t slide = this->fSlide;
        const uintptr_t relocBase = this->getRelocBase();
        
        register const uintptr_t slide = this->fSlide;
        const uintptr_t relocBase = this->getRelocBase();
        
@@ -885,6 +904,7 @@ void ImageLoaderMachOClassic::rebase(const LinkContext& context)
        
        // update stats
        fgTotalRebaseFixups += fDynamicInfo->nlocrel;
        
        // update stats
        fgTotalRebaseFixups += fDynamicInfo->nlocrel;
+       CRSetCrashLogMessage2(NULL);
 }
 
 
 }
 
 
@@ -986,7 +1006,7 @@ bool ImageLoaderMachOClassic::containsSymbol(const void* addr) const
 }
 
 
 }
 
 
-uintptr_t ImageLoaderMachOClassic::exportedSymbolAddress(const Symbol* symbol) const
+uintptr_t ImageLoaderMachOClassic::exportedSymbolAddress(const LinkContext& context, const Symbol* symbol, bool runResolver) const
 {
        const struct macho_nlist* sym = (macho_nlist*)symbol;
        uintptr_t result = sym->n_value + fSlide;
 {
        const struct macho_nlist* sym = (macho_nlist*)symbol;
        uintptr_t result = sym->n_value + fSlide;
@@ -1066,9 +1086,9 @@ bool ImageLoaderMachOClassic::symbolIsWeakReference(const struct macho_nlist* sy
        return false;
 }
 
        return false;
 }
 
-uintptr_t ImageLoaderMachOClassic::getSymbolAddress(const macho_nlist* sym, const LinkContext& context) const
+uintptr_t ImageLoaderMachOClassic::getSymbolAddress(const macho_nlist* sym, const LinkContext& context, bool runResolver) const
 {
 {
-       return ImageLoaderMachO::getSymbolAddress((Symbol*)sym, this, context);
+       return ImageLoaderMachO::getSymbolAddress((Symbol*)sym, this, context, runResolver);
 }
 
 uintptr_t ImageLoaderMachOClassic::resolveUndefined(const LinkContext& context, const struct macho_nlist* undefinedSymbol, 
 }
 
 uintptr_t ImageLoaderMachOClassic::resolveUndefined(const LinkContext& context, const struct macho_nlist* undefinedSymbol, 
@@ -1085,7 +1105,7 @@ uintptr_t ImageLoaderMachOClassic::resolveUndefined(const LinkContext& context,
                // flat lookup
                if ( ((undefinedSymbol->n_type & N_PEXT) != 0) && ((undefinedSymbol->n_type & N_TYPE) == N_SECT) ) {
                        // is a multi-module private_extern internal reference that the linker did not optimize away
                // flat lookup
                if ( ((undefinedSymbol->n_type & N_PEXT) != 0) && ((undefinedSymbol->n_type & N_TYPE) == N_SECT) ) {
                        // is a multi-module private_extern internal reference that the linker did not optimize away
-                       uintptr_t addr = this->getSymbolAddress(undefinedSymbol, context);
+                       uintptr_t addr = this->getSymbolAddress(undefinedSymbol, context, false);
                        *foundIn = this;
                        return addr;
                }
                        *foundIn = this;
                        return addr;
                }
@@ -1107,7 +1127,7 @@ uintptr_t ImageLoaderMachOClassic::resolveUndefined(const LinkContext& context,
                        // if reference is weak_import, then it is ok, just return 0
                        return 0;
                }
                        // if reference is weak_import, then it is ok, just return 0
                        return 0;
                }
-               throwSymbolNotFound(symbolName, this->getPath(), "flat namespace");
+               throwSymbolNotFound(context, symbolName, this->getPath(), "flat namespace");
        }
        else {
                // symbol requires searching images with coalesced symbols (not done during prebinding)
        }
        else {
                // symbol requires searching images with coalesced symbols (not done during prebinding)
@@ -1118,14 +1138,14 @@ uintptr_t ImageLoaderMachOClassic::resolveUndefined(const LinkContext& context,
                                        this->addDynamicReference(*foundIn);
                                return (*foundIn)->getExportedSymbolAddress(sym, context, this);
                        }
                                        this->addDynamicReference(*foundIn);
                                return (*foundIn)->getExportedSymbolAddress(sym, context, this);
                        }
-                       //throwSymbolNotFound(symbolName, this->getPath(), "coalesced namespace");
+                       //throwSymbolNotFound(context, symbolName, this->getPath(), "coalesced namespace");
                        //dyld::log("dyld: coalesced symbol %s not found in any coalesced image, falling back to two-level lookup", symbolName);
                }
                
                // if this is a real definition (not an undefined symbol) there is no ordinal
                if ( (undefinedSymbol->n_type & N_TYPE) == N_SECT ) {
                        // static linker should never generate this case, but if it does, do something sane
                        //dyld::log("dyld: coalesced symbol %s not found in any coalesced image, falling back to two-level lookup", symbolName);
                }
                
                // if this is a real definition (not an undefined symbol) there is no ordinal
                if ( (undefinedSymbol->n_type & N_TYPE) == N_SECT ) {
                        // static linker should never generate this case, but if it does, do something sane
-                       uintptr_t addr = this->getSymbolAddress(undefinedSymbol, context);
+                       uintptr_t addr = this->getSymbolAddress(undefinedSymbol, context, false);
                        *foundIn = this;
                        return addr;
                }
                        *foundIn = this;
                        return addr;
                }
@@ -1152,7 +1172,7 @@ uintptr_t ImageLoaderMachOClassic::resolveUndefined(const LinkContext& context,
                        if ( context.flatExportFinder(symbolName, &sym, foundIn) )
                                return (*foundIn)->getExportedSymbolAddress(sym, context, this);
                        
                        if ( context.flatExportFinder(symbolName, &sym, foundIn) )
                                return (*foundIn)->getExportedSymbolAddress(sym, context, this);
                        
-                       throwSymbolNotFound(symbolName, this->getPath(), "dynamic lookup");
+                       throwSymbolNotFound(context, symbolName, this->getPath(), "dynamic lookup");
                }
                else if ( ord <= libraryCount() ) {
                        target = libImage(ord-1);
                }
                else if ( ord <= libraryCount() ) {
                        target = libImage(ord-1);
@@ -1178,7 +1198,7 @@ uintptr_t ImageLoaderMachOClassic::resolveUndefined(const LinkContext& context,
                else if ( (undefinedSymbol->n_type & N_PEXT) != 0 ) {
                        // don't know why the static linker did not eliminate the internal reference to a private extern definition
                        *foundIn = this;
                else if ( (undefinedSymbol->n_type & N_PEXT) != 0 ) {
                        // don't know why the static linker did not eliminate the internal reference to a private extern definition
                        *foundIn = this;
-                       return this->getSymbolAddress(undefinedSymbol, context);
+                       return this->getSymbolAddress(undefinedSymbol, context, false);
                }
                else if ( (undefinedSymbol->n_desc & N_WEAK_REF) != 0 ) {
                        // if definition not found and reference is weak return 0
                }
                else if ( (undefinedSymbol->n_desc & N_WEAK_REF) != 0 ) {
                        // if definition not found and reference is weak return 0
@@ -1186,7 +1206,7 @@ uintptr_t ImageLoaderMachOClassic::resolveUndefined(const LinkContext& context,
                }
                
                // nowhere to be found
                }
                
                // nowhere to be found
-               throwSymbolNotFound(symbolName, this->getPath(), target->getPath());
+               throwSymbolNotFound(context, symbolName, this->getPath(), target->getPath());
        }
 }
 
        }
 }
 
@@ -1412,7 +1432,7 @@ uintptr_t ImageLoaderMachOClassic::bindIndirectSymbol(uintptr_t* ptrToBind, cons
        return targetAddr;
 }
 
        return targetAddr;
 }
 
-uintptr_t ImageLoaderMachOClassic::doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context)
+uintptr_t ImageLoaderMachOClassic::doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context, void (*lock)(), void (*unlock)())
 {
        throw "compressed LINKEDIT lazy binder called with classic LINKEDIT";
 }
 {
        throw "compressed LINKEDIT lazy binder called with classic LINKEDIT";
 }
@@ -1557,7 +1577,15 @@ uintptr_t ImageLoaderMachOClassic::getAddressCoalIterator(CoalIterator& it, cons
        }       
        const struct macho_nlist* sym = &fSymbolTable[symbol_index];
        //dyld::log("getAddressCoalIterator() => 0x%llX, %s symbol_index=%d, in %s\n", (uint64_t)(sym->n_value + fSlide), &fStrings[sym->n_un.n_strx], symbol_index, this->getPath());
        }       
        const struct macho_nlist* sym = &fSymbolTable[symbol_index];
        //dyld::log("getAddressCoalIterator() => 0x%llX, %s symbol_index=%d, in %s\n", (uint64_t)(sym->n_value + fSlide), &fStrings[sym->n_un.n_strx], symbol_index, this->getPath());
+#if __arm__
+               // processor assumes code address with low bit set is thumb
+               if (sym->n_desc & N_ARM_THUMB_DEF)
+                       return (sym->n_value | 1) + fSlide ;
+               else
+                       return sym->n_value + fSlide;
+#else
        return sym->n_value + fSlide;
        return sym->n_value + fSlide;
+#endif
 }
 
 
 }
 
 
@@ -1622,7 +1650,7 @@ void ImageLoaderMachOClassic::updateUsesCoalIterator(CoalIterator& it, uintptr_t
                        #if __arm__
                                                // if weak and thumb subtract off extra thumb bit
                                                if ( (undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0 )
                        #if __arm__
                                                // if weak and thumb subtract off extra thumb bit
                                                if ( (undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0 )
-                                                       addend += 1;
+                                                       addend &= -2;
                        #endif
                                        }
                                } 
                        #endif
                                        }
                                } 
@@ -1645,6 +1673,11 @@ void ImageLoaderMachOClassic::updateUsesCoalIterator(CoalIterator& it, uintptr_t
                                        // to be definition address plus addend
                                        //dyld::log("weak def, initialValue=0x%lX, undefAddr=0x%lX\n", initialValue, undefinedSymbol->n_value+fSlide);
                                        addend = initialValue - (undefinedSymbol->n_value + fSlide);
                                        // to be definition address plus addend
                                        //dyld::log("weak def, initialValue=0x%lX, undefAddr=0x%lX\n", initialValue, undefinedSymbol->n_value+fSlide);
                                        addend = initialValue - (undefinedSymbol->n_value + fSlide);
+               #if __arm__
+                                       // if weak and thumb subtract off extra thumb bit
+                                       if ( (undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0 )
+                                               addend &= -2;
+               #endif
                                }
                                else {
                                        // nothing fixed up yet, addend is just initial value
                                }
                                else {
                                        // nothing fixed up yet, addend is just initial value
@@ -1905,6 +1938,7 @@ void ImageLoaderMachOClassic::initializeLazyStubs(const LinkContext& context)
 
 void ImageLoaderMachOClassic::doBind(const LinkContext& context, bool forceLazysBound)
 {
 
 void ImageLoaderMachOClassic::doBind(const LinkContext& context, bool forceLazysBound)
 {
+       CRSetCrashLogMessage2(this->getPath());
 #if __i386__
        this->initializeLazyStubs(context);
 #endif
 #if __i386__
        this->initializeLazyStubs(context);
 #endif
@@ -1918,6 +1952,12 @@ void ImageLoaderMachOClassic::doBind(const LinkContext& context, bool forceLazys
                // no valid prebinding, so bind symbols.
                // values bound by name are stored two different ways in classic mach-o:
                
                // no valid prebinding, so bind symbols.
                // values bound by name are stored two different ways in classic mach-o:
                
+       #if TEXT_RELOC_SUPPORT
+               // if there are __TEXT fixups, temporarily make __TEXT writable
+               if ( fTextSegmentBinds ) 
+                       this->makeTextSegmentWritable(context, true);
+       #endif
+
                // 1) external relocations are used for data initialized to external symbols
                this->doBindExternalRelocations(context);
                
                // 1) external relocations are used for data initialized to external symbols
                this->doBindExternalRelocations(context);
                
@@ -1925,10 +1965,17 @@ void ImageLoaderMachOClassic::doBind(const LinkContext& context, bool forceLazys
                // if this image is in the shared cache, there is no way to reset the lazy pointers, so bind them now
                this->bindIndirectSymbolPointers(context, true, forceLazysBound || fInSharedCache);
 
                // if this image is in the shared cache, there is no way to reset the lazy pointers, so bind them now
                this->bindIndirectSymbolPointers(context, true, forceLazysBound || fInSharedCache);
 
+       #if TEXT_RELOC_SUPPORT
+               // if there were __TEXT fixups, restore write protection
+               if ( fTextSegmentBinds ) 
+                       this->makeTextSegmentWritable(context, false);
+       #endif  
        }
        
        // set up dyld entry points in image
        this->setupLazyPointerHandler(context);
        }
        
        // set up dyld entry points in image
        this->setupLazyPointerHandler(context);
+       
+       CRSetCrashLogMessage2(NULL);
 }
 
 void ImageLoaderMachOClassic::doBindJustLazies(const LinkContext& context)
 }
 
 void ImageLoaderMachOClassic::doBindJustLazies(const LinkContext& context)
@@ -1937,6 +1984,100 @@ void ImageLoaderMachOClassic::doBindJustLazies(const LinkContext& context)
        this->bindIndirectSymbolPointers(context, false, true);
 }
 
        this->bindIndirectSymbolPointers(context, false, true);
 }
 
+void ImageLoaderMachOClassic::doInterpose(const LinkContext& context)
+{
+       if ( context.verboseInterposing )
+               dyld::log("dyld: interposing %lu tuples onto: %s\n", fgInterposingTuples.size(), this->getPath());
+
+       // scan indirect symbols
+       const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
+       const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
+       const struct load_command* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               switch (cmd->cmd) {
+                       case LC_SEGMENT_COMMAND:
+                               {
+                                       const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
+                                       const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
+                                       const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
+                                       for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+                                               const uint8_t type = sect->flags & SECTION_TYPE;
+                                               if ( (type == S_NON_LAZY_SYMBOL_POINTERS) || (type == S_LAZY_SYMBOL_POINTERS) ) {
+                                                       const uint32_t pointerCount = sect->size / sizeof(uintptr_t);
+                                                       uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + fSlide);
+                                                       for (uint32_t pointerIndex=0; pointerIndex < pointerCount; ++pointerIndex) {
+                                                               for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
+                                                                       // replace all references to 'replacee' with 'replacement'
+                                                                       if ( (symbolPointers[pointerIndex] == it->replacee) && (this != it->replacementImage) ) {
+                                                                               if ( context.verboseInterposing ) {
+                                                                                       dyld::log("dyld: interposing: at %p replace 0x%lX with 0x%lX in %s\n", 
+                                                                                               &symbolPointers[pointerIndex], it->replacee, it->replacement, this->getPath());
+                                                                               }
+                                                                               symbolPointers[pointerIndex] = it->replacement;
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                               #if __i386__
+                                               // i386 has special self-modifying stubs that might be prebound to "JMP rel32" that need checking
+                                               else if ( (type == S_SYMBOL_STUBS) && ((sect->flags & S_ATTR_SELF_MODIFYING_CODE) != 0) && (sect->reserved2 == 5) ) {
+                                                       // check each jmp entry in this section
+                                                       uint8_t* start = (uint8_t*)(sect->addr + this->fSlide);
+                                                       uint8_t* end = start + sect->size;
+                                                       for (uint8_t* entry = start; entry < end; entry += 5) {
+                                                               if ( entry[0] == 0xE9 ) { // 0xE9 == JMP 
+                                                                       uint32_t rel32 = *((uint32_t*)&entry[1]); // assume unaligned load of uint32_t is ok
+                                                                       uint32_t target = (uint32_t)&entry[5] + rel32;
+                                                                       for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
+                                                                               // replace all references to 'replacee' with 'replacement'
+                                                                               if ( (it->replacee == target) && (this != it->replacementImage) ) {
+                                                                                       if ( context.verboseInterposing ) {
+                                                                                               dyld::log("dyld: interposing: at %p replace JMP 0x%lX with JMP 0x%lX in %s\n", 
+                                                                                                       &entry[1], it->replacee, it->replacement, this->getPath());
+                                                                                       }
+                                                                                       uint32_t newRel32 = it->replacement - (uint32_t)&entry[5];
+                                                                                       *((uint32_t*)&entry[1]) = newRel32; // assume unaligned store of uint32_t is ok
+                                                                               }
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                               #endif
+                                       }
+                               }
+                               break;
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+       }
+       
+       // scan external relocations 
+       const uintptr_t relocBase = this->getRelocBase();
+       const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->extreloff]);
+       const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nextrel];
+       for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
+               if (reloc->r_length == RELOC_SIZE) {
+                       switch(reloc->r_type) {
+                               case POINTER_RELOC:
+                                       {
+                                               uintptr_t* location = ((uintptr_t*)(reloc->r_address + relocBase));
+                                               for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
+                                                       // replace all references to 'replacee' with 'replacement'
+                                                       if ( (*location == it->replacee) && (this != it->replacementImage) ) {
+                                                               if ( context.verboseInterposing ) {
+                                                                       dyld::log("dyld: interposing: at %p replace 0x%lX with 0x%lX in %s\n", 
+                                                                               location, it->replacee, it->replacement, this->getPath());
+                                                               }
+                                                               *location = it->replacement;
+                                                       }
+                                               }
+                                       }
+                                       break;
+                       }
+               }
+       }
+}
+
+
 const char* ImageLoaderMachOClassic::findClosestSymbol(const void* addr, const void** closestAddr) const
 {
        uintptr_t targetAddress = (uintptr_t)addr - fSlide;
 const char* ImageLoaderMachOClassic::findClosestSymbol(const void* addr, const void** closestAddr) const
 {
        uintptr_t targetAddress = (uintptr_t)addr - fSlide;
@@ -1970,7 +2111,14 @@ const char* ImageLoaderMachOClassic::findClosestSymbol(const void* addr, const v
                }
        }
        if ( bestSymbol != NULL ) {
                }
        }
        if ( bestSymbol != NULL ) {
+#if __arm__
+               if (bestSymbol->n_desc & N_ARM_THUMB_DEF)
+                       *closestAddr = (void*)((bestSymbol->n_value | 1) + fSlide);
+               else
+                       *closestAddr = (void*)(bestSymbol->n_value + fSlide);
+#else
                *closestAddr = (void*)(bestSymbol->n_value + fSlide);
                *closestAddr = (void*)(bestSymbol->n_value + fSlide);
+#endif
                return &fStrings[bestSymbol->n_un.n_strx];
        }
        return NULL;
                return &fStrings[bestSymbol->n_un.n_strx];
        }
        return NULL;
index 6a339ec869a94a6d321a4282d01968b6d3dc5659..5d766508a0e6ca8a1d833dc0002e7c48bc5a675e 100644 (file)
@@ -41,8 +41,9 @@ public:
                                                                                                                                        unsigned int segCount, unsigned int libCount, const LinkContext& context);
        static ImageLoaderMachOClassic*         instantiateFromFile(const char* path, int fd, const uint8_t* fileData, 
                                                                                                                        uint64_t offsetInFat, uint64_t lenInFat, const struct stat& info, 
                                                                                                                                        unsigned int segCount, unsigned int libCount, const LinkContext& context);
        static ImageLoaderMachOClassic*         instantiateFromFile(const char* path, int fd, const uint8_t* fileData, 
                                                                                                                        uint64_t offsetInFat, uint64_t lenInFat, const struct stat& info, 
-                                                                                                                       unsigned int segCount, unsigned int libCount, const LinkContext& context);
-       static ImageLoaderMachOClassic*         instantiateFromCache(const macho_header* mh, const char* path, const struct stat& info,
+                                                                                                                       unsigned int segCount, unsigned int libCount, 
+                                                                                                                       const struct linkedit_data_command* codeSigCmd, const LinkContext& context);
+       static ImageLoaderMachOClassic*         instantiateFromCache(const macho_header* mh, const char* path, long slide, const struct stat& info,
                                                                                                                                unsigned int segCount, unsigned int libCount, const LinkContext& context);
        static ImageLoaderMachOClassic*         instantiateFromMemory(const char* moduleName, const macho_header* mh, uint64_t len, 
                                                                                                                        unsigned int segCount, unsigned int libCount, const LinkContext& context);
                                                                                                                                unsigned int segCount, unsigned int libCount, const LinkContext& context);
        static ImageLoaderMachOClassic*         instantiateFromMemory(const char* moduleName, const macho_header* mh, uint64_t len, 
                                                                                                                        unsigned int segCount, unsigned int libCount, const LinkContext& context);
@@ -51,11 +52,12 @@ public:
 
        virtual ImageLoader*                            libImage(unsigned int) const;
        virtual bool                                            libReExported(unsigned int) const;
 
        virtual ImageLoader*                            libImage(unsigned int) const;
        virtual bool                                            libReExported(unsigned int) const;
-       virtual void                                            setLibImage(unsigned int, ImageLoader*, bool);
+       virtual bool                                            libIsUpward(unsigned int) const;
+       virtual void                                            setLibImage(unsigned int, ImageLoader*, bool, bool);
        virtual void                                            doBind(const LinkContext& context, bool forceLazysBound);
        virtual void                                            doBindJustLazies(const LinkContext& context);
        virtual uintptr_t                                       doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context);
        virtual void                                            doBind(const LinkContext& context, bool forceLazysBound);
        virtual void                                            doBindJustLazies(const LinkContext& context);
        virtual uintptr_t                                       doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context);
-       virtual uintptr_t                                       doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context);
+       virtual uintptr_t                                       doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context, void (*lock)(), void (*unlock)());
        virtual const char*                                     findClosestSymbol(const void* addr, const void** closestAddr) const;
        virtual void                                            initializeCoalIterator(CoalIterator&, unsigned int loadOrder);
        virtual bool                                            incrementCoalIterator(CoalIterator&);
        virtual const char*                                     findClosestSymbol(const void* addr, const void** closestAddr) const;
        virtual void                                            initializeCoalIterator(CoalIterator&, unsigned int loadOrder);
        virtual bool                                            incrementCoalIterator(CoalIterator&);
@@ -63,6 +65,7 @@ public:
        virtual void                                            updateUsesCoalIterator(CoalIterator&, uintptr_t newAddr, ImageLoader* target, const LinkContext& context);
 
 protected:
        virtual void                                            updateUsesCoalIterator(CoalIterator&, uintptr_t newAddr, ImageLoader* target, const LinkContext& context);
 
 protected:
+       virtual void                                            doInterpose(const LinkContext& context);
        virtual void                                            setDyldInfo(const dyld_info_command*) {}
        virtual void                                            setSymbolTableInfo(const macho_nlist*, const char*, const dysymtab_command*);
        virtual bool                                            isSubframeworkOf(const LinkContext& context, const ImageLoader* image) const;
        virtual void                                            setDyldInfo(const dyld_info_command*) {}
        virtual void                                            setSymbolTableInfo(const macho_nlist*, const char*, const dysymtab_command*);
        virtual bool                                            isSubframeworkOf(const LinkContext& context, const ImageLoader* image) const;
@@ -71,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 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 Symbol* symbol) const;
+       virtual uintptr_t                                       exportedSymbolAddress(const LinkContext& context, const Symbol* symbol, bool runResolver) const;
        virtual bool                                            exportedSymbolIsWeakDefintion(const Symbol* symbol) const;
        virtual const char*                                     exportedSymbolName(const Symbol* symbol) const;
        virtual unsigned int                            exportedSymbolCount() const;
        virtual bool                                            exportedSymbolIsWeakDefintion(const Symbol* symbol) const;
        virtual const char*                                     exportedSymbolName(const Symbol* symbol) const;
        virtual unsigned int                            exportedSymbolCount() const;
@@ -99,7 +102,7 @@ private:
        static  bool                                            symbolIsWeakDefinition(const struct macho_nlist* symbol); 
        uintptr_t                                                       resolveUndefined(const LinkContext& context, const struct macho_nlist* symbol, bool twoLevel, 
                                                                                                                        bool dontCoalesce, const ImageLoader **foundIn);
        static  bool                                            symbolIsWeakDefinition(const struct macho_nlist* symbol); 
        uintptr_t                                                       resolveUndefined(const LinkContext& context, const struct macho_nlist* symbol, bool twoLevel, 
                                                                                                                        bool dontCoalesce, const ImageLoader **foundIn);
-       uintptr_t                                                       getSymbolAddress(const macho_nlist*, const LinkContext& context) const;
+       uintptr_t                                                       getSymbolAddress(const macho_nlist*, const LinkContext& context, bool runResolver) const;
        bool                                                            isAddrInSection(uintptr_t addr, uint8_t sectionIndex);
        void                                                            doBindExternalRelocations(const LinkContext& context);
        uintptr_t                                                       bindIndirectSymbol(uintptr_t* ptrToBind, const struct macho_section* sect, 
        bool                                                            isAddrInSection(uintptr_t addr, uint8_t sectionIndex);
        void                                                            doBindExternalRelocations(const LinkContext& context);
        uintptr_t                                                       bindIndirectSymbol(uintptr_t* ptrToBind, const struct macho_section* sect, 
index 7d3812bd6617cb174c7be99243b07498bbf7aad6..dda3e8af74dfc2c370bea6c486f717287066d5c8 100644 (file)
@@ -67,14 +67,13 @@ static uintptr_t read_uleb128(const uint8_t*& p, const uint8_t* end)
 
                uint64_t slice = *p & 0x7f;
 
 
                uint64_t slice = *p & 0x7f;
 
-               if (bit >= 64 || slice << bit >> bit != slice)
-                       dyld::throwf("uleb128 too big");
+               if (bit > 63)
+                       dyld::throwf("uleb128 too big for uint64, bit=%d, result=0x%0llX", bit, result);
                else {
                        result |= (slice << bit);
                        bit += 7;
                }
                else {
                        result |= (slice << bit);
                        bit += 7;
                }
-       } 
-       while (*p++ & 0x80);
+       } while (*p++ & 0x80);
        return result;
 }
 
        return result;
 }
 
@@ -108,11 +107,12 @@ ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateMainExecutabl
        image->setSlide(slide);
 
        // for PIE record end of program, to know where to start loading dylibs
        image->setSlide(slide);
 
        // for PIE record end of program, to know where to start loading dylibs
-       if ( (mh->flags & MH_PIE) && !context.noPIE )
+       if ( slide != 0 )
                fgNextPIEDylibAddress = (uintptr_t)image->getEnd();
        
        image->setNeverUnload();
        image->instantiateFinish(context);
                fgNextPIEDylibAddress = (uintptr_t)image->getEnd();
        
        image->setNeverUnload();
        image->instantiateFinish(context);
+       image->setMapped(context);
        
        if ( context.verboseMapping ) {
                dyld::log("dyld: Main executable mapped %s\n", path);
        
        if ( context.verboseMapping ) {
                dyld::log("dyld: Main executable mapped %s\n", path);
@@ -131,7 +131,8 @@ ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateMainExecutabl
 // create image by mapping in a mach-o file
 ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromFile(const char* path, int fd, const uint8_t* fileData, 
                                                                                                                        uint64_t offsetInFat, uint64_t lenInFat, const struct stat& info, 
 // create image by mapping in a mach-o file
 ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromFile(const char* path, int fd, const uint8_t* fileData, 
                                                                                                                        uint64_t offsetInFat, uint64_t lenInFat, const struct stat& info, 
-                                                                                                                       unsigned int segCount, unsigned int libCount, const LinkContext& context)
+                                                                                                                       unsigned int segCount, unsigned int libCount, 
+                                                                                                                       const struct linkedit_data_command* codeSigCmd, const LinkContext& context)
 {
        ImageLoaderMachOCompressed* image = ImageLoaderMachOCompressed::instantiateStart((macho_header*)fileData, path, segCount, libCount);
 
 {
        ImageLoaderMachOCompressed* image = ImageLoaderMachOCompressed::instantiateStart((macho_header*)fileData, path, segCount, libCount);
 
@@ -139,6 +140,12 @@ ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromFile(cons
                // record info about file  
                image->setFileInfo(info.st_dev, info.st_ino, info.st_mtime);
 
                // 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
+               
                // mmap segments
                image->mapSegments(fd, offsetInFat, lenInFat, info.st_size, context);
 
                // mmap segments
                image->mapSegments(fd, offsetInFat, lenInFat, info.st_size, context);
 
@@ -165,6 +172,9 @@ ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromFile(cons
                else 
                        image->setPath(path);
 
                else 
                        image->setPath(path);
 
+               // make sure path is stable before recording in dyld_all_image_infos
+               image->setMapped(context);
+
                // pre-fetch content of __DATA and __LINKEDIT segment for faster launches
                // don't do this on prebound images or if prefetching is disabled
         if ( !context.preFetchDisabled && !image->isPrebindable()) {
                // pre-fetch content of __DATA and __LINKEDIT segment for faster launches
                // don't do this on prebound images or if prefetching is disabled
         if ( !context.preFetchDisabled && !image->isPrebindable()) {
@@ -183,8 +193,9 @@ ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromFile(cons
 }
 
 // create image by using cached mach-o file
 }
 
 // create image by using cached mach-o file
-ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromCache(const macho_header* mh, const char* path, const struct stat& info,
-                                                                                                                               unsigned int segCount, unsigned int libCount, const LinkContext& context)
+ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromCache(const macho_header* mh, const char* path, long slide,
+                                                                                                                                               const struct stat& info, unsigned int segCount,
+                                                                                                                                               unsigned int libCount, const LinkContext& context)
 {
        ImageLoaderMachOCompressed* image = ImageLoaderMachOCompressed::instantiateStart(mh, path, segCount, libCount);
        try {
 {
        ImageLoaderMachOCompressed* image = ImageLoaderMachOCompressed::instantiateStart(mh, path, segCount, libCount);
        try {
@@ -193,7 +204,9 @@ ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromCache(con
 
                // remember this is from shared cache and cannot be unloaded
                image->fInSharedCache = true;
 
                // remember this is from shared cache and cannot be unloaded
                image->fInSharedCache = true;
+               image->fGoodFirstSegment = true;
                image->setNeverUnload();
                image->setNeverUnload();
+               image->setSlide(slide);
 
                // segments already mapped in cache
                if ( context.verboseMapping ) {
 
                // segments already mapped in cache
                if ( context.verboseMapping ) {
@@ -204,6 +217,7 @@ ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromCache(con
                }
 
                image->instantiateFinish(context);
                }
 
                image->instantiateFinish(context);
+               image->setMapped(context);
        }
        catch (...) {
                // ImageLoader::setMapped() can throw an exception to block loading of image
        }
        catch (...) {
                // ImageLoader::setMapped() can throw an exception to block loading of image
@@ -236,6 +250,7 @@ ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromMemory(co
                        image->setPath(moduleName);
 
                image->instantiateFinish(context);
                        image->setPath(moduleName);
 
                image->instantiateFinish(context);
+               image->setMapped(context);
        }
        catch (...) {
                // ImageLoader::setMapped() can throw an exception to block loading of image
        }
        catch (...) {
                // ImageLoader::setMapped() can throw an exception to block loading of image
@@ -281,9 +296,6 @@ void ImageLoaderMachOCompressed::instantiateFinish(const LinkContext& context)
 {
        // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
        this->parseLoadCmds();
 {
        // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
        this->parseLoadCmds();
-               
-       // notify state change
-       this->setMapped(context);
 }
 
 uint32_t* ImageLoaderMachOCompressed::segmentCommandOffsets() const
 }
 
 uint32_t* ImageLoaderMachOCompressed::segmentCommandOffsets() const
@@ -295,8 +307,8 @@ uint32_t* ImageLoaderMachOCompressed::segmentCommandOffsets() const
 ImageLoader* ImageLoaderMachOCompressed::libImage(unsigned int libIndex) const
 {
        const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed) + fSegmentsCount*sizeof(uint32_t)));
 ImageLoader* ImageLoaderMachOCompressed::libImage(unsigned int libIndex) const
 {
        const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed) + fSegmentsCount*sizeof(uint32_t)));
-       // mask off low bit
-       return (ImageLoader*)(images[libIndex] & (-2));
+       // mask off low bits
+       return (ImageLoader*)(images[libIndex] & (-4));
 }
 
 bool ImageLoaderMachOCompressed::libReExported(unsigned int libIndex) const
 }
 
 bool ImageLoaderMachOCompressed::libReExported(unsigned int libIndex) const
@@ -306,13 +318,22 @@ bool ImageLoaderMachOCompressed::libReExported(unsigned int libIndex) const
        return ((images[libIndex] & 1) != 0);
 }      
 
        return ((images[libIndex] & 1) != 0);
 }      
 
+bool ImageLoaderMachOCompressed::libIsUpward(unsigned int libIndex) const
+{
+       const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed) + fSegmentsCount*sizeof(uint32_t)));
+       // re-export flag is second bit
+       return ((images[libIndex] & 2) != 0);
+}      
+
 
 
-void ImageLoaderMachOCompressed::setLibImage(unsigned int libIndex, ImageLoader* image, bool reExported)
+void ImageLoaderMachOCompressed::setLibImage(unsigned int libIndex, ImageLoader* image, bool reExported, bool upward)
 {
        uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed) + fSegmentsCount*sizeof(uint32_t)));
        uintptr_t value = (uintptr_t)image;
        if ( reExported ) 
                value |= 1;
 {
        uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed) + fSegmentsCount*sizeof(uint32_t)));
        uintptr_t value = (uintptr_t)image;
        if ( reExported ) 
                value |= 1;
+       if ( upward ) 
+               value |= 2;
        images[libIndex] = value;
 }
 
        images[libIndex] = value;
 }
 
@@ -364,7 +385,7 @@ void ImageLoaderMachOCompressed::markLINKEDIT(const LinkContext& context, int ad
                const char* adstr = "sequential";
                if ( advise == MADV_FREE )
                        adstr = "free";
                const char* adstr = "sequential";
                if ( advise == MADV_FREE )
                        adstr = "free";
-               dyld::log("%18s %s 0x%0lX -> 0x%0lX\n", "__LINKEDIT", adstr, start, end-1);
+               dyld::log("%18s %s 0x%0lX -> 0x%0lX for %s\n", "__LINKEDIT", adstr, start, end-1, this->getPath());
        }
 }
 
        }
 }
 
@@ -396,6 +417,7 @@ void ImageLoaderMachOCompressed::throwBadRebaseAddress(uintptr_t address, uintpt
 
 void ImageLoaderMachOCompressed::rebase(const LinkContext& context)
 {
 
 void ImageLoaderMachOCompressed::rebase(const LinkContext& context)
 {
+       CRSetCrashLogMessage2(this->getPath());
        const uintptr_t slide = this->fSlide;
        const uint8_t* const start = fLinkEditBase + fDyldInfo->rebase_off;
        const uint8_t* const end = &start[fDyldInfo->rebase_size];
        const uintptr_t slide = this->fSlide;
        const uint8_t* const start = fLinkEditBase + fDyldInfo->rebase_off;
        const uint8_t* const end = &start[fDyldInfo->rebase_size];
@@ -481,70 +503,117 @@ void ImageLoaderMachOCompressed::rebase(const LinkContext& context)
                free((void*)msg);
                throw newMsg;
        }
                free((void*)msg);
                throw newMsg;
        }
+       CRSetCrashLogMessage2(NULL);
 }
 
 }
 
-
-
-
-const ImageLoader::Symbol* ImageLoaderMachOCompressed::findExportedSymbol(const char* symbol, const ImageLoader** foundIn) const
+//
+// This function is the hotspot of symbol lookup.  It was pulled out of findExportedSymbol()
+// to enable it to be re-written in assembler if needed.
+//
+const uint8_t* ImageLoaderMachOCompressed::trieWalk(const uint8_t* start, const uint8_t* end, const char* s)
 {
 {
-       //dyld::log("findExportedSymbolCompressed(%s) in %s\n", symbol, this->getShortName());
-       if ( fDyldInfo->export_size == 0 )
-               return NULL;
-       ++ImageLoaderMachO::fgSymbolTrieSearchs;
-       const uint8_t* start = &fLinkEditBase[fDyldInfo->export_off];
-       const uint8_t* end = &start[fDyldInfo->export_size];
        const uint8_t* p = start;
        const uint8_t* p = start;
-       const char* s = symbol;
-       do {
-               const uint8_t terminalSize = *p++;
-               const uint8_t* children = p + terminalSize;
+       while ( p != NULL ) {
+               uint32_t terminalSize = *p++;
+               if ( terminalSize > 127 ) {
+                       // except for re-export-with-rename, all terminal sizes fit in one byte
+                       --p;
+                       terminalSize = read_uleb128(p, end);
+               }
                if ( (*s == '\0') && (terminalSize != 0) ) {
                if ( (*s == '\0') && (terminalSize != 0) ) {
-                       // found match, return pointer to terminal part of node
-                       //dyld::log("findExportedSymbol(%s) in %s found match, returning %p\n", symbol, this->getShortName(), p);
-                       if ( foundIn != NULL )
-                               *foundIn = (ImageLoader*)this;          
-                       return (Symbol*)p;
+                       //dyld::log("trieWalk(%p) returning %p\n", start, p);
+                       return p;
                }
                }
-               const uint8_t childrenCount = *children++;
-               const uint8_t* e = children;
-               const uint8_t* newNode = NULL;
-               for (uint8_t i=0; i < childrenCount; ++i) {
+               const uint8_t* children = p + terminalSize;
+               //dyld::log("trieWalk(%p) sym=%s, terminalSize=%d, children=%p\n", start, s, terminalSize, children);
+               uint8_t childrenRemaining = *children++;
+               p = children;
+               uint32_t nodeOffset = 0;
+               for (; childrenRemaining > 0; --childrenRemaining) {
                        const char* ss = s;
                        const char* ss = s;
+                       //dyld::log("trieWalk(%p) child str=%s\n", start, (char*)p);
                        bool wrongEdge = false;
                        bool wrongEdge = false;
-                       //dyld::log("findExportedSymbol() looking at edge %s for match to %s\n", e, s);
                        // scan whole edge to get to next edge
                        // if edge is longer than target symbol name, don't read past end of symbol name
                        // scan whole edge to get to next edge
                        // if edge is longer than target symbol name, don't read past end of symbol name
-                       while ( *e != '\0' ) {
+                       char c = *p;
+                       while ( c != '\0' ) {
                                if ( !wrongEdge ) {
                                if ( !wrongEdge ) {
-                                       if ( *e != *ss++ )
+                                       if ( c != *ss )
                                                wrongEdge = true;
                                                wrongEdge = true;
+                                       ++ss;
                                }
                                }
-                               ++e;
+                               ++p;
+                               c = *p;
                        }
                        if ( wrongEdge ) {
                                // advance to next child
                        }
                        if ( wrongEdge ) {
                                // advance to next child
-                               ++e;
-                               read_uleb128(e, end);
+                               ++p; // skip over zero terminator
+                               // skip over uleb128 until last byte is found
+                               while ( (*p & 0x80) != 0 )
+                                       ++p;
+                               ++p; // skil over last byte of uleb128
                        }
                        else {
                        }
                        else {
-                               // the symbol so far matches this edge (child)
+                               // the symbol so far matches this edge (child)
                                // so advance to the child's node
                                // so advance to the child's node
-                               ++e;
-                               uint32_t nodeOffset = read_uleb128(e, end);
-                               newNode = &start[nodeOffset];
+                               ++p;
+                               nodeOffset = read_uleb128(p, end);
                                s = ss;
                                s = ss;
-                               //dyld::log("findExportedSymbol() found matching edge advancing to node 0x%x\n", nodeOffset);
+                               //dyld::log("trieWalk() found matching edge advancing to node 0x%x\n", nodeOffset);
                                break;
                        }
                }
                                break;
                        }
                }
-               if ( newNode != NULL )
-                       p = newNode;
+               if ( nodeOffset != 0 )
+                       p = &start[nodeOffset];
+               else
+                       p = NULL;
+       }
+       //dyld::log("trieWalk(%p) return NULL\n", start);
+       return NULL;
+}
+
+
+const ImageLoader::Symbol* ImageLoaderMachOCompressed::findExportedSymbol(const char* symbol, const ImageLoader** foundIn) const
+{
+       //dyld::log("Compressed::findExportedSymbol(%s) in %s\n", symbol, this->getShortName());
+       if ( fDyldInfo->export_size == 0 )
+               return NULL;
+#if LOG_BINDINGS
+       dyld::logBindings("%s: %s\n", this->getShortName(), symbol);
+#endif
+       ++ImageLoaderMachO::fgSymbolTrieSearchs;
+       const uint8_t* start = &fLinkEditBase[fDyldInfo->export_off];
+       const uint8_t* end = &start[fDyldInfo->export_size];
+       const uint8_t* foundNodeStart = this->trieWalk(start, end, symbol); 
+       if ( foundNodeStart != NULL ) {
+               const uint8_t* p = foundNodeStart;
+               const uint32_t flags = read_uleb128(p, end);
+               // found match, return pointer to terminal part of node
+               if ( flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
+                       // re-export from another dylib, lookup there
+                       const uint32_t ordinal = read_uleb128(p, end);
+                       const char* importedName = (char*)p;
+                       if ( importedName[0] == '\0' )
+                               importedName = symbol;
+                       if ( (ordinal > 0) && (ordinal <= libraryCount()) ) {
+                               const ImageLoader* reexportedFrom = libImage(ordinal-1);
+                               //dyld::log("Compressed::findExportedSymbol(), %s -> %s/%s\n", symbol, reexportedFrom->getShortName(), importedName);
+                               return reexportedFrom->findExportedSymbol(importedName, true, foundIn);
+                       }
+                       else {
+                               //dyld::throwf("bad mach-o binary, library ordinal (%u) invalid (max %u) for re-exported symbol %s in %s",
+                               //      ordinal, libraryCount(), symbol, this->getPath());
+                       }
+               }
                else {
                else {
-                       //dyld::log("findExportedSymbol(%s) in %s failed\n", symbol, this->getShortName());
-                       return NULL;
+                       //dyld::log("findExportedSymbol(%s) in %s found match, returning %p\n", symbol, this->getShortName(), p);
+                       if ( foundIn != NULL )
+                               *foundIn = (ImageLoader*)this;          
+                       // return pointer to terminal part of node
+                       return (Symbol*)foundNodeStart;
                }
                }
-       } while ( true );
+       }
+       return NULL;
 }
 
 
 }
 
 
@@ -556,18 +625,35 @@ bool ImageLoaderMachOCompressed::containsSymbol(const void* addr) const
 }
 
 
 }
 
 
-uintptr_t ImageLoaderMachOCompressed::exportedSymbolAddress(const Symbol* symbol) const
+uintptr_t ImageLoaderMachOCompressed::exportedSymbolAddress(const LinkContext& context, const Symbol* symbol, bool runResolver) const
 {
        const uint8_t* exportNode = (uint8_t*)symbol;
        const uint8_t* exportTrieStart = fLinkEditBase + fDyldInfo->export_off;
        const uint8_t* exportTrieEnd = exportTrieStart + fDyldInfo->export_size;
        if ( (exportNode < exportTrieStart) || (exportNode > exportTrieEnd) )
                throw "symbol is not in trie";
 {
        const uint8_t* exportNode = (uint8_t*)symbol;
        const uint8_t* exportTrieStart = fLinkEditBase + fDyldInfo->export_off;
        const uint8_t* exportTrieEnd = exportTrieStart + fDyldInfo->export_size;
        if ( (exportNode < exportTrieStart) || (exportNode > exportTrieEnd) )
                throw "symbol is not in trie";
+       //dyld::log("exportedSymbolAddress(): node=%p, nodeOffset=0x%04X in %s\n", symbol, (int)((uint8_t*)symbol - exportTrieStart), this->getShortName());
        uint32_t flags = read_uleb128(exportNode, exportTrieEnd);
        uint32_t flags = read_uleb128(exportNode, exportTrieEnd);
-       if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_REGULAR )
+       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
+                       read_uleb128(exportNode, exportTrieEnd); // skip over stub
+                       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 )
+                       dyld::throwf("unsupported exported symbol kind. flags=%d at node=%p", flags, symbol);
                return read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)fMachOData;
                return read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)fMachOData;
+       }
        else
        else
-               throw "unsupported exported symbol kind";
+               dyld::throwf("unsupported exported symbol kind. flags=%d at node=%p", flags, symbol);
 }
 
 bool ImageLoaderMachOCompressed::exportedSymbolIsWeakDefintion(const Symbol* symbol) const
 }
 
 bool ImageLoaderMachOCompressed::exportedSymbolIsWeakDefintion(const Symbol* symbol) const
@@ -614,36 +700,37 @@ const char* ImageLoaderMachOCompressed::importedSymbolName(const Symbol* symbol)
 
 
 
 
 
 
-uintptr_t ImageLoaderMachOCompressed::resolveFlat(const LinkContext& context, const char* symbolName, bool weak_import, const ImageLoader** foundIn)
+uintptr_t ImageLoaderMachOCompressed::resolveFlat(const LinkContext& context, const char* symbolName, bool weak_import, 
+                                                                                                       bool runResolver, const ImageLoader** foundIn)
 {
        const Symbol* sym;
        if ( context.flatExportFinder(symbolName, &sym, foundIn) ) {
                if ( (*foundIn != this) && !(*foundIn)->neverUnload() )
                                this->addDynamicReference(*foundIn);
 {
        const Symbol* sym;
        if ( context.flatExportFinder(symbolName, &sym, foundIn) ) {
                if ( (*foundIn != this) && !(*foundIn)->neverUnload() )
                                this->addDynamicReference(*foundIn);
-               return (*foundIn)->getExportedSymbolAddress(sym, context, this);
+               return (*foundIn)->getExportedSymbolAddress(sym, context, this, runResolver);
        }
        // if a bundle is loaded privately the above will not find its exports
        if ( this->isBundle() && this->hasHiddenExports() ) {
                // look in self for needed symbol
                sym = this->ImageLoaderMachO::findExportedSymbol(symbolName, false, foundIn);
                if ( sym != NULL )
        }
        // if a bundle is loaded privately the above will not find its exports
        if ( this->isBundle() && this->hasHiddenExports() ) {
                // look in self for needed symbol
                sym = this->ImageLoaderMachO::findExportedSymbol(symbolName, false, foundIn);
                if ( sym != NULL )
-                       return (*foundIn)->getExportedSymbolAddress(sym, context, this);
+                       return (*foundIn)->getExportedSymbolAddress(sym, context, this, runResolver);
        }
        if ( weak_import ) {
                // definition can't be found anywhere, ok because it is weak, just return 0
                return 0;
        }
        }
        if ( weak_import ) {
                // definition can't be found anywhere, ok because it is weak, just return 0
                return 0;
        }
-       throwSymbolNotFound(symbolName, this->getPath(), "flat namespace");
+       throwSymbolNotFound(context, symbolName, this->getPath(), "flat namespace");
 }
 
 
 uintptr_t ImageLoaderMachOCompressed::resolveTwolevel(const LinkContext& context, const ImageLoader* targetImage, bool weak_import, 
 }
 
 
 uintptr_t ImageLoaderMachOCompressed::resolveTwolevel(const LinkContext& context, const ImageLoader* targetImage, bool weak_import, 
-                                                                                               const char* symbolName, const ImageLoader** foundIn)
+                                                                                               const char* symbolName, bool runResolver, const ImageLoader** foundIn)
 {
        // two level lookup
        const Symbol* sym = targetImage->findExportedSymbol(symbolName, true, foundIn);
        if ( sym != NULL ) {
 {
        // two level lookup
        const Symbol* sym = targetImage->findExportedSymbol(symbolName, true, foundIn);
        if ( sym != NULL ) {
-               return (*foundIn)->getExportedSymbolAddress(sym, context, this);
+               return (*foundIn)->getExportedSymbolAddress(sym, context, this, runResolver);
        }
        
        if ( weak_import ) {
        }
        
        if ( weak_import ) {
@@ -652,13 +739,13 @@ uintptr_t ImageLoaderMachOCompressed::resolveTwolevel(const LinkContext& context
        }
 
        // nowhere to be found
        }
 
        // nowhere to be found
-       throwSymbolNotFound(symbolName, this->getPath(), targetImage->getPath());
+       throwSymbolNotFound(context, symbolName, this->getPath(), targetImage->getPath());
 }
 
 
 uintptr_t ImageLoaderMachOCompressed::resolve(const LinkContext& context, const char* symbolName, 
                                                                                                        uint8_t symboFlags, int libraryOrdinal, const ImageLoader** targetImage,
 }
 
 
 uintptr_t ImageLoaderMachOCompressed::resolve(const LinkContext& context, const char* symbolName, 
                                                                                                        uint8_t symboFlags, int libraryOrdinal, const ImageLoader** targetImage,
-                                                                                                       LastLookup* last)
+                                                                                                       LastLookup* last, bool runResolver)
 {
        *targetImage = NULL;
        
 {
        *targetImage = NULL;
        
@@ -675,7 +762,7 @@ uintptr_t ImageLoaderMachOCompressed::resolve(const LinkContext& context, const
        bool weak_import = (symboFlags & BIND_SYMBOL_FLAGS_WEAK_IMPORT);
        uintptr_t symbolAddress;
        if ( context.bindFlat || (libraryOrdinal == BIND_SPECIAL_DYLIB_FLAT_LOOKUP) ) {
        bool weak_import = (symboFlags & BIND_SYMBOL_FLAGS_WEAK_IMPORT);
        uintptr_t symbolAddress;
        if ( context.bindFlat || (libraryOrdinal == BIND_SPECIAL_DYLIB_FLAT_LOOKUP) ) {
-               symbolAddress = this->resolveFlat(context, symbolName, weak_import, targetImage);
+               symbolAddress = this->resolveFlat(context, symbolName, weak_import, runResolver, targetImage);
        }
        else {
                if ( libraryOrdinal == BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE ) {
        }
        else {
                if ( libraryOrdinal == BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE ) {
@@ -706,7 +793,7 @@ uintptr_t ImageLoaderMachOCompressed::resolve(const LinkContext& context, const
                        }
                }
                else {
                        }
                }
                else {
-                       symbolAddress = resolveTwolevel(context, *targetImage, weak_import, symbolName, targetImage);
+                       symbolAddress = resolveTwolevel(context, *targetImage, weak_import, symbolName, runResolver, targetImage);
                }
        }
        
                }
        }
        
@@ -723,13 +810,14 @@ uintptr_t ImageLoaderMachOCompressed::resolve(const LinkContext& context, const
 }
 
 uintptr_t ImageLoaderMachOCompressed::bindAt(const LinkContext& context, uintptr_t addr, uint8_t type, const char* symbolName, 
 }
 
 uintptr_t ImageLoaderMachOCompressed::bindAt(const LinkContext& context, uintptr_t addr, uint8_t type, const char* symbolName, 
-                                                               uint8_t symboFlags, intptr_t addend, int libraryOrdinal, const char* msg, LastLookup* last)
+                                                               uint8_t symboFlags, intptr_t addend, int libraryOrdinal, const char* msg, 
+                                                               LastLookup* last, bool runResolver)
 {
        const ImageLoader*      targetImage;
        uintptr_t                       symbolAddress;
        
        // resolve symbol
 {
        const ImageLoader*      targetImage;
        uintptr_t                       symbolAddress;
        
        // resolve symbol
-       symbolAddress = this->resolve(context, symbolName, symboFlags, libraryOrdinal, &targetImage, last);
+       symbolAddress = this->resolve(context, symbolName, symboFlags, libraryOrdinal, &targetImage, last, runResolver);
 
        // do actual update
        return this->bindLocation(context, addr, symbolAddress, targetImage, type, symbolName, addend, msg);
 
        // do actual update
        return this->bindLocation(context, addr, symbolAddress, targetImage, type, symbolName, addend, msg);
@@ -746,28 +834,50 @@ void ImageLoaderMachOCompressed::throwBadBindingAddress(uintptr_t address, uintp
 
 void ImageLoaderMachOCompressed::doBind(const LinkContext& context, bool forceLazysBound)
 {
 
 void ImageLoaderMachOCompressed::doBind(const LinkContext& context, bool forceLazysBound)
 {
+       CRSetCrashLogMessage2(this->getPath());
+
        // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
        // note: flat-namespace binaries need to have imports rebound (even if correctly prebound)
        if ( this->usablePrebinding(context) ) {
                // don't need to bind
        }
        else {
        // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
        // note: flat-namespace binaries need to have imports rebound (even if correctly prebound)
        if ( this->usablePrebinding(context) ) {
                // don't need to bind
        }
        else {
+       
+       #if TEXT_RELOC_SUPPORT
+               // if there are __TEXT fixups, temporarily make __TEXT writable
+               if ( fTextSegmentBinds ) 
+                       this->makeTextSegmentWritable(context, true);
+       #endif
+       
                // run through all binding opcodes
                eachBind(context, &ImageLoaderMachOCompressed::bindAt);
                        
                // run through all binding opcodes
                eachBind(context, &ImageLoaderMachOCompressed::bindAt);
                        
-               // if this image is in the shared cache, but depends on someting no longer in the shared cache,
+       #if TEXT_RELOC_SUPPORT
+               // if there were __TEXT fixups, restore write protection
+               if ( fTextSegmentBinds ) 
+                       this->makeTextSegmentWritable(context, false);
+       #endif  
+       
+               // if this image is in the shared cache, but depends on something no longer in the shared cache,
                // there is no way to reset the lazy pointers, so force bind them now
                // there is no way to reset the lazy pointers, so force bind them now
-               if ( forceLazysBound || fInSharedCache )
+               if ( forceLazysBound || fInSharedCache ) 
                        this->doBindJustLazies(context);
                        this->doBindJustLazies(context);
+            
+               // this image is in cache, but something below it is not.  If
+        // this image has lazy pointer to a resolver function, then
+        // the stub may have been altered to point to a shared lazy pointer.
+               if ( fInSharedCache ) 
+                       this->updateOptimizedLazyPointers(context);
+       
+               // tell kernel we are done with chunks of LINKEDIT
+               if ( !context.preFetchDisabled ) 
+                       this->markFreeLINKEDIT(context);
        }
        
        // set up dyld entry points in image
        // do last so flat main executables will have __dyld or __program_vars set up
        this->setupLazyPointerHandler(context);
        }
        
        // set up dyld entry points in image
        // do last so flat main executables will have __dyld or __program_vars set up
        this->setupLazyPointerHandler(context);
-       
-       // tell kernel we are done with chunks of LINKEDIT
-       if ( !context.preFetchDisabled ) 
-               this->markFreeLINKEDIT(context);
+       CRSetCrashLogMessage2(NULL);
 }
 
 
 }
 
 
@@ -844,19 +954,19 @@ void ImageLoaderMachOCompressed::eachBind(const LinkContext& context, bind_handl
                                case BIND_OPCODE_DO_BIND:
                                        if ( address >= segmentEndAddress ) 
                                                throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
                                case BIND_OPCODE_DO_BIND:
                                        if ( address >= segmentEndAddress ) 
                                                throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
-                                       (this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "", &last);
+                                       (this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "", &last, false);
                                        address += sizeof(intptr_t);
                                        break;
                                case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
                                        if ( address >= segmentEndAddress ) 
                                                throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
                                        address += sizeof(intptr_t);
                                        break;
                                case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
                                        if ( address >= segmentEndAddress ) 
                                                throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
-                                       (this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "", &last);
+                                       (this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "", &last, false);
                                        address += read_uleb128(p, end) + sizeof(intptr_t);
                                        break;
                                case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
                                        if ( address >= segmentEndAddress ) 
                                                throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
                                        address += read_uleb128(p, end) + sizeof(intptr_t);
                                        break;
                                case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
                                        if ( address >= segmentEndAddress ) 
                                                throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
-                                       (this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "", &last);
+                                       (this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "", &last, false);
                                        address += immediate*sizeof(intptr_t) + sizeof(intptr_t);
                                        break;
                                case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
                                        address += immediate*sizeof(intptr_t) + sizeof(intptr_t);
                                        break;
                                case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
@@ -865,7 +975,7 @@ void ImageLoaderMachOCompressed::eachBind(const LinkContext& context, bind_handl
                                        for (uint32_t i=0; i < count; ++i) {
                                                if ( address >= segmentEndAddress ) 
                                                        throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
                                        for (uint32_t i=0; i < count; ++i) {
                                                if ( address >= segmentEndAddress ) 
                                                        throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
-                                               (this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "", &last);
+                                               (this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "", &last, false);
                                                address += skip + sizeof(intptr_t);
                                        }
                                        break;
                                                address += skip + sizeof(intptr_t);
                                        }
                                        break;
@@ -946,7 +1056,7 @@ void ImageLoaderMachOCompressed::eachLazyBind(const LinkContext& context, bind_h
                                case BIND_OPCODE_DO_BIND:
                                        if ( address >= segmentEndAddress ) 
                                                throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
                                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);
+                                       (this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "lazy forced", NULL, true);
                                        address += sizeof(intptr_t);
                                        break;
                                case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
                                        address += sizeof(intptr_t);
                                        break;
                                case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
@@ -1039,12 +1149,25 @@ uintptr_t ImageLoaderMachOCompressed::doBindLazySymbol(uintptr_t* lazyPointer, c
 }
 
 
 }
 
 
-uintptr_t ImageLoaderMachOCompressed::doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context)
+uintptr_t ImageLoaderMachOCompressed::doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context,
+                                                                                                                       void (*lock)(), void (*unlock)())
 {
 {
+       // <rdar://problem/8663923> race condition with flat-namespace lazy binding
+       if ( this->usesTwoLevelNameSpace() ) {
+               // two-level namespace lookup does not require lock because dependents can't be unloaded before this image
+       }
+       else {
+               // acquire dyld global lock
+               if ( lock != NULL )
+                       lock();
+       }
+       
        const uint8_t* const start = fLinkEditBase + fDyldInfo->lazy_bind_off;
        const uint8_t* const end = &start[fDyldInfo->lazy_bind_size];
        const uint8_t* const start = fLinkEditBase + fDyldInfo->lazy_bind_off;
        const uint8_t* const end = &start[fDyldInfo->lazy_bind_size];
-       if ( lazyBindingInfoOffset > fDyldInfo->lazy_bind_size )
-               throw "fast lazy bind offset out of range";
+       if ( lazyBindingInfoOffset > fDyldInfo->lazy_bind_size ) {
+               dyld::throwf("fast lazy bind offset out of range (%u, max=%u) in image %s", 
+                       lazyBindingInfoOffset, fDyldInfo->lazy_bind_size, this->getPath());
+       }
 
        uint8_t type = BIND_TYPE_POINTER;
        uintptr_t address = 0;
 
        uint8_t type = BIND_TYPE_POINTER;
        uintptr_t address = 0;
@@ -1094,7 +1217,9 @@ uintptr_t ImageLoaderMachOCompressed::doBindFastLazySymbol(uint32_t lazyBindingI
                                address = segActualLoadAddress(immediate) + read_uleb128(p, end);
                                break;
                        case BIND_OPCODE_DO_BIND:
                                address = segActualLoadAddress(immediate) + read_uleb128(p, end);
                                break;
                        case BIND_OPCODE_DO_BIND:
-                               result = this->bindAt(context, address, type, symbolName, 0, 0, libraryOrdinal, "lazy ", NULL);
+                               
+                       
+                               result = this->bindAt(context, address, type, symbolName, 0, 0, libraryOrdinal, "lazy ", NULL, true);
                                break;
                        case BIND_OPCODE_SET_ADDEND_SLEB:
                        case BIND_OPCODE_ADD_ADDR_ULEB:
                                break;
                        case BIND_OPCODE_SET_ADDEND_SLEB:
                        case BIND_OPCODE_ADD_ADDR_ULEB:
@@ -1105,6 +1230,12 @@ uintptr_t ImageLoaderMachOCompressed::doBindFastLazySymbol(uint32_t lazyBindingI
                                dyld::throwf("bad lazy bind opcode %d", *p);
                }
        }       
                                dyld::throwf("bad lazy bind opcode %d", *p);
                }
        }       
+       
+       if ( !this->usesTwoLevelNameSpace() ) {
+               // release dyld global lock
+               if ( unlock != NULL )
+                       unlock();
+       }
        return result;
 }
 
        return result;
 }
 
@@ -1290,6 +1421,35 @@ void ImageLoaderMachOCompressed::updateUsesCoalIterator(CoalIterator& it, uintpt
                this->addDynamicReference(targetImage);
 }
 
                this->addDynamicReference(targetImage);
 }
 
+uintptr_t ImageLoaderMachOCompressed::interposeAt(const LinkContext& context, uintptr_t addr, uint8_t type, const char*, 
+                                                                                               uint8_t, intptr_t, int, const char*, LastLookup*, bool runResolver)
+{
+       if ( type == BIND_TYPE_POINTER ) {
+               uintptr_t* fixupLocation = (uintptr_t*)addr;
+               uintptr_t value = *fixupLocation;
+               for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) {
+                       // replace all references to 'replacee' with 'replacement'
+                       if ( (value == it->replacee) && (this != it->replacementImage) ) {
+                               if ( context.verboseInterposing ) {
+                                       dyld::log("dyld: interposing: at %p replace 0x%lX with 0x%lX in %s\n", 
+                                               fixupLocation, it->replacee, it->replacement, this->getPath());
+                               }
+                               *fixupLocation = it->replacement;
+                       }
+               }
+       }
+       return 0;
+}
+
+void ImageLoaderMachOCompressed::doInterpose(const LinkContext& context)
+{
+       if ( context.verboseInterposing )
+               dyld::log("dyld: interposing %lu tuples onto image: %s\n", fgInterposingTuples.size(), this->getPath());
+
+       // update prebound symbols
+       eachBind(context, &ImageLoaderMachOCompressed::interposeAt);
+       eachLazyBind(context, &ImageLoaderMachOCompressed::interposeAt);
+}
 
 
 
 
 
 
@@ -1354,7 +1514,14 @@ const char* ImageLoaderMachOCompressed::findClosestSymbol(const void* addr, cons
                }
        }
        if ( bestSymbol != NULL ) {
                }
        }
        if ( bestSymbol != NULL ) {
+#if __arm__
+               if (bestSymbol->n_desc & N_ARM_THUMB_DEF)
+                       *closestAddr = (void*)((bestSymbol->n_value | 1) + fSlide);
+               else
+                       *closestAddr = (void*)(bestSymbol->n_value + fSlide);
+#else
                *closestAddr = (void*)(bestSymbol->n_value + fSlide);
                *closestAddr = (void*)(bestSymbol->n_value + fSlide);
+#endif
                return &symbolTableStrings[bestSymbol->n_un.n_strx];
        }
        return NULL;
                return &symbolTableStrings[bestSymbol->n_un.n_strx];
        }
        return NULL;
@@ -1368,3 +1535,96 @@ void ImageLoaderMachOCompressed::resetPreboundLazyPointers(const LinkContext& co
 }
 #endif
 
 }
 #endif
 
+
+#if __arm__ || __x86_64__
+void ImageLoaderMachOCompressed::updateAlternateLazyPointer(uint8_t* stub, void** originalLazyPointerAddr)
+{
+#if __arm__ 
+       uint32_t* instructions = (uint32_t*)stub;
+    // sanity check this is a stub we understand
+       if ( (instructions[0] != 0xe59fc004) || (instructions[1] != 0xe08fc00c) || (instructions[2] != 0xe59cf000) )
+               return;
+    
+       void** lazyPointerAddr = (void**)(instructions[3] + (stub + 12));
+#endif
+#if __x86_64__
+    // sanity check this is a stub we understand
+       if ( (stub[0] != 0xFF) || (stub[1] != 0x25) )
+               return;
+    int32_t ripOffset = *((int32_t*)(&stub[2]));
+       void** lazyPointerAddr = (void**)(ripOffset + stub + 6);
+#endif
+
+   // if stub does not use original lazy pointer (meaning it was optimized by update_dyld_shared_cache)
+    if ( lazyPointerAddr != originalLazyPointerAddr ) {
+        // copy newly re-bound lazy pointer value to shared lazy pointer
+        *lazyPointerAddr = *originalLazyPointerAddr;
+    }
+}
+#endif
+
+
+// <rdar://problem/8890875> overriding shared cache dylibs with resolvers fails
+void ImageLoaderMachOCompressed::updateOptimizedLazyPointers(const LinkContext& context)
+{
+#if __arm__ || __x86_64__
+       // find stubs and lazy pointer sections
+       const struct macho_section* stubsSection = NULL;
+       const struct macho_section* lazyPointerSection = NULL;
+       const dysymtab_command* dynSymbolTable = NULL;
+       const macho_header* mh = (macho_header*)fMachOData;
+       const uint32_t cmd_count = mh->ncmds;
+       const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
+       const struct load_command* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               if (cmd->cmd == 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_SYMBOL_STUBS ) 
+                                       stubsSection = sect;
+                               else if ( type == S_LAZY_SYMBOL_POINTERS ) 
+                                       lazyPointerSection = sect;
+                       }
+               }
+               else if ( cmd->cmd == LC_DYSYMTAB ) {
+                       dynSymbolTable = (struct dysymtab_command*)cmd;
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+       }
+       
+       // sanity check
+       if ( dynSymbolTable == NULL )
+               return;
+       if ( (stubsSection == NULL) || (lazyPointerSection == NULL) )
+               return;
+       const uint32_t stubsCount = stubsSection->size / stubsSection->reserved2;
+       const uint32_t lazyPointersCount = lazyPointerSection->size / sizeof(void*);
+       if ( stubsCount != lazyPointersCount )
+               return;
+       const uint32_t stubsIndirectTableOffset = stubsSection->reserved1;
+       const uint32_t lazyPointersIndirectTableOffset = lazyPointerSection->reserved1;
+       if ( (stubsIndirectTableOffset+stubsCount) > dynSymbolTable->nindirectsyms )
+               return;
+       if ( (lazyPointersIndirectTableOffset+lazyPointersCount) > dynSymbolTable->nindirectsyms )
+               return;
+       
+       // walk stubs and lazy pointers
+       const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[dynSymbolTable->indirectsymoff];
+       void** const lazyPointersStartAddr = (void**)(lazyPointerSection->addr + this->fSlide);
+       uint8_t* const stubsStartAddr = (uint8_t*)(stubsSection->addr + this->fSlide);
+       uint8_t* stub = stubsStartAddr;
+       void** lpa = lazyPointersStartAddr;
+       for(uint32_t i=0; i < stubsCount; ++i, stub += stubsSection->reserved2, ++lpa) {
+        // sanity check symbol index of stub and lazy pointer match
+               if ( indirectTable[stubsIndirectTableOffset+i] != indirectTable[lazyPointersIndirectTableOffset+i] ) 
+                       continue;
+               this->updateAlternateLazyPointer(stub, lpa);
+       }
+       
+#endif
+}
+
+
index ae137c0463af93ac5407bffd405999c4d89e9d78..99c55294d0be209d058374f6070aa12e88b11ce1 100644 (file)
@@ -41,8 +41,9 @@ public:
                                                                                                                                        unsigned int segCount, unsigned int libCount, const LinkContext& context);
        static ImageLoaderMachOCompressed*      instantiateFromFile(const char* path, int fd, const uint8_t* fileData, 
                                                                                                                        uint64_t offsetInFat, uint64_t lenInFat, const struct stat& info, 
                                                                                                                                        unsigned int segCount, unsigned int libCount, const LinkContext& context);
        static ImageLoaderMachOCompressed*      instantiateFromFile(const char* path, int fd, const uint8_t* fileData, 
                                                                                                                        uint64_t offsetInFat, uint64_t lenInFat, const struct stat& info, 
-                                                                                                                       unsigned int segCount, unsigned int libCount, const LinkContext& context);
-       static ImageLoaderMachOCompressed*      instantiateFromCache(const macho_header* mh, const char* path, const struct stat& info,
+                                                                                                                       unsigned int segCount, unsigned int libCount, 
+                                                                                                                       const struct linkedit_data_command* codeSigCmd, const LinkContext& context);
+       static ImageLoaderMachOCompressed*      instantiateFromCache(const macho_header* mh, const char* path, long slide, const struct stat& info,
                                                                                                                                unsigned int segCount, unsigned int libCount, const LinkContext& context);
        static ImageLoaderMachOCompressed*      instantiateFromMemory(const char* moduleName, const macho_header* mh, uint64_t len, 
                                                                                                                        unsigned int segCount, unsigned int libCount, const LinkContext& context);
                                                                                                                                unsigned int segCount, unsigned int libCount, const LinkContext& context);
        static ImageLoaderMachOCompressed*      instantiateFromMemory(const char* moduleName, const macho_header* mh, uint64_t len, 
                                                                                                                        unsigned int segCount, unsigned int libCount, const LinkContext& context);
@@ -52,11 +53,12 @@ public:
 
        virtual ImageLoader*                            libImage(unsigned int) const;
        virtual bool                                            libReExported(unsigned int) const;
 
        virtual ImageLoader*                            libImage(unsigned int) const;
        virtual bool                                            libReExported(unsigned int) const;
-       virtual void                                            setLibImage(unsigned int, ImageLoader*, bool);
+       virtual bool                                            libIsUpward(unsigned int) const;
+       virtual void                                            setLibImage(unsigned int, ImageLoader*, bool, bool);
        virtual void                                            doBind(const LinkContext& context, bool forceLazysBound);
        virtual void                                            doBindJustLazies(const LinkContext& context);
        virtual uintptr_t                                       doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context);
        virtual void                                            doBind(const LinkContext& context, bool forceLazysBound);
        virtual void                                            doBindJustLazies(const LinkContext& context);
        virtual uintptr_t                                       doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context);
-       virtual uintptr_t                                       doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context);
+       virtual uintptr_t                                       doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context, void (*lock)(), void (*unlock)());
        virtual const char*                                     findClosestSymbol(const void* addr, const void** closestAddr) const;
        virtual void                                            initializeCoalIterator(CoalIterator&, unsigned int loadOrder);
        virtual bool                                            incrementCoalIterator(CoalIterator&);
        virtual const char*                                     findClosestSymbol(const void* addr, const void** closestAddr) const;
        virtual void                                            initializeCoalIterator(CoalIterator&, unsigned int loadOrder);
        virtual bool                                            incrementCoalIterator(CoalIterator&);
@@ -65,6 +67,7 @@ public:
 
        
 protected:
 
        
 protected:
+       virtual void                                            doInterpose(const LinkContext& context);
        virtual void                                            setDyldInfo(const dyld_info_command* dyldInfo) { fDyldInfo = dyldInfo; }
        virtual void                                            setSymbolTableInfo(const macho_nlist*, const char*, const dysymtab_command*) {}
        virtual bool                                            isSubframeworkOf(const LinkContext& context, const ImageLoader* image) const { return false; }
        virtual void                                            setDyldInfo(const dyld_info_command* dyldInfo) { fDyldInfo = dyldInfo; }
        virtual void                                            setSymbolTableInfo(const macho_nlist*, const char*, const dysymtab_command*) {}
        virtual bool                                            isSubframeworkOf(const LinkContext& context, const ImageLoader* image) const { return false; }
@@ -73,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 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 Symbol* symbol) const;
+       virtual uintptr_t                                       exportedSymbolAddress(const LinkContext& context, const Symbol* symbol, bool runResolver) const;
        virtual bool                                            exportedSymbolIsWeakDefintion(const Symbol* symbol) const;
        virtual const char*                                     exportedSymbolName(const Symbol* symbol) const;
        virtual unsigned int                            exportedSymbolCount() const;
        virtual bool                                            exportedSymbolIsWeakDefintion(const Symbol* symbol) const;
        virtual const char*                                     exportedSymbolName(const Symbol* symbol) const;
        virtual unsigned int                            exportedSymbolCount() const;
@@ -92,7 +95,7 @@ private:
 
        typedef uintptr_t (ImageLoaderMachOCompressed::*bind_handler)(const LinkContext& context, uintptr_t addr, uint8_t type, 
                                                                                        const char* symbolName, uint8_t symboFlags, intptr_t addend, int libraryOrdinal, 
 
        typedef uintptr_t (ImageLoaderMachOCompressed::*bind_handler)(const LinkContext& context, uintptr_t addr, uint8_t type, 
                                                                                        const char* symbolName, uint8_t symboFlags, intptr_t addend, int libraryOrdinal, 
-                                                                                       const char* msg, LastLookup* last);
+                                                                                       const char* msg, LastLookup* last, bool runResolver);
 
        void                                                            eachLazyBind(const LinkContext& context, bind_handler);
        void                                                            eachBind(const LinkContext& context, bind_handler);
 
        void                                                            eachLazyBind(const LinkContext& context, bind_handler);
        void                                                            eachBind(const LinkContext& context, bind_handler);
@@ -111,18 +114,24 @@ private:
                                                                                                const uint8_t* startOpcodes, const uint8_t* endOpcodes, const uint8_t* pos);
        uintptr_t                                                       bindAt(const LinkContext& context, uintptr_t addr, uint8_t type, const char* symbolName, 
                                                                                                uint8_t symboFlags, intptr_t addend, int libraryOrdinal, const char* msg,
                                                                                                const uint8_t* startOpcodes, const uint8_t* endOpcodes, const uint8_t* pos);
        uintptr_t                                                       bindAt(const LinkContext& context, uintptr_t addr, uint8_t type, const char* symbolName, 
                                                                                                uint8_t symboFlags, intptr_t addend, int libraryOrdinal, const char* msg,
-                                                                                               LastLookup* last);
+                                                                                               LastLookup* last, bool runResolver=false);
        void                                                            bindCompressed(const LinkContext& context);
        void                                                            throwBadBindingAddress(uintptr_t address, uintptr_t segmentEndAddress, int segmentIndex, 
                                                                                                const uint8_t* startOpcodes, const uint8_t* endOpcodes, const uint8_t* pos);
        uintptr_t                                                       resolve(const LinkContext& context, const char* symbolName, 
        void                                                            bindCompressed(const LinkContext& context);
        void                                                            throwBadBindingAddress(uintptr_t address, uintptr_t segmentEndAddress, int segmentIndex, 
                                                                                                const uint8_t* startOpcodes, const uint8_t* endOpcodes, const uint8_t* pos);
        uintptr_t                                                       resolve(const LinkContext& context, const char* symbolName, 
-                                                                                               uint8_t symboFlags, int libraryOrdinal, const ImageLoader** targetImage, LastLookup* last = NULL);
-       uintptr_t                                                       resolveFlat(const LinkContext& context, const char* symbolName, bool weak_import, 
+                                                                                               uint8_t symboFlags, int libraryOrdinal, const ImageLoader** targetImage, 
+                                                                                               LastLookup* last = NULL, bool runResolver=false);
+       uintptr_t                                                       resolveFlat(const LinkContext& context, const char* symbolName, bool weak_import, bool runResolver,
                                                                                                        const ImageLoader** foundIn);
        uintptr_t                                                       resolveCoalesced(const LinkContext& context, const char* symbolName, const ImageLoader** foundIn);
        uintptr_t                                                       resolveTwolevel(const LinkContext& context, const ImageLoader* targetImage, bool weak_import, 
                                                                                                        const ImageLoader** foundIn);
        uintptr_t                                                       resolveCoalesced(const LinkContext& context, const char* symbolName, const ImageLoader** foundIn);
        uintptr_t                                                       resolveTwolevel(const LinkContext& context, const ImageLoader* targetImage, bool weak_import, 
-                                                                                                               const char* symbolName, const ImageLoader** foundIn);
-                       
+                                                                                                               const char* symbolName, bool runResolver, const ImageLoader** foundIn);
+       uintptr_t                                                       interposeAt(const LinkContext& context, uintptr_t addr, uint8_t type, const char*, 
+                                                                                               uint8_t, intptr_t, int, const char*, LastLookup*, bool runResolver);
+       static const uint8_t*                           trieWalk(const uint8_t* start, const uint8_t* end, const  char* s);
+    void                                updateOptimizedLazyPointers(const LinkContext& context);
+    void                                updateAlternateLazyPointer(uint8_t* stub, void** originalLazyPointerAddr);
+               
        const struct dyld_info_command*                 fDyldInfo;
 };
 
        const struct dyld_info_command*                 fDyldInfo;
 };
 
index 3d5bcd000bdb7cd7a7305d69a04149482f31ef51..d86e0b1717850cd5b37816474212680108331e20 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2004-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <unistd.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <dirent.h>
 #include <sys/param.h>
 #include <mach/mach_time.h> // mach_absolute_time()
 #include <sys/types.h>
 #include <sys/stat.h> 
 #include <sys/param.h>
 #include <mach/mach_time.h> // mach_absolute_time()
 #include <sys/types.h>
 #include <sys/stat.h> 
+#include <sys/syscall.h>
 #include <mach-o/fat.h> 
 #include <mach-o/loader.h> 
 #include <mach-o/ldsyms.h> 
 #include <mach-o/fat.h> 
 #include <mach-o/loader.h> 
 #include <mach-o/ldsyms.h> 
@@ -40,6 +42,9 @@
 #include <sys/mman.h>
 #include <sys/dtrace.h>
 #include <libkern/OSAtomic.h>
 #include <sys/mman.h>
 #include <sys/dtrace.h>
 #include <libkern/OSAtomic.h>
+#include <Availability.h>
+#include <Kernel/sys/codesign.h>
+
 
 #ifndef CPU_SUBTYPE_ARM_V5TEJ
        #define CPU_SUBTYPE_ARM_V5TEJ           ((cpu_subtype_t) 7)
 
 #ifndef CPU_SUBTYPE_ARM_V5TEJ
        #define CPU_SUBTYPE_ARM_V5TEJ           ((cpu_subtype_t) 7)
 #ifndef CPU_SUBTYPE_ARM_V7
        #define CPU_SUBTYPE_ARM_V7                      ((cpu_subtype_t) 9)
 #endif
 #ifndef CPU_SUBTYPE_ARM_V7
        #define CPU_SUBTYPE_ARM_V7                      ((cpu_subtype_t) 9)
 #endif
+#ifndef LC_DYLD_ENVIRONMENT
+       #define LC_DYLD_ENVIRONMENT                     0x27
+#endif
+
+#ifndef VM_PROT_SLIDE   
+    #define VM_PROT_SLIDE 0x20
+#endif
 
 #include <vector>
 #include <algorithm>
 
 #include <vector>
 #include <algorithm>
@@ -90,6 +102,8 @@ extern "C" char *                    _simple_string(_SIMPLE_STRING __b);
 extern void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[]);
 extern void removeImageFromAllImages(const mach_header* mh);
 extern void setAlImageInfosHalt(const char* message, uintptr_t flags);
 extern void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[]);
 extern void removeImageFromAllImages(const mach_header* mh);
 extern void setAlImageInfosHalt(const char* message, uintptr_t flags);
+extern void addNonSharedCacheImageUUID(const dyld_uuid_info& info);
+extern const char* notifyGDB(enum dyld_image_states state, uint32_t infoCount, const dyld_image_info info[]);
 
 // magic so CrashReporter logs message
 extern "C" {
 
 // magic so CrashReporter logs message
 extern "C" {
@@ -123,6 +137,8 @@ struct EnvironmentVariables {
        const char* const *                     DYLD_FALLBACK_LIBRARY_PATH;
        const char* const *                     DYLD_INSERT_LIBRARIES;
        const char* const *                     LD_LIBRARY_PATH;                        // for unix conformance
        const char* const *                     DYLD_FALLBACK_LIBRARY_PATH;
        const char* const *                     DYLD_INSERT_LIBRARIES;
        const char* const *                     LD_LIBRARY_PATH;                        // for unix conformance
+       const char* const *                     DYLD_VERSIONED_LIBRARY_PATH;
+       const char* const *                     DYLD_VERSIONED_FRAMEWORK_PATH;
        bool                                            DYLD_PRINT_LIBRARIES;
        bool                                            DYLD_PRINT_LIBRARIES_POST_LAUNCH;
        bool                                            DYLD_BIND_AT_LAUNCH;
        bool                                            DYLD_PRINT_LIBRARIES;
        bool                                            DYLD_PRINT_LIBRARIES_POST_LAUNCH;
        bool                                            DYLD_BIND_AT_LAUNCH;
@@ -130,6 +146,7 @@ struct EnvironmentVariables {
        bool                                            DYLD_PRINT_OPTS;
        bool                                            DYLD_PRINT_ENV;
        bool                                            DYLD_DISABLE_DOFS;
        bool                                            DYLD_PRINT_OPTS;
        bool                                            DYLD_PRINT_ENV;
        bool                                            DYLD_DISABLE_DOFS;
+       bool                                            DYLD_PRINT_CS_NOTIFICATIONS;
                             //  DYLD_SHARED_CACHE_DONT_VALIDATE ==> sSharedCacheIgnoreInodeAndTimeStamp
                             //  DYLD_SHARED_CACHE_DIR           ==> sSharedCacheDir
                                                        //      DYLD_ROOT_PATH                                  ==> gLinkContext.rootPaths
                             //  DYLD_SHARED_CACHE_DONT_VALIDATE ==> sSharedCacheIgnoreInodeAndTimeStamp
                             //  DYLD_SHARED_CACHE_DIR           ==> sSharedCacheDir
                                                        //      DYLD_ROOT_PATH                                  ==> gLinkContext.rootPaths
@@ -149,16 +166,21 @@ struct EnvironmentVariables {
                                                        //      DYLD_NEW_LOCAL_SHARED_REGIONS   ==> gLinkContext.sharedRegionMode
                                                        //      DYLD_SHARED_REGION                              ==> gLinkContext.sharedRegionMode
                                                        //      DYLD_PRINT_WARNINGS                             ==> gLinkContext.verboseWarnings
                                                        //      DYLD_NEW_LOCAL_SHARED_REGIONS   ==> gLinkContext.sharedRegionMode
                                                        //      DYLD_SHARED_REGION                              ==> gLinkContext.sharedRegionMode
                                                        //      DYLD_PRINT_WARNINGS                             ==> gLinkContext.verboseWarnings
+                                                       //      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; };
 };
         
 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; };
 
 // all global state
 static const char*                                     sExecPath = NULL;
 static const macho_header*                     sMainExecutableMachHeader = NULL;
 
 // all global state
 static const char*                                     sExecPath = NULL;
 static const macho_header*                     sMainExecutableMachHeader = NULL;
+#if CPU_SUBTYPES_SUPPORTED
 static cpu_type_t                                      sHostCPU;
 static cpu_subtype_t                           sHostCPUsubtype;
 static cpu_type_t                                      sHostCPU;
 static cpu_subtype_t                           sHostCPUsubtype;
+#endif
 static ImageLoader*                                    sMainExecutable = NULL;
 static bool                                                    sProcessIsRestricted = false;
 static unsigned int                                    sInsertedDylibCount = 0;
 static ImageLoader*                                    sMainExecutable = NULL;
 static bool                                                    sProcessIsRestricted = false;
 static unsigned int                                    sInsertedDylibCount = 0;
@@ -178,8 +200,15 @@ static UndefinedHandler                            sUndefinedHandler = NULL;
 static ImageLoader*                                    sBundleBeingLoaded = NULL;      // hack until OFI is reworked
 #if DYLD_SHARED_CACHE_SUPPORT
 static const dyld_cache_header*                sSharedCache = NULL;
 static ImageLoader*                                    sBundleBeingLoaded = NULL;      // hack until OFI is reworked
 #if DYLD_SHARED_CACHE_SUPPORT
 static const dyld_cache_header*                sSharedCache = NULL;
+static long                                                    sSharedCacheSlide = 0;
 static bool                                                    sSharedCacheIgnoreInodeAndTimeStamp = false;
 static bool                                                    sSharedCacheIgnoreInodeAndTimeStamp = false;
-static const char*                                     sSharedCacheDir = DYLD_SHARED_CACHE_DIR;
+#if __IPHONE_OS_VERSION_MIN_REQUIRED   
+       bool                                                    gSharedCacheOverridden = false;
+       static const char*                              sSharedCacheDir = IPHONE_DYLD_SHARED_CACHE_DIR;
+       static bool                                             sDylibsOverrideCache = false;
+#else
+       static const char*                              sSharedCacheDir = MACOSX_DYLD_SHARED_CACHE_DIR;
+#endif
 #endif
 ImageLoader::LinkContext                       gLinkContext;
 bool                                                           gLogAPIs = false;
 #endif
 ImageLoader::LinkContext                       gLinkContext;
 bool                                                           gLogAPIs = false;
@@ -187,7 +216,7 @@ const struct LibSystemHelpers*              gLibSystemHelpers = NULL;
 #if SUPPORT_OLD_CRT_INITIALIZATION
 bool                                                           gRunInitializersOldWay = false;
 #endif
 #if SUPPORT_OLD_CRT_INITIALIZATION
 bool                                                           gRunInitializersOldWay = false;
 #endif
-
+static std::vector<DylibOverride>      sDylibOverrides;
 
 //
 // The MappedRanges structure is used for fast address->image lookups.
 
 //
 // The MappedRanges structure is used for fast address->image lookups.
@@ -306,6 +335,35 @@ void throwf(const char* format, ...)
 //#define ALTERNATIVE_LOGFILE "/dev/console"
 static int sLogfile = STDERR_FILENO;
 
 //#define ALTERNATIVE_LOGFILE "/dev/console"
 static int sLogfile = STDERR_FILENO;
 
+#if LOG_BINDINGS
+static int sBindingsLogfile = -1;
+static void mysprintf(char* dst, const char* format, ...)
+{
+       _SIMPLE_STRING buf = _simple_salloc();
+       if ( buf != NULL ) {
+               va_list list;
+               va_start(list, format);
+               _simple_vsprintf(buf, format, list);
+               va_end(list);
+               strcpy(dst, _simple_string(buf));
+               _simple_sfree(buf);
+       }
+       else {
+               strcpy(dst, "out of memory");
+       }
+}
+void logBindings(const char* format, ...) 
+{
+       if ( sBindingsLogfile != -1 ) {
+               va_list list;
+               va_start(list, format);
+               _simple_vdprintf(sBindingsLogfile, format, list);
+               va_end(list);
+       }
+}
+
+#endif
+
 void log(const char* format, ...) 
 {
        va_list list;
 void log(const char* format, ...) 
 {
        va_list list;
@@ -432,10 +490,13 @@ static void notifyAddImageCallbacks(ImageLoader* image)
 }
 
 
 }
 
 
+
 // notify gdb about these new images
 // notify gdb about these new images
-static const char* notifyGDB(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+static const char* updateAllImages(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
 {
 {
-       addImagesToAllImages(infoCount, info);
+       // <rdar://problem/8812589> don't add images without paths to all-image-info-list
+       if ( info[0].imageFilePath != NULL )
+               addImagesToAllImages(infoCount, info);
        return NULL;
 }
 
        return NULL;
 }
 
@@ -487,17 +548,70 @@ static void notifySingle(dyld_image_states state, const ImageLoader* image)
                        }
                }
        }
                        }
                }
        }
+       if ( state == dyld_image_state_mapped ) {
+               // <rdar://problem/7008875> Save load addr + UUID for images from outside the shared cache
+               if ( !image->inSharedCache() ) {
+                       dyld_uuid_info info;
+                       if ( image->getUUID(info.imageUUID) ) {
+                               info.imageLoadAddress = image->machHeader();
+                               addNonSharedCacheImageUUID(info);
+                       }
+               }
+       }
 #if CORESYMBOLICATION_SUPPORT
     // mach message csdlc about dynamically loaded images 
 #if CORESYMBOLICATION_SUPPORT
     // mach message csdlc about dynamically loaded images 
-    if ( dyld_all_image_infos.coreSymbolicationShmPage != NULL) {
-               CSCppDyldSharedMemoryPage* connection = (CSCppDyldSharedMemoryPage*)dyld_all_image_infos.coreSymbolicationShmPage;
-               if ( connection->is_valid_version() ) {
-                       if ( state == dyld_image_state_terminated ) {
+       if ( image->addFuncNotified() && (state == dyld_image_state_terminated) ) {
+               if ( sEnv.DYLD_PRINT_CS_NOTIFICATIONS ) {
+                       dyld::log("dyld core symbolication unload notification: %p %s\n", image->machHeader(), image->getPath());
+               }
+               if ( dyld_all_image_infos.coreSymbolicationShmPage != NULL) {
+                       CSCppDyldSharedMemoryPage* connection = (CSCppDyldSharedMemoryPage*)dyld_all_image_infos.coreSymbolicationShmPage;
+                       if ( connection->is_valid_version() ) {
                                coresymbolication_unload_image(connection, image);
                        }
                }
        }
                                coresymbolication_unload_image(connection, image);
                        }
                }
        }
-#endif 
+#endif
+}
+
+
+
+
+//
+// Normally, dyld_all_image_infos is only updated in batches after an entire
+// graph is loaded.  But if there is an error loading the initial set of
+// 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.
+// It should only be called before terminating.
+//
+void syncAllImages()
+{
+       for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); ++it) {
+               dyld_image_info info;
+               ImageLoader* image = *it;
+               info.imageLoadAddress = image->machHeader();
+               info.imageFilePath = image->getPath();
+               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;
+               if ( existing != NULL ) {
+                       for (int i=0; i < existingCount; ++i) {
+                               if ( existing[i].imageLoadAddress == info.imageLoadAddress ) {
+                                       //dyld::log("not adding %s\n", info.imageFilePath);
+                                       found = true;
+                                       break;
+                               }
+                       }
+               }
+               if ( ! found ) {
+                       //dyld::log("adding %s\n", info.imageFilePath);
+                       addImagesToAllImages(1, &info);
+               }
+       }
 }
 
 
 }
 
 
@@ -567,10 +681,17 @@ static void notifyBatchPartial(dyld_image_states state, bool orLater, dyld_image
                }
        }
 #if CORESYMBOLICATION_SUPPORT
                }
        }
 #if CORESYMBOLICATION_SUPPORT
-       if ( dyld_all_image_infos.coreSymbolicationShmPage != NULL) {
-               CSCppDyldSharedMemoryPage* connection = (CSCppDyldSharedMemoryPage*)dyld_all_image_infos.coreSymbolicationShmPage;
-               if ( connection->is_valid_version() ) {
-                       if ( state == dyld_image_state_rebased ) {
+       if ( state == dyld_image_state_rebased ) {
+               if ( sEnv.DYLD_PRINT_CS_NOTIFICATIONS ) {
+                       for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
+                               dyld_image_states imageState = (*it)->getState();
+                               if ( (imageState == dyld_image_state_rebased) || (orLater && (imageState > dyld_image_state_rebased)) )
+                                       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 ( connection->is_valid_version() ) {
                                // This needs to be captured now
                                uint64_t load_timestamp = mach_absolute_time();
                                for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
                                // This needs to be captured now
                                uint64_t load_timestamp = mach_absolute_time();
                                for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
@@ -584,6 +705,8 @@ static void notifyBatchPartial(dyld_image_states state, bool orLater, dyld_image
 #endif
 }
 
 #endif
 }
 
+
+
 static void notifyBatch(dyld_image_states state)
 {
        notifyBatchPartial(state, false, NULL);
 static void notifyBatch(dyld_image_states state)
 {
        notifyBatchPartial(state, false, NULL);
@@ -701,6 +824,10 @@ void removeImage(ImageLoader* image)
        // notify 
        notifySingle(dyld_image_state_terminated, 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);
 
        // remove from mapped images table
        removedMappedRanges(image);
 
@@ -747,19 +874,26 @@ const char* getExecutablePath()
 
 void initializeMainExecutable()
 {
 
 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;
 
        // run initialzers for any inserted dylibs
 
        // record that we've reached this step
        gLinkContext.startedInitializingMainExecutable = true;
 
        // run initialzers for any inserted dylibs
+       ImageLoader::InitializerTimingList initializerTimes[sAllImages.size()];
        const int rootCount = sImageRoots.size();
        if ( rootCount > 1 ) {
        const int rootCount = sImageRoots.size();
        if ( rootCount > 1 ) {
-               for(int i=1; i < rootCount; ++i)
-                       sImageRoots[i]->runInitializers(gLinkContext);
+               for(int i=1; i < rootCount; ++i) {
+                       initializerTimes[0].count = 0;
+                       sImageRoots[i]->runInitializers(gLinkContext, initializerTimes[0]);
+               }
        }
        
        // run initializers for main executable and everything it brings up 
        }
        
        // run initializers for main executable and everything it brings up 
-       sMainExecutable->runInitializers(gLinkContext);
+       initializerTimes[0].count = 0;
+       sMainExecutable->runInitializers(gLinkContext, initializerTimes[0]);
        
        // register atexit() handler to run terminators in all loaded images when this process exits
        if ( gLibSystemHelpers != NULL ) 
        
        // register atexit() handler to run terminators in all loaded images when this process exits
        if ( gLibSystemHelpers != NULL ) 
@@ -767,7 +901,7 @@ void initializeMainExecutable()
 
        // dump info if requested
        if ( sEnv.DYLD_PRINT_STATISTICS )
 
        // dump info if requested
        if ( sEnv.DYLD_PRINT_STATISTICS )
-               ImageLoaderMachO::printStatistics(sAllImages.size());
+               ImageLoaderMachO::printStatistics(sAllImages.size(), initializerTimes[0]);
 }
 
 bool mainExecutablePrebound()
 }
 
 bool mainExecutablePrebound()
@@ -793,12 +927,122 @@ void runTerminators(void* extra)
 }
 
 
 }
 
 
+// forward reference
+static bool getDylibVersionAndInstallname(const char* dylibPath, uint32_t* version, char* installName);
+
+
 //
 //
-// Turns a colon separated list of strings
-// into a NULL terminated array of string 
-// pointers.
+// Examines a dylib file and if its current_version is newer than the installed
+// dylib at its install_name, then add the dylib file to sDylibOverrides.
 //
 //
-static const char** parseColonList(const char* list)
+static void checkDylibOverride(const char* dylibFile)
+{
+       //dyld::log("checkDylibOverride('%s')\n", dylibFile);
+       uint32_t altVersion;
+       char sysInstallName[PATH_MAX];
+       if ( getDylibVersionAndInstallname(dylibFile, &altVersion, sysInstallName) ) {
+               //dyld::log("%s has version 0x%08X and install name %s\n", dylibFile, altVersion, sysInstallName);
+               uint32_t sysVersion;
+               if ( getDylibVersionAndInstallname(sysInstallName, &sysVersion, NULL) ) {
+                       //dyld::log("%s has version 0x%08X\n", sysInstallName, sysVersion);
+                       if ( altVersion > sysVersion ) {
+                               //dyld::log("override found: %s -> %s\n", sysInstallName, dylibFile);
+                               // see if there already is an override for this dylib
+                               bool entryExists = false;
+                               for (std::vector<DylibOverride>::iterator it = sDylibOverrides.begin(); it != sDylibOverrides.end(); ++it) {
+                                       if ( strcmp(it->installName, sysInstallName) == 0 ) {
+                                               entryExists = true;
+                                               uint32_t prevVersion;
+                                               if ( getDylibVersionAndInstallname(it->override, &prevVersion, NULL) ) {
+                                                       if ( altVersion > prevVersion ) {
+                                                               // found an even newer override
+                                                               free((void*)(it->override));
+                                                               it->override = strdup(dylibFile);
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                               }
+                               if ( ! entryExists ) {
+                                       DylibOverride entry;
+                                       entry.installName = strdup(sysInstallName);
+                                       entry.override = strdup(dylibFile);
+                                       sDylibOverrides.push_back(entry);
+                                       //dyld::log("added override: %s -> %s\n", entry.installName, entry.override);
+                               }
+                       }
+               }
+       }
+       
+}
+
+static void checkDylibOverridesInDir(const char* dirPath)
+{
+       //dyld::log("checkDylibOverridesInDir('%s')\n", dirPath);
+       char dylibPath[PATH_MAX];
+       int dirPathLen = strlen(dirPath);
+       strlcpy(dylibPath, dirPath, PATH_MAX); 
+       DIR* dirp = opendir(dirPath);
+       if ( dirp != NULL) {
+               dirent entry;
+               dirent* entp = NULL;
+               while ( readdir_r(dirp, &entry, &entp) == 0 ) {
+                       if ( entp == NULL )
+                               break;
+                       if ( entp->d_type != DT_REG ) 
+                               continue;
+                       dylibPath[dirPathLen] = '/';     
+                       dylibPath[dirPathLen+1] = '\0';     
+                       if ( strlcat(dylibPath, entp->d_name, PATH_MAX) > PATH_MAX ) 
+                               continue;
+                       checkDylibOverride(dylibPath);
+               }
+               closedir(dirp);
+       }
+}
+
+
+static void checkFrameworkOverridesInDir(const char* dirPath)
+{
+       //dyld::log("checkFrameworkOverridesInDir('%s')\n", dirPath);
+       char frameworkPath[PATH_MAX];
+       int dirPathLen = strlen(dirPath);
+       strlcpy(frameworkPath, dirPath, PATH_MAX); 
+       DIR* dirp = opendir(dirPath);
+       if ( dirp != NULL) {
+               dirent entry;
+               dirent* entp = NULL;
+               while ( readdir_r(dirp, &entry, &entp) == 0 ) {
+                       if ( entp == NULL )
+                               break;
+                       if ( entp->d_type != DT_DIR ) 
+                               continue;
+                       frameworkPath[dirPathLen] = '/';     
+                       frameworkPath[dirPathLen+1] = '\0';
+                       int dirNameLen = strlen(entp->d_name);
+                       if ( dirNameLen < 11 )
+                               continue;
+                       if ( strcmp(&entp->d_name[dirNameLen-10], ".framework") != 0 )
+                               continue;
+                       if ( strlcat(frameworkPath, entp->d_name, PATH_MAX) > PATH_MAX ) 
+                               continue;
+                       if ( strlcat(frameworkPath, "/", PATH_MAX) > PATH_MAX ) 
+                               continue;
+                       if ( strlcat(frameworkPath, entp->d_name, PATH_MAX) > PATH_MAX ) 
+                               continue;
+                       frameworkPath[strlen(frameworkPath)-10] = '\0';
+                       checkDylibOverride(frameworkPath);
+               }
+               closedir(dirp);
+       }
+}
+
+//
+// Turns a colon separated list of strings into a NULL terminated array 
+// of string pointers. If mainExecutableDir param is not NULL,
+// substitutes @loader_path with main executable's dir.
+//
+static const char** parseColonList(const char* list, const char* mainExecutableDir)
 {
        static const char* sEmptyList[] = { NULL };
 
 {
        static const char* sEmptyList[] = { NULL };
 
@@ -817,22 +1061,90 @@ static const char** parseColonList(const char* list)
        for(const char* s=list; *s != '\0'; ++s) {
                if (*s == ':') {
                        int len = s-start;
        for(const char* s=list; *s != '\0'; ++s) {
                if (*s == ':') {
                        int len = s-start;
-                       char* str = new char[len+1];
-                       strncpy(str, start, len);
-                       str[len] = '\0';
-                       start = &s[1];
-                       result[index++] = str;
+                       if ( (mainExecutableDir != NULL) && (strncmp(start, "@loader_path/", 13) == 0) ) {
+                               int mainExecDirLen = strlen(mainExecutableDir);
+                               char* str = new char[mainExecDirLen+len+1];
+                               strcpy(str, mainExecutableDir);
+                               strlcat(str, &start[13], mainExecDirLen+len+1);
+                               str[mainExecDirLen+len-13] = '\0';
+                               start = &s[1];
+                               result[index++] = str;
+                       }
+                       else if ( (mainExecutableDir != NULL) && (strncmp(start, "@executable_path/", 17) == 0) ) {
+                               int mainExecDirLen = strlen(mainExecutableDir);
+                               char* str = new char[mainExecDirLen+len+1];
+                               strcpy(str, mainExecutableDir);
+                               strlcat(str, &start[17], mainExecDirLen+len+1);
+                               str[mainExecDirLen+len-17] = '\0';
+                               start = &s[1];
+                               result[index++] = str;
+                       }
+                       else {
+                               char* str = new char[len+1];
+                               strncpy(str, start, len);
+                               str[len] = '\0';
+                               start = &s[1];
+                               result[index++] = str;
+                       }
                }
        }
        int len = strlen(start);
                }
        }
        int len = strlen(start);
-       char* str = new char[len+1];
-       strcpy(str, start);
-       result[index++] = str;
+       if ( (mainExecutableDir != NULL) && (strncmp(start, "@loader_path/", 13) == 0) ) {
+               int mainExecDirLen = strlen(mainExecutableDir);
+               char* str = new char[mainExecDirLen+len+1];
+               strcpy(str, mainExecutableDir);
+               strlcat(str, &start[13], mainExecDirLen+len+1);
+               str[mainExecDirLen+len-13] = '\0';
+               result[index++] = str;
+       }
+       else if ( (mainExecutableDir != NULL) && (strncmp(start, "@executable_path/", 17) == 0) ) {
+               int mainExecDirLen = strlen(mainExecutableDir);
+               char* str = new char[mainExecDirLen+len+1];
+               strcpy(str, mainExecutableDir);
+               strlcat(str, &start[17], mainExecDirLen+len+1);
+               str[mainExecDirLen+len-17] = '\0';
+               result[index++] = str;
+       }
+       else {
+               char* str = new char[len+1];
+               strcpy(str, start);
+               result[index++] = str;
+       }
        result[index] = NULL;
        
        result[index] = NULL;
        
+       //dyld::log("parseColonList(%s)\n", list);
+       //for(int i=0; result[i] != NULL; ++i)
+       //      dyld::log("  %s\n", result[i]);
        return (const char**)result;
 }
 
        return (const char**)result;
 }
 
+static void    appendParsedColonList(const char* list, const char* mainExecutableDir, const char* const ** storage)
+{
+       const char** newlist = parseColonList(list, mainExecutableDir);
+       if ( *storage == NULL ) {
+               // first time, just set
+               *storage = newlist;
+       }
+       else {
+               // need to append to existing list
+               const char* const* existing = *storage;
+               int count = 0;
+               for(int i=0; existing[i] != NULL; ++i)
+                       ++count;
+               for(int i=0; newlist[i] != NULL; ++i)
+                       ++count;
+               const char** combinedList = new const char*[count+2];
+               int index = 0;
+               for(int i=0; existing[i] != NULL; ++i)
+                       combinedList[index++] = existing[i];
+               for(int i=0; newlist[i] != NULL; ++i)
+                       combinedList[index++] = newlist[i];
+               combinedList[index] = NULL;
+               // leak old arrays
+               *storage = combinedList;
+       }
+}
+
  
 static void paths_expand_roots(const char **paths, const char *key, const char *val)
 {
  
 static void paths_expand_roots(const char **paths, const char *key, const char *val)
 {
@@ -898,23 +1210,23 @@ static void printEnvironmentVariables(const char* envp[])
        }
 }
 
        }
 }
 
-void processDyldEnvironmentVarible(const char* key, const char* value)
+void processDyldEnvironmentVariable(const char* key, const char* value, const char* mainExecutableDir)
 {
        if ( strcmp(key, "DYLD_FRAMEWORK_PATH") == 0 ) {
 {
        if ( strcmp(key, "DYLD_FRAMEWORK_PATH") == 0 ) {
-               sEnv.DYLD_FRAMEWORK_PATH = parseColonList(value);
+               appendParsedColonList(value, mainExecutableDir, &sEnv.DYLD_FRAMEWORK_PATH);
        }
        else if ( strcmp(key, "DYLD_FALLBACK_FRAMEWORK_PATH") == 0 ) {
        }
        else if ( strcmp(key, "DYLD_FALLBACK_FRAMEWORK_PATH") == 0 ) {
-               sEnv.DYLD_FALLBACK_FRAMEWORK_PATH = parseColonList(value);
+               appendParsedColonList(value, mainExecutableDir, &sEnv.DYLD_FALLBACK_FRAMEWORK_PATH);
        }
        else if ( strcmp(key, "DYLD_LIBRARY_PATH") == 0 ) {
        }
        else if ( strcmp(key, "DYLD_LIBRARY_PATH") == 0 ) {
-               sEnv.DYLD_LIBRARY_PATH = parseColonList(value);
+               appendParsedColonList(value, mainExecutableDir, &sEnv.DYLD_LIBRARY_PATH);
        }
        else if ( strcmp(key, "DYLD_FALLBACK_LIBRARY_PATH") == 0 ) {
        }
        else if ( strcmp(key, "DYLD_FALLBACK_LIBRARY_PATH") == 0 ) {
-               sEnv.DYLD_FALLBACK_LIBRARY_PATH = parseColonList(value);
+               appendParsedColonList(value, mainExecutableDir, &sEnv.DYLD_FALLBACK_LIBRARY_PATH);
        }
        else if ( (strcmp(key, "DYLD_ROOT_PATH") == 0) || (strcmp(key, "DYLD_PATHS_ROOT") == 0) ) {
                if ( strcmp(value, "/") != 0 ) {
        }
        else if ( (strcmp(key, "DYLD_ROOT_PATH") == 0) || (strcmp(key, "DYLD_PATHS_ROOT") == 0) ) {
                if ( strcmp(value, "/") != 0 ) {
-                       gLinkContext.rootPaths = parseColonList(value);
+                       gLinkContext.rootPaths = parseColonList(value, mainExecutableDir);
                        for (int i=0; gLinkContext.rootPaths[i] != NULL; ++i) {
                                if ( gLinkContext.rootPaths[i][0] != '/' ) {
                                        dyld::warn("DYLD_ROOT_PATH not used because it contains a non-absolute path\n");
                        for (int i=0; gLinkContext.rootPaths[i] != NULL; ++i) {
                                if ( gLinkContext.rootPaths[i][0] != '/' ) {
                                        dyld::warn("DYLD_ROOT_PATH not used because it contains a non-absolute path\n");
@@ -928,7 +1240,7 @@ void processDyldEnvironmentVarible(const char* key, const char* value)
                gLinkContext.imageSuffix = value;
        }
        else if ( strcmp(key, "DYLD_INSERT_LIBRARIES") == 0 ) {
                gLinkContext.imageSuffix = value;
        }
        else if ( strcmp(key, "DYLD_INSERT_LIBRARIES") == 0 ) {
-               sEnv.DYLD_INSERT_LIBRARIES = parseColonList(value);
+               sEnv.DYLD_INSERT_LIBRARIES = parseColonList(value, NULL);
        }
        else if ( strcmp(key, "DYLD_PRINT_OPTS") == 0 ) {
                sEnv.DYLD_PRINT_OPTS = true;
        }
        else if ( strcmp(key, "DYLD_PRINT_OPTS") == 0 ) {
                sEnv.DYLD_PRINT_OPTS = true;
@@ -989,8 +1301,14 @@ void processDyldEnvironmentVarible(const char* key, const char* value)
        else if ( strcmp(key, "DYLD_PRINT_WARNINGS") == 0 ) {
                gLinkContext.verboseWarnings = true;
        }
        else if ( strcmp(key, "DYLD_PRINT_WARNINGS") == 0 ) {
                gLinkContext.verboseWarnings = true;
        }
-       else if ( strcmp(key, "DYLD_NO_PIE") == 0 ) {
-               gLinkContext.noPIE = true;
+       else if ( strcmp(key, "DYLD_PRINT_RPATHS") == 0 ) {
+               gLinkContext.verboseRPaths = true;
+       }
+       else if ( strcmp(key, "DYLD_PRINT_CS_NOTIFICATIONS") == 0 ) {
+               sEnv.DYLD_PRINT_CS_NOTIFICATIONS = true;
+       }
+       else if ( strcmp(key, "DYLD_PRINT_INTERPOSING") == 0 ) {
+               gLinkContext.verboseInterposing = true;
        }
        else if ( strcmp(key, "DYLD_SHARED_REGION") == 0 ) {
                if ( strcmp(value, "private") == 0 ) {
        }
        else if ( strcmp(key, "DYLD_SHARED_REGION") == 0 ) {
                if ( strcmp(value, "private") == 0 ) {
@@ -1034,12 +1352,83 @@ void processDyldEnvironmentVarible(const char* key, const char* value)
                        dyld::warn("unknown option to DYLD_IGNORE_PREBINDING.  Valid options are: all, app, nonsplit\n");
                }
        }
                        dyld::warn("unknown option to DYLD_IGNORE_PREBINDING.  Valid options are: all, app, nonsplit\n");
                }
        }
+#if SUPPORT_VERSIONED_PATHS
+       else if ( strcmp(key, "DYLD_VERSIONED_LIBRARY_PATH") == 0 ) {
+               appendParsedColonList(value, mainExecutableDir, &sEnv.DYLD_VERSIONED_LIBRARY_PATH);
+       }
+       else if ( strcmp(key, "DYLD_VERSIONED_FRAMEWORK_PATH") == 0 ) {
+               appendParsedColonList(value, mainExecutableDir, &sEnv.DYLD_VERSIONED_FRAMEWORK_PATH);
+       }
+#endif
        else {
                dyld::warn("unknown environment variable: %s\n", key);
        }
 }
 
 
        else {
                dyld::warn("unknown environment variable: %s\n", key);
        }
 }
 
 
+#if SUPPORT_LC_DYLD_ENVIRONMENT
+static void checkLoadCommandEnvironmentVariables()
+{
+       // <rdar://problem/8440934> Support augmenting dyld environment variables in load commands
+       const uint32_t cmd_count = sMainExecutableMachHeader->ncmds;
+       const struct load_command* const cmds = (struct load_command*)(((char*)sMainExecutableMachHeader)+sizeof(macho_header));
+       const struct load_command* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               switch (cmd->cmd) {
+                       case LC_DYLD_ENVIRONMENT:
+                       {
+                               const struct dylinker_command* envcmd = (struct dylinker_command*)cmd;
+                               const char* keyEqualsValue = (char*)envcmd + envcmd->name.offset;
+                               char mainExecutableDir[strlen(sExecPath)];
+                               strcpy(mainExecutableDir, sExecPath);
+                               char* lastSlash = strrchr(mainExecutableDir, '/');
+                               if ( lastSlash != NULL)
+                                       lastSlash[1] = '\0';
+                               // only process variables that start with DYLD_ and end in _PATH
+                               if ( (strncmp(keyEqualsValue, "DYLD_", 5) == 0) ) {
+                                       const char* equals = strchr(keyEqualsValue, '=');
+                                       if ( equals != NULL ) {
+                                               if ( strncmp(&equals[-5], "_PATH", 5) == 0 ) {
+                                                       const char* value = &equals[1];
+                                                       const int keyLen = equals-keyEqualsValue;
+                                                       char key[keyLen+1];
+                                                       strncpy(key, keyEqualsValue, keyLen);
+                                                       key[keyLen] = '\0';
+                                                       //dyld::log("processing: %s\n", keyEqualsValue);
+                                                       //dyld::log("mainExecutableDir: %s\n", mainExecutableDir);
+                                                       processDyldEnvironmentVariable(key, value, mainExecutableDir);
+                                               }
+                                       }
+                               }
+                       }
+                       break;
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+       }
+}
+#endif // SUPPORT_LC_DYLD_ENVIRONMENT  
+
+
+#if SUPPORT_VERSIONED_PATHS
+static void checkVersionedPaths()
+{
+       // search DYLD_VERSIONED_LIBRARY_PATH directories for dylibs and check if they are newer
+       if ( sEnv.DYLD_VERSIONED_LIBRARY_PATH != NULL ) {
+               for(const char* const* lp = sEnv.DYLD_VERSIONED_LIBRARY_PATH; *lp != NULL; ++lp) {
+                       checkDylibOverridesInDir(*lp);
+               }
+       }
+       
+       // search DYLD_VERSIONED_FRAMEWORK_PATH directories for dylibs and check if they are newer
+       if ( sEnv.DYLD_VERSIONED_FRAMEWORK_PATH != NULL ) {
+               for(const char* const* fp = sEnv.DYLD_VERSIONED_FRAMEWORK_PATH; *fp != NULL; ++fp) {
+                       checkFrameworkOverridesInDir(*fp);
+               }
+       }
+}
+#endif 
+
+
 //
 // For security, setuid programs ignore DYLD_* environment variables.
 // Additionally, the DYLD_* enviroment variables are removed
 //
 // For security, setuid programs ignore DYLD_* environment variables.
 // Additionally, the DYLD_* enviroment variables are removed
@@ -1066,6 +1455,8 @@ static void pruneEnvironmentVariables(const char* envp[], const char*** applep)
                do {
                        *d = d[removedCount];
                } while ( *d++ != NULL );
                do {
                        *d = d[removedCount];
                } while ( *d++ != NULL );
+               for(int i=0; i < removedCount; ++i)
+                       *d++ = NULL;
        }
        
        // disable framework and library fallback paths for setuid binaries rdar://problem/4589305
        }
        
        // disable framework and library fallback paths for setuid binaries rdar://problem/4589305
@@ -1088,7 +1479,7 @@ static void checkEnvironmentVariables(const char* envp[], bool ignoreEnviron)
                                char key[keyLen+1];
                                strncpy(key, keyEqualsValue, keyLen);
                                key[keyLen] = '\0';
                                char key[keyLen+1];
                                strncpy(key, keyEqualsValue, keyLen);
                                key[keyLen] = '\0';
-                               processDyldEnvironmentVarible(key, value);
+                               processDyldEnvironmentVariable(key, value, NULL);
                        }
                }
            else if ( strncmp(keyEqualsValue, "HOME=", 5) == 0 ) {
                        }
                }
            else if ( strncmp(keyEqualsValue, "HOME=", 5) == 0 ) {
@@ -1096,9 +1487,13 @@ static void checkEnvironmentVariables(const char* envp[], bool ignoreEnviron)
                }
                else if ( strncmp(keyEqualsValue, "LD_LIBRARY_PATH=", 16) == 0 ) {
                        const char* path = &keyEqualsValue[16];
                }
                else if ( strncmp(keyEqualsValue, "LD_LIBRARY_PATH=", 16) == 0 ) {
                        const char* path = &keyEqualsValue[16];
-                       sEnv.LD_LIBRARY_PATH = parseColonList(path);
+                       sEnv.LD_LIBRARY_PATH = parseColonList(path, NULL);
                }
        }
                }
        }
+
+#if SUPPORT_LC_DYLD_ENVIRONMENT
+       checkLoadCommandEnvironmentVariables();
+#endif // SUPPORT_LC_DYLD_ENVIRONMENT  
        
        // default value for DYLD_FALLBACK_FRAMEWORK_PATH, if not set in environment
        if ( sEnv.DYLD_FALLBACK_FRAMEWORK_PATH == NULL ) {
        
        // default value for DYLD_FALLBACK_FRAMEWORK_PATH, if not set in environment
        if ( sEnv.DYLD_FALLBACK_FRAMEWORK_PATH == NULL ) {
@@ -1119,34 +1514,38 @@ static void checkEnvironmentVariables(const char* envp[], bool ignoreEnviron)
                        paths_expand_roots(paths, "$HOME", home);
                sEnv.DYLD_FALLBACK_LIBRARY_PATH = paths;
        }
                        paths_expand_roots(paths, "$HOME", home);
                sEnv.DYLD_FALLBACK_LIBRARY_PATH = paths;
        }
+       
+#if SUPPORT_VERSIONED_PATHS
+       checkVersionedPaths();
+#endif 
 }
 
 
 static void getHostInfo()
 {
 }
 
 
 static void getHostInfo()
 {
-#if 1
+#if CPU_SUBTYPES_SUPPORTED
+#if __ARM_ARCH_7A__
+       sHostCPU                = CPU_TYPE_ARM;
+       sHostCPUsubtype = CPU_SUBTYPE_ARM_V7;
+#elif __ARM_ARCH_6K__
+       sHostCPU                = CPU_TYPE_ARM;
+       sHostCPUsubtype = CPU_SUBTYPE_ARM_V6;
+#else
        struct host_basic_info info;
        mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
        mach_port_t hostPort = mach_host_self();
        kern_return_t result = host_info(hostPort, HOST_BASIC_INFO, (host_info_t)&info, &count);
        if ( result != KERN_SUCCESS )
                throw "host_info() failed";
        struct host_basic_info info;
        mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
        mach_port_t hostPort = mach_host_self();
        kern_return_t result = host_info(hostPort, HOST_BASIC_INFO, (host_info_t)&info, &count);
        if ( result != KERN_SUCCESS )
                throw "host_info() failed";
-       
        sHostCPU                = info.cpu_type;
        sHostCPUsubtype = info.cpu_subtype;
        sHostCPU                = info.cpu_type;
        sHostCPUsubtype = info.cpu_subtype;
-#else
-       size_t valSize = sizeof(sHostCPU);
-       if (sysctlbyname ("hw.cputype", &sHostCPU, &valSize, NULL, 0) != 0) 
-               throw "sysctlbyname(hw.cputype) failed";
-       valSize = sizeof(sHostCPUsubtype);
-       if (sysctlbyname ("hw.cpusubtype", &sHostCPUsubtype, &valSize, NULL, 0) != 0) 
-               throw "sysctlbyname(hw.cpusubtype) failed";
+#endif
 #endif
 }
 
 static void checkSharedRegionDisable()
 {
 #endif
 }
 
 static void checkSharedRegionDisable()
 {
-       #if !__LP64__
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        // if main executable has segments that overlap the shared region, 
        // then disable using the shared region
        if ( sMainExecutable->overlapsWithAddressRange((void*)(uintptr_t)SHARED_REGION_BASE, (void*)(uintptr_t)(SHARED_REGION_BASE + SHARED_REGION_SIZE)) ) {
        // if main executable has segments that overlap the shared region, 
        // then disable using the shared region
        if ( sMainExecutable->overlapsWithAddressRange((void*)(uintptr_t)SHARED_REGION_BASE, (void*)(uintptr_t)(SHARED_REGION_BASE + SHARED_REGION_SIZE)) ) {
@@ -1154,7 +1553,8 @@ static void checkSharedRegionDisable()
                if ( gLinkContext.verboseMapping )
                        dyld::warn("disabling shared region because main executable overlaps\n");
        }
                if ( gLinkContext.verboseMapping )
                        dyld::warn("disabling shared region because main executable overlaps\n");
        }
-       #endif
+#endif
+       // iPhoneOS cannot run without shared region
 }
 
 bool validImage(const ImageLoader* possibleImage)
 }
 
 bool validImage(const ImageLoader* possibleImage)
@@ -1563,70 +1963,73 @@ static ImageLoader* instantiateFromLoadedImage(const macho_header* mh, uintptr_t
        throw "main executable not a known format";
 }
 
        throw "main executable not a known format";
 }
 
+
 #if DYLD_SHARED_CACHE_SUPPORT
 #if DYLD_SHARED_CACHE_SUPPORT
-bool inSharedCache(const char* path)
+static bool findInSharedCacheImage(const char* path, const struct stat* stat_buf, const macho_header** mh, const char** pathInCache, long* slide)
 {
        if ( sSharedCache != NULL ) {
 {
        if ( sSharedCache != NULL ) {
-               struct stat stat_buf;
-               if ( stat(path, &stat_buf) == -1 )
-                       return false;
-               
+#if __MAC_OS_X_VERSION_MIN_REQUIRED    
+               // Mac OS X always requires inode/mtime to valid cache
+               // if stat() not done yet, do it now
+               struct stat statb;
+               if ( stat_buf == NULL ) {
+                       if ( stat(path, &statb) == -1 )
+                               return false;
+                       stat_buf = &statb;
+               }
+#endif
                // walk shared cache to see if there is a cached image that matches the inode/mtime/path desired
                const dyld_cache_image_info* const start = (dyld_cache_image_info*)((uint8_t*)sSharedCache + sSharedCache->imagesOffset);
                const dyld_cache_image_info* const end = &start[sSharedCache->imagesCount];
                for( const dyld_cache_image_info* p = start; p != end; ++p) {
                // walk shared cache to see if there is a cached image that matches the inode/mtime/path desired
                const dyld_cache_image_info* const start = (dyld_cache_image_info*)((uint8_t*)sSharedCache + sSharedCache->imagesOffset);
                const dyld_cache_image_info* const end = &start[sSharedCache->imagesCount];
                for( const dyld_cache_image_info* p = start; p != end; ++p) {
+#if __IPHONE_OS_VERSION_MIN_REQUIRED   
+                       // just check path
+                       const char* aPath = (char*)sSharedCache + p->pathFileOffset;
+                       if ( strcmp(path, aPath) == 0 ) {
+                               // found image in cache
+                               *mh = (macho_header*)(p->address+sSharedCacheSlide);
+                               *pathInCache = aPath;
+                               *slide = sSharedCacheSlide;
+                               return true;
+                       }
+#elif __MAC_OS_X_VERSION_MIN_REQUIRED
                        // check mtime and inode first because it is fast
                        if ( sSharedCacheIgnoreInodeAndTimeStamp 
                        // check mtime and inode first because it is fast
                        if ( sSharedCacheIgnoreInodeAndTimeStamp 
-                               || ( ((time_t)p->modTime == stat_buf.st_mtime) && ((ino_t)p->inode == stat_buf.st_ino) ) ) {
+                               || ( ((time_t)p->modTime == stat_buf->st_mtime) && ((ino_t)p->inode == stat_buf->st_ino) ) ) {
                                // mod-time and inode match an image in the shared cache, now check path
                                // mod-time and inode match an image in the shared cache, now check path
-                               const char* pathInCache = (char*)sSharedCache + p->pathFileOffset;
-                               bool cacheHit = (strcmp(path, pathInCache) == 0);
+                               const char* aPath = (char*)sSharedCache + p->pathFileOffset;
+                               bool cacheHit = (strcmp(path, aPath) == 0);
                                if ( ! cacheHit ) {
                                        // path does not match install name of dylib in cache, but inode and mtime does match
                                        // perhaps path is a symlink to the cached dylib
                                        struct stat pathInCacheStatBuf;
                                if ( ! cacheHit ) {
                                        // path does not match install name of dylib in cache, but inode and mtime does match
                                        // perhaps path is a symlink to the cached dylib
                                        struct stat pathInCacheStatBuf;
-                                       if ( stat(pathInCache, &pathInCacheStatBuf) != -1 )
-                                               cacheHit = ( (pathInCacheStatBuf.st_dev == stat_buf.st_dev) && (pathInCacheStatBuf.st_ino == stat_buf.st_ino) );        
+                                       if ( stat(aPath, &pathInCacheStatBuf) != -1 )
+                                               cacheHit = ( (pathInCacheStatBuf.st_dev == stat_buf->st_dev) && (pathInCacheStatBuf.st_ino == stat_buf->st_ino) );      
                                }
                                if ( cacheHit ) {
                                }
                                if ( cacheHit ) {
-                                       // found image in cache
+                                       // found image in cache, return info
+                                       *mh = (macho_header*)(p->address+sSharedCacheSlide);
+                                       //dyld::log("findInSharedCacheImage(), mh=%p, p->address=0x%0llX, slid=0x%0lX, path=%p\n", 
+                                       //      *mh, p->address, sSharedCacheSlide, aPath);
+                                       *pathInCache = aPath;
+                                       *slide = sSharedCacheSlide;
                                        return true;
                                }
                        }
                                        return true;
                                }
                        }
+#endif
                }       
        }
        return false;
 }
 
                }       
        }
        return false;
 }
 
-static ImageLoader* findSharedCacheImage(const struct stat& stat_buf, const char* path)
+bool inSharedCache(const char* path)
 {
 {
-       if ( sSharedCache != NULL ) {
-               // walk shared cache to see if there is a cached image that matches the inode/mtime/path desired
-               const dyld_cache_image_info* const start = (dyld_cache_image_info*)((uint8_t*)sSharedCache + sSharedCache->imagesOffset);
-               const dyld_cache_image_info* const end = &start[sSharedCache->imagesCount];
-               for( const dyld_cache_image_info* p = start; p != end; ++p) {
-                       // check mtime and inode first because it is fast
-                       if ( sSharedCacheIgnoreInodeAndTimeStamp 
-                               || ( ((time_t)p->modTime == stat_buf.st_mtime) && ((ino_t)p->inode == stat_buf.st_ino) ) ) {
-                               // mod-time and inode match an image in the shared cache, now check path
-                               const char* pathInCache = (char*)sSharedCache + p->pathFileOffset;
-                               bool cacheHit = (strcmp(path, pathInCache) == 0);
-                               if ( ! cacheHit ) {
-                                       // path does not match install name of dylib in cache, but inode and mtime does match
-                                       // perhaps path is a symlink to the cached dylib
-                                       struct stat pathInCacheStatBuf;
-                                       if ( stat(pathInCache, &pathInCacheStatBuf) != -1 )
-                                               cacheHit = ( (pathInCacheStatBuf.st_dev == stat_buf.st_dev) && (pathInCacheStatBuf.st_ino == stat_buf.st_ino) );        
-                               }
-                               if ( cacheHit ) {
-                                       // found image in cache, instantiate an ImageLoader with it
-                                       return ImageLoaderMachO::instantiateFromCache((macho_header*)(p->address), pathInCache, stat_buf, gLinkContext);
-                               }
-                       }
-               }       
-       }
-       return NULL;
+       const macho_header* mhInCache;
+       const char*                     pathInCache;
+       long                            slide;
+       return findInSharedCacheImage(path, NULL, &mhInCache, &pathInCache, &slide);
 }
 }
+
 #endif
 
 static ImageLoader* checkandAddImage(ImageLoader* image, const LoadContext& context)
 #endif
 
 static ImageLoader* checkandAddImage(ImageLoader* image, const LoadContext& context)
@@ -1640,6 +2043,7 @@ static ImageLoader* checkandAddImage(ImageLoader* image, const LoadContext& cont
                        if ( installPath != NULL) {
                                if ( strcmp(loadedImageInstallPath, installPath) == 0 ) {
                                        //dyld::log("duplicate(%s) => %p\n", installPath, anImage);
                        if ( installPath != NULL) {
                                if ( strcmp(loadedImageInstallPath, installPath) == 0 ) {
                                        //dyld::log("duplicate(%s) => %p\n", installPath, anImage);
+                                       removeImage(image);
                                        ImageLoader::deleteImage(image);
                                        return anImage;
                                }
                                        ImageLoader::deleteImage(image);
                                        return anImage;
                                }
@@ -1667,7 +2071,7 @@ static ImageLoader* checkandAddImage(ImageLoader* image, const LoadContext& cont
 }
 
 // map in file and instantiate an ImageLoader
 }
 
 // map in file and instantiate an ImageLoader
-static ImageLoader* loadPhase6(int fd, struct stat& stat_buf, const char* path, const LoadContext& context)
+static ImageLoader* loadPhase6(int fd, const struct stat& stat_buf, const char* path, const LoadContext& context)
 {
        //dyld::log("%s(%s)\n", __func__ , path);
        uint64_t fileOffset = 0;
 {
        //dyld::log("%s(%s)\n", __func__ , path);
        uint64_t fileOffset = 0;
@@ -1706,10 +2110,20 @@ static ImageLoader* loadPhase6(int fd, struct stat& stat_buf, const char* path,
        }
        
        // try mach-o loader
        }
        
        // try mach-o loader
+       if ( shortPage ) 
+               throw "file too short";
        if ( isCompatibleMachO(firstPage, path) ) {
        if ( isCompatibleMachO(firstPage, path) ) {
-               if ( shortPage ) 
-                       throw "file too short";
 
 
+               // only MH_BUNDLE, MH_DYLIB, and some MH_EXECUTE can be dynamically loaded
+               switch ( ((mach_header*)firstPage)->filetype ) {
+                       case MH_EXECUTE:
+                       case MH_DYLIB:
+                       case MH_BUNDLE:
+                               break;
+                       default:
+                               throw "mach-o, but wrong filetype";
+               }
+               
                // instantiate an image
                ImageLoader* image = ImageLoaderMachO::instantiateFromFile(path, fd, firstPage, fileOffset, fileLength, stat_buf, gLinkContext);
                
                // instantiate an image
                ImageLoader* image = ImageLoaderMachO::instantiateFromFile(path, fd, firstPage, fileOffset, fileLength, stat_buf, gLinkContext);
                
@@ -1734,8 +2148,37 @@ static ImageLoader* loadPhase6(int fd, struct stat& stat_buf, const char* path,
 }
 
 
 }
 
 
-// try to open file
-static ImageLoader* loadPhase5open(const char* path, const LoadContext& context, std::vector<const char*>* exceptions)
+static ImageLoader* loadPhase5open(const char* path, const LoadContext& context, const struct stat& stat_buf, std::vector<const char*>* exceptions)
+{
+       //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
+
+       // open file (automagically closed when this function exits)
+       FileOpener file(path);
+               
+       // just return NULL if file not found, but record any other errors
+       if ( file.getFileDescriptor() == -1 ) {
+               int err = errno;
+               if ( err != ENOENT ) {
+                       const char* newMsg = dyld::mkstringf("%s: open() failed with errno=%d", path, err);
+                       exceptions->push_back(newMsg);
+               }
+               return NULL;
+       }
+
+       try {
+               return loadPhase6(file.getFileDescriptor(), stat_buf, path, context);
+       }
+       catch (const char* msg) {
+               const char* newMsg = dyld::mkstringf("%s: %s", path, msg);
+               exceptions->push_back(newMsg);
+               free((void*)msg);
+               return NULL;
+       }
+}
+
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED    
+static ImageLoader* loadPhase5load(const char* path, const char* orgPath, const LoadContext& context, std::vector<const char*>* exceptions)
 {
        //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
        ImageLoader* image = NULL;
 {
        //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
        ImageLoader* image = NULL;
@@ -1761,40 +2204,111 @@ static ImageLoader* loadPhase5open(const char* path, const LoadContext& context,
 
 #if DYLD_SHARED_CACHE_SUPPORT
        // see if this image is in shared cache
 
 #if DYLD_SHARED_CACHE_SUPPORT
        // see if this image is in shared cache
-       image = findSharedCacheImage(stat_buf, path);
-       if ( image != NULL ) {
+       const macho_header* mhInCache;
+       const char*                     pathInCache;
+       long                            slideInCache;
+       if ( findInSharedCacheImage(path, &stat_buf, &mhInCache, &pathInCache, &slideInCache) ) {
+               image = ImageLoaderMachO::instantiateFromCache(mhInCache, pathInCache, slideInCache, stat_buf, gLinkContext);
                return checkandAddImage(image, context);
        }
 #endif
                return checkandAddImage(image, context);
        }
 #endif
-       
-       // open file (automagically closed when this function exits)
-       FileOpener file(path);
-               
-       // just return NULL if file not found, but record any other errors
-       if ( file.getFileDescriptor() == -1 ) {
-               int err = errno;
-               if ( err != ENOENT ) {
-                       const char* newMsg = dyld::mkstringf("%s: open() failed with errno=%d", path, err);
-                       exceptions->push_back(newMsg);
+       // file exists and is not in dyld shared cache, so open it
+       return loadPhase5open(path, context, stat_buf, exceptions);
+}
+#endif // __MAC_OS_X_VERSION_MIN_REQUIRED
+
+
+
+#if __IPHONE_OS_VERSION_MIN_REQUIRED 
+static ImageLoader* loadPhase5stat(const char* path, const LoadContext& context, struct stat* stat_buf, 
+                                                                       int* statErrNo, bool* imageFound, std::vector<const char*>* exceptions)
+{
+       ImageLoader* image = NULL;
+       *imageFound = false;
+       if ( 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 ) {
+                       *imageFound = true;
+                       return image;
+               }
+               // do nothing if not already loaded and if RTLD_NOLOAD 
+               if ( context.dontLoad ) {
+                       *imageFound = true;
+                       return NULL;
+               }
+               image = loadPhase5open(path, context, *stat_buf, exceptions);
+               if ( image != NULL ) {
+                       *imageFound = true;
+                       return image;
                }
                }
-               return NULL;
        }
        }
+       else {
+               *statErrNo = errno;
+       }
+       return NULL;
+}
 
 
-       try {
-               return loadPhase6(file.getFileDescriptor(), stat_buf, path, context);
+// try to open file
+static ImageLoader* loadPhase5load(const char* path, const char* orgPath, const LoadContext& context, std::vector<const char*>* exceptions)
+{
+       //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
+       struct stat stat_buf;
+       bool imageFound;
+       int statErrNo;
+       ImageLoader* image;
+#if DYLD_SHARED_CACHE_SUPPORT
+       if ( sDylibsOverrideCache ) {
+               // flag is set that allows installed framework roots to override dyld shared cache
+               image = loadPhase5stat(path, context, &stat_buf, &statErrNo, &imageFound, exceptions);
+               if ( imageFound )
+                       return image;
        }
        }
-       catch (const char* msg) {
-               const char* newMsg = dyld::mkstringf("%s: %s", path, msg);
-               exceptions->push_back(newMsg);
-               free((void*)msg);
-               return NULL;
+       // see if this image is in shared cache
+       const macho_header* mhInCache;
+       const char*                     pathInCache;
+       long                            slideInCache;
+       if ( findInSharedCacheImage(path, NULL, &mhInCache, &pathInCache, &slideInCache) ) {
+               // see if this image in the cache was already loaded via a different path
+               for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); ++it) {
+                       ImageLoader* anImage = *it;
+                       if ( anImage->machHeader() == mhInCache )
+                               return anImage;
+               }
+               // do nothing if not already loaded and if RTLD_NOLOAD 
+               if ( context.dontLoad )
+                       return NULL;
+               // nope, so instantiate a new image from dyld shared cache
+               // <rdar://problem/7014995> zero out stat buffer so mtime, etc are zero for items from the shared cache
+               bzero(&stat_buf, sizeof(stat_buf));
+               image = ImageLoaderMachO::instantiateFromCache(mhInCache, pathInCache, slideInCache, stat_buf, gLinkContext);
+               return checkandAddImage(image, context);
        }
        }
+       
+       if ( !sDylibsOverrideCache ) {
+               // flag is not set, and not in cache to try opening it
+               image = loadPhase5stat(path, context, &stat_buf, &statErrNo, &imageFound, exceptions);
+               if ( imageFound )
+                       return image;
+       }
+#else
+       image = loadPhase5stat(path, context, &stat_buf, &statErrNo, &imageFound, exceptions);
+       if ( imageFound )
+               return image;
+#endif
+       // just return NULL if file not found, but record any other errors
+       if ( statErrNo != ENOENT ) {
+               exceptions->push_back(dyld::mkstringf("%s: stat() failed with errno=%d", path, statErrNo));
+       }
+       return NULL;
 }
 }
+#endif // __IPHONE_OS_VERSION_MIN_REQUIRED
+
 
 // look for path match with existing loaded images
 
 // look for path match with existing loaded images
-static ImageLoader* loadPhase5check(const char* path, const LoadContext& context)
+static ImageLoader* loadPhase5check(const char* path, const char* orgPath, const LoadContext& context)
 {
 {
-       //dyld::log("%s(%s)\n", __func__ , path);
+       //dyld::log("%s(%s, %s)\n", __func__ , path, orgPath);
        // search path against load-path and install-path of all already loaded images
        uint32_t hash = ImageLoader::hash(path);
        //dyld::log("check() hash=%d, path=%s\n", hash, path);
        // search path against load-path and install-path of all already loaded images
        uint32_t hash = ImageLoader::hash(path);
        //dyld::log("check() hash=%d, path=%s\n", hash, path);
@@ -1802,12 +2316,13 @@ static ImageLoader* loadPhase5check(const char* path, const LoadContext& context
                ImageLoader* anImage = *it;
                // check hash first to cut down on strcmp calls
                //dyld::log("    check() hash=%d, path=%s\n", anImage->getPathHash(), anImage->getPath());
                ImageLoader* anImage = *it;
                // check hash first to cut down on strcmp calls
                //dyld::log("    check() hash=%d, path=%s\n", anImage->getPathHash(), anImage->getPath());
-               if ( anImage->getPathHash() == hash )
+               if ( anImage->getPathHash() == hash ) {
                        if ( strcmp(path, anImage->getPath()) == 0 ) {
                                // if we are looking for a dylib don't return something else
                                if ( !context.mustBeDylib || anImage->isDylib() )
                                        return anImage;
                        }
                        if ( strcmp(path, anImage->getPath()) == 0 ) {
                                // if we are looking for a dylib don't return something else
                                if ( !context.mustBeDylib || anImage->isDylib() )
                                        return anImage;
                        }
+               }
                if ( context.matchByInstallName || anImage->matchInstallPath() ) {
                        const char* installPath = anImage->getInstallPath();
                        if ( installPath != NULL) {
                if ( context.matchByInstallName || anImage->matchInstallPath() ) {
                        const char* installPath = anImage->getInstallPath();
                        if ( installPath != NULL) {
@@ -1818,6 +2333,16 @@ static ImageLoader* loadPhase5check(const char* path, const LoadContext& context
                                }
                        }
                }
                                }
                        }
                }
+               // an install name starting with @rpath should match by install name, not just real path
+               if ( (orgPath[0] == '@') && (strncmp(orgPath, "@rpath/", 7) == 0) ) {
+                       const char* installPath = anImage->getInstallPath();
+                       if ( installPath != NULL) {
+                               if ( !context.mustBeDylib || anImage->isDylib() ) {
+                                       if ( strcmp(orgPath, installPath) == 0 )
+                                               return anImage;
+                               }
+                       }
+               }
        }
        
        //dyld::log("%s(%s) => NULL\n", __func__,   path);
        }
        
        //dyld::log("%s(%s) => NULL\n", __func__,   path);
@@ -1826,37 +2351,46 @@ static ImageLoader* loadPhase5check(const char* path, const LoadContext& context
 
 
 // open or check existing
 
 
 // open or check existing
-static ImageLoader* loadPhase5(const char* path, const LoadContext& context, std::vector<const char*>* exceptions)
+static ImageLoader* loadPhase5(const char* path, const char* orgPath, const LoadContext& context, std::vector<const char*>* exceptions)
 {
        //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
 {
        //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
+       
+       // check for specific dylib overrides
+       for (std::vector<DylibOverride>::iterator it = sDylibOverrides.begin(); it != sDylibOverrides.end(); ++it) {
+               if ( strcmp(it->installName, path) == 0 ) {
+                       path = it->override;
+                       break;
+               }
+       }
+       
        if ( exceptions != NULL ) 
        if ( exceptions != NULL ) 
-               return loadPhase5open(path, context, exceptions);
+               return loadPhase5load(path, orgPath, context, exceptions);
        else
        else
-               return loadPhase5check(path, context);
+               return loadPhase5check(path, orgPath, context);
 }
 
 // try with and without image suffix
 }
 
 // try with and without image suffix
-static ImageLoader* loadPhase4(const char* path, const LoadContext& context, std::vector<const char*>* exceptions)
+static ImageLoader* loadPhase4(const char* path, const char* orgPath, const LoadContext& context, std::vector<const char*>* exceptions)
 {
        //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
        ImageLoader* image = NULL;
        if (  gLinkContext.imageSuffix != NULL ) {
                char pathWithSuffix[strlen(path)+strlen( gLinkContext.imageSuffix)+2];
                ImageLoader::addSuffix(path,  gLinkContext.imageSuffix, pathWithSuffix);
 {
        //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
        ImageLoader* image = NULL;
        if (  gLinkContext.imageSuffix != NULL ) {
                char pathWithSuffix[strlen(path)+strlen( gLinkContext.imageSuffix)+2];
                ImageLoader::addSuffix(path,  gLinkContext.imageSuffix, pathWithSuffix);
-               image = loadPhase5(pathWithSuffix, context, exceptions);
+               image = loadPhase5(pathWithSuffix, orgPath, context, exceptions);
        }
        if ( image == NULL )
        }
        if ( image == NULL )
-               image = loadPhase5(path, context, exceptions);
+               image = loadPhase5(path, orgPath, context, exceptions);
        return image;
 }
 
        return image;
 }
 
-static ImageLoader* loadPhase2(const char* path, const LoadContext& context, 
+static ImageLoader* loadPhase2(const char* path, const char* orgPath, const LoadContext& context, 
                                                           const char* const frameworkPaths[], const char* const libraryPaths[], 
                                                           std::vector<const char*>* exceptions); // forward reference
 
 
 // expand @ variables
                                                           const char* const frameworkPaths[], const char* const libraryPaths[], 
                                                           std::vector<const char*>* exceptions); // forward reference
 
 
 // expand @ variables
-static ImageLoader* loadPhase3(const char* path, const LoadContext& context, std::vector<const char*>* exceptions)
+static ImageLoader* loadPhase3(const char* path, const char* orgPath, const LoadContext& context, std::vector<const char*>* exceptions)
 {
        //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
        ImageLoader* image = NULL;
 {
        //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
        ImageLoader* image = NULL;
@@ -1873,7 +2407,7 @@ static ImageLoader* loadPhase3(const char* path, const LoadContext& context, std
                        strcpy(&addPoint[1], &path[17]);
                else
                        strcpy(newPath, &path[17]);
                        strcpy(&addPoint[1], &path[17]);
                else
                        strcpy(newPath, &path[17]);
-               image = loadPhase4(newPath, context, exceptions);
+               image = loadPhase4(newPath, orgPath, context, exceptions);
                if ( image != NULL ) 
                        return image;
 
                if ( image != NULL ) 
                        return image;
 
@@ -1887,7 +2421,7 @@ static ImageLoader* loadPhase3(const char* path, const LoadContext& context, std
                                strcpy(&addPoint[1], &path[17]);
                        else
                                strcpy(newRealPath, &path[17]);
                                strcpy(&addPoint[1], &path[17]);
                        else
                                strcpy(newRealPath, &path[17]);
-                       image = loadPhase4(newRealPath, context, exceptions);
+                       image = loadPhase4(newRealPath, orgPath, context, exceptions);
                        if ( image != NULL ) 
                                return image;
                }
                        if ( image != NULL ) 
                                return image;
                }
@@ -1904,7 +2438,7 @@ static ImageLoader* loadPhase3(const char* path, const LoadContext& context, std
                        strcpy(&addPoint[1], &path[13]);
                else
                        strcpy(newPath, &path[13]);
                        strcpy(&addPoint[1], &path[13]);
                else
                        strcpy(newPath, &path[13]);
-               image = loadPhase4(newPath, context, exceptions);
+               image = loadPhase4(newPath, orgPath, context, exceptions);
                if ( image != NULL ) 
                        return image;
                
                if ( image != NULL ) 
                        return image;
                
@@ -1918,7 +2452,7 @@ static ImageLoader* loadPhase3(const char* path, const LoadContext& context, std
                                strcpy(&addPoint[1], &path[13]);
                        else
                                strcpy(newRealPath, &path[13]);
                                strcpy(&addPoint[1], &path[13]);
                        else
                                strcpy(newRealPath, &path[13]);
-                       image = loadPhase4(newRealPath, context, exceptions);
+                       image = loadPhase4(newRealPath, orgPath, context, exceptions);
                        if ( image != NULL ) 
                                return image;
                }
                        if ( image != NULL ) 
                                return image;
                }
@@ -1934,7 +2468,13 @@ static ImageLoader* loadPhase3(const char* path, const LoadContext& context, std
                                        strcpy(newPath, anRPath);
                                        strcat(newPath, "/"); 
                                        strcat(newPath, trailingPath); 
                                        strcpy(newPath, anRPath);
                                        strcat(newPath, "/"); 
                                        strcat(newPath, trailingPath); 
-                                       image = loadPhase4(newPath, context, exceptions);
+                                       image = loadPhase4(newPath, orgPath, context, exceptions);
+                                       if ( gLinkContext.verboseRPaths && (exceptions != NULL) ) {
+                                               if ( image != NULL ) 
+                                                       dyld::log("RPATH successful expansion of %s to: %s\n", orgPath, newPath);
+                                               else
+                                                       dyld::log("RPATH failed to expanding     %s to: %s\n", orgPath, newPath);
+                                       }
                                        if ( image != NULL ) 
                                                return image;
                                }
                                        if ( image != NULL ) 
                                                return image;
                                }
@@ -1943,7 +2483,7 @@ static ImageLoader* loadPhase3(const char* path, const LoadContext& context, std
                
                // substitute @rpath with LD_LIBRARY_PATH
                if ( sEnv.LD_LIBRARY_PATH != NULL ) {
                
                // substitute @rpath with LD_LIBRARY_PATH
                if ( sEnv.LD_LIBRARY_PATH != NULL ) {
-                       image = loadPhase2(trailingPath, context, NULL, sEnv.LD_LIBRARY_PATH, exceptions);
+                       image = loadPhase2(trailingPath, orgPath, context, NULL, sEnv.LD_LIBRARY_PATH, exceptions);
                        if ( image != NULL )
                                return image;
                }
                        if ( image != NULL )
                                return image;
                }
@@ -1956,12 +2496,12 @@ static ImageLoader* loadPhase3(const char* path, const LoadContext& context, std
                throwf("unsafe use of relative rpath %s in %s with restricted binary", path, context.origin);
        }
        
                throwf("unsafe use of relative rpath %s in %s with restricted binary", path, context.origin);
        }
        
-       return loadPhase4(path, context, exceptions);
+       return loadPhase4(path, orgPath, context, exceptions);
 }
 
 
 // try search paths
 }
 
 
 // try search paths
-static ImageLoader* loadPhase2(const char* path, const LoadContext& context, 
+static ImageLoader* loadPhase2(const char* path, const char* orgPath, const LoadContext& context, 
                                                           const char* const frameworkPaths[], const char* const libraryPaths[], 
                                                           std::vector<const char*>* exceptions)
 {
                                                           const char* const frameworkPaths[], const char* const libraryPaths[], 
                                                           std::vector<const char*>* exceptions)
 {
@@ -1977,7 +2517,7 @@ static ImageLoader* loadPhase2(const char* path, const LoadContext& context,
                                strcat(npath, "/");
                                strcat(npath, frameworkPartialPath);
                                //dyld::log("dyld: fallback framework path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, npath);
                                strcat(npath, "/");
                                strcat(npath, frameworkPartialPath);
                                //dyld::log("dyld: fallback framework path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, npath);
-                               image = loadPhase4(npath, context, exceptions);
+                               image = loadPhase4(npath, orgPath, context, exceptions);
                                if ( image != NULL )
                                        return image;
                        }
                                if ( image != NULL )
                                        return image;
                        }
@@ -1992,7 +2532,7 @@ static ImageLoader* loadPhase2(const char* path, const LoadContext& context,
                        strcat(libpath, "/");
                        strcat(libpath, libraryLeafName);
                        //dyld::log("dyld: fallback library path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, libpath);
                        strcat(libpath, "/");
                        strcat(libpath, libraryLeafName);
                        //dyld::log("dyld: fallback library path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, libpath);
-                       image = loadPhase4(libpath, context, exceptions);
+                       image = loadPhase4(libpath, orgPath, context, exceptions);
                        if ( image != NULL )
                                return image;
                }
                        if ( image != NULL )
                                return image;
                }
@@ -2001,27 +2541,27 @@ static ImageLoader* loadPhase2(const char* path, const LoadContext& context,
 }
 
 // try search overrides and fallbacks
 }
 
 // try search overrides and fallbacks
-static ImageLoader* loadPhase1(const char* path, const LoadContext& context, std::vector<const char*>* exceptions)
+static ImageLoader* loadPhase1(const char* path, const char* orgPath, const LoadContext& context, std::vector<const char*>* exceptions)
 {
        //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
        ImageLoader* image = NULL;
 
        // handle LD_LIBRARY_PATH environment variables that force searching
        if ( context.useLdLibraryPath && (sEnv.LD_LIBRARY_PATH != NULL) ) {
 {
        //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
        ImageLoader* image = NULL;
 
        // handle LD_LIBRARY_PATH environment variables that force searching
        if ( context.useLdLibraryPath && (sEnv.LD_LIBRARY_PATH != NULL) ) {
-               image = loadPhase2(path, context, NULL, sEnv.LD_LIBRARY_PATH, exceptions);
+               image = loadPhase2(path, orgPath, context, NULL, sEnv.LD_LIBRARY_PATH, exceptions);
                if ( image != NULL )
                        return image;
        }
 
        // handle DYLD_ environment variables that force searching
        if ( context.useSearchPaths && ((sEnv.DYLD_FRAMEWORK_PATH != NULL) || (sEnv.DYLD_LIBRARY_PATH != NULL)) ) {
                if ( image != NULL )
                        return image;
        }
 
        // handle DYLD_ environment variables that force searching
        if ( context.useSearchPaths && ((sEnv.DYLD_FRAMEWORK_PATH != NULL) || (sEnv.DYLD_LIBRARY_PATH != NULL)) ) {
-               image = loadPhase2(path, context, sEnv.DYLD_FRAMEWORK_PATH, sEnv.DYLD_LIBRARY_PATH, exceptions);
+               image = loadPhase2(path, orgPath, context, sEnv.DYLD_FRAMEWORK_PATH, sEnv.DYLD_LIBRARY_PATH, exceptions);
                if ( image != NULL )
                        return image;
        }
        
        // try raw path
                if ( image != NULL )
                        return image;
        }
        
        // try raw path
-       image = loadPhase3(path, context, exceptions);
+       image = loadPhase3(path, orgPath, context, exceptions);
        if ( image != NULL )
                return image;
        
        if ( image != NULL )
                return image;
        
@@ -2030,7 +2570,7 @@ static ImageLoader* loadPhase1(const char* path, const LoadContext& context, std
        if ( (fallbackLibraryPaths != NULL) && !context.useFallbackPaths )
                fallbackLibraryPaths = NULL;
        if ( !context.dontLoad  && (exceptions != NULL) && ((sEnv.DYLD_FALLBACK_FRAMEWORK_PATH != NULL) || (fallbackLibraryPaths != NULL)) ) {
        if ( (fallbackLibraryPaths != NULL) && !context.useFallbackPaths )
                fallbackLibraryPaths = NULL;
        if ( !context.dontLoad  && (exceptions != NULL) && ((sEnv.DYLD_FALLBACK_FRAMEWORK_PATH != NULL) || (fallbackLibraryPaths != NULL)) ) {
-               image = loadPhase2(path, context, sEnv.DYLD_FALLBACK_FRAMEWORK_PATH, fallbackLibraryPaths, exceptions);
+               image = loadPhase2(path, orgPath, context, sEnv.DYLD_FALLBACK_FRAMEWORK_PATH, fallbackLibraryPaths, exceptions);
                if ( image != NULL )
                        return image;
        }
                if ( image != NULL )
                        return image;
        }
@@ -2039,7 +2579,7 @@ static ImageLoader* loadPhase1(const char* path, const LoadContext& context, std
 }
 
 // try root substitutions
 }
 
 // try root substitutions
-static ImageLoader* loadPhase0(const char* path, const LoadContext& context, std::vector<const char*>* exceptions)
+static ImageLoader* loadPhase0(const char* path, const char* orgPath, const LoadContext& context, std::vector<const char*>* exceptions)
 {
        //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
 
 {
        //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
 
@@ -2049,14 +2589,14 @@ static ImageLoader* loadPhase0(const char* path, const LoadContext& context, std
                        char newPath[strlen(*rootPath) + strlen(path)+2];
                        strcpy(newPath, *rootPath);
                        strcat(newPath, path);
                        char newPath[strlen(*rootPath) + strlen(path)+2];
                        strcpy(newPath, *rootPath);
                        strcat(newPath, path);
-                       ImageLoader* image = loadPhase1(newPath, context, exceptions);
+                       ImageLoader* image = loadPhase1(newPath, orgPath, context, exceptions);
                        if ( image != NULL )
                                return image;
                }
        }
 
        // try raw path
                        if ( image != NULL )
                                return image;
                }
        }
 
        // try raw path
-       return loadPhase1(path, context, exceptions);
+       return loadPhase1(path, orgPath, context, exceptions);
 }
 
 //
 }
 
 //
@@ -2075,6 +2615,9 @@ static ImageLoader* loadPhase0(const char* path, const LoadContext& context, std
 //
 ImageLoader* load(const char* path, const LoadContext& context)
 {
 //
 ImageLoader* load(const char* path, const LoadContext& context)
 {
+       CRSetCrashLogMessage2(path);
+       const char* orgPath = path;
+       
        //dyld::log("%s(%s)\n", __func__ , path);
        char realPath[PATH_MAX];
        // when DYLD_IMAGE_SUFFIX is in used, do a realpath(), otherwise a load of "Foo.framework/Foo" will not match
        //dyld::log("%s(%s)\n", __func__ , path);
        char realPath[PATH_MAX];
        // when DYLD_IMAGE_SUFFIX is in used, do a realpath(), otherwise a load of "Foo.framework/Foo" will not match
@@ -2084,18 +2627,36 @@ ImageLoader* load(const char* path, const LoadContext& context)
        }
        
        // try all path permutations and check against existing loaded images
        }
        
        // try all path permutations and check against existing loaded images
-       ImageLoader* image = loadPhase0(path, context, NULL);
-       if ( image != NULL )
+       ImageLoader* image = loadPhase0(path, orgPath, context, NULL);
+       if ( image != NULL ) {
+               CRSetCrashLogMessage2(NULL);
                return image;
                return image;
+       }
 
 
-       // try all path permutations and try open() until first sucesss
+       // try all path permutations and try open() until first success
        std::vector<const char*> exceptions;
        std::vector<const char*> exceptions;
-       image = loadPhase0(path, context, &exceptions);
-       if ( image != NULL )
+       image = loadPhase0(path, orgPath, context, &exceptions);
+    CRSetCrashLogMessage2(NULL);
+       if ( image != NULL ) {
+               // <rdar://problem/6916014> leak in dyld during dlopen when using DYLD_ variables
+               for (std::vector<const char*>::iterator it = exceptions.begin(); it != exceptions.end(); ++it) {
+                       free((void*)(*it));
+               }
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
+               // if loaded image is not from cache, but original path is in cache
+               // set gSharedCacheOverridden flag to disable some ObjC optimizations
+               if ( !gSharedCacheOverridden ) {
+                       if ( !image->inSharedCache() && inSharedCache(path) ) {
+                               gSharedCacheOverridden = true;
+                       }
+               }
+#endif
                return image;
                return image;
+       }
        else if ( exceptions.size() == 0 ) {
        else if ( exceptions.size() == 0 ) {
-               if ( context.dontLoad )
+               if ( context.dontLoad ) {
                        return NULL;
                        return NULL;
+               }
                else
                        throw "image not found";
        }
                else
                        throw "image not found";
        }
@@ -2122,44 +2683,83 @@ ImageLoader* load(const char* path, const LoadContext& context)
 #if DYLD_SHARED_CACHE_SUPPORT
 
 
 #if DYLD_SHARED_CACHE_SUPPORT
 
 
-// hack until dyld no longer needs to run on Leopard kernels that don't have new shared region syscall
-static bool newSharedRegionSyscallAvailable()
-{
-       int shreg_version;
-       size_t buffer_size = sizeof(shreg_version);
-       if ( sysctlbyname("vm.shared_region_version", &shreg_version, &buffer_size, NULL, 0) == 0 ) {
-          if ( shreg_version == 3 ) 
-                       return true;
-       }
-       return false;
-}
+
+
+#if __ppc__
+       #define ARCH_NAME                       "ppc"
+       #define ARCH_NAME_ROSETTA       "rosetta"
+       #define ARCH_CACHE_MAGIC        "dyld_v1     ppc"
+#elif __ppc64__
+       #define ARCH_NAME                       "ppc64"
+       #define ARCH_CACHE_MAGIC        "dyld_v1   ppc64"
+#elif __i386__
+       #define ARCH_NAME                       "i386"
+       #define ARCH_CACHE_MAGIC        "dyld_v1    i386"
+#elif __x86_64__
+       #define ARCH_NAME                       "x86_64"
+       #define ARCH_CACHE_MAGIC        "dyld_v1  x86_64"
+       #define SHARED_REGION_READ_ONLY_START   0x7FFF80000000LL
+       #define SHARED_REGION_READ_ONLY_END     0x7FFFC0000000LL
+       #define SHARED_REGION_WRITABLE_START    0x7FFF70000000LL
+       #define SHARED_REGION_WRITABLE_END      0x7FFF80000000LL
+       #define SLIDEABLE_CACHE_SUPPORT             1
+#elif __ARM_ARCH_5TEJ__
+       #define ARCH_NAME                       "armv5"
+       #define ARCH_CACHE_MAGIC        "dyld_v1   armv5"
+#elif __ARM_ARCH_6K__
+       #define ARCH_NAME                       "armv6"
+       #define ARCH_CACHE_MAGIC        "dyld_v1   armv6"
+#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
+#endif
 
 
 static int __attribute__((noinline)) _shared_region_check_np(uint64_t* start_address)
 {
 
 
 static int __attribute__((noinline)) _shared_region_check_np(uint64_t* start_address)
 {
-       if ( (gLinkContext.sharedRegionMode == ImageLoader::kUseSharedRegion) && newSharedRegionSyscallAvailable() 
+       if ( (gLinkContext.sharedRegionMode == ImageLoader::kUseSharedRegion) ) 
                return syscall(294, start_address);
        return -1;
 }
 
 
                return syscall(294, start_address);
        return -1;
 }
 
 
-static int __attribute__((noinline)) _shared_region_map_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)
 {
 {
-       int result;
-       if ( (gLinkContext.sharedRegionMode == ImageLoader::kUseSharedRegion) && newSharedRegionSyscallAvailable() ) {
-               return syscall(295, fd, count, mappings);
+#if __IPHONE_OS_VERSION_MIN_REQUIRED   
+       // register code signature blob for whole dyld cache
+       if ( codeSignatureMappingIndex != -1 ) {
+               fsignatures_t siginfo;
+               siginfo.fs_file_start = 0;  // cache always starts at beginning of file
+               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);
+       }
+#endif
+       if ( (gLinkContext.sharedRegionMode == ImageLoader::kUseSharedRegion) ) {
+               return syscall(438, fd, count, mappings, slide, slideInfo, slideInfoSize);
        }
 
        // remove the shared region sub-map
        vm_deallocate(mach_task_self(), (vm_address_t)SHARED_REGION_BASE, SHARED_REGION_SIZE);
        
        }
 
        // remove the shared region sub-map
        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;
+
        // map cache just for this process with mmap()
        // map cache just for this process with mmap()
-       bool failed = false;
-       const shared_file_mapping_np* start = mappings;
-       const shared_file_mapping_np* end = &mappings[count];
+       const shared_file_mapping_np* const start = mappings;
+       const shared_file_mapping_np* const end = &mappings[count];
        for (const shared_file_mapping_np* p = start; p < end; ++p ) {
                void* mmapAddress = (void*)(uintptr_t)(p->sfm_address);
                size_t size = p->sfm_size;
        for (const shared_file_mapping_np* p = start; p < end; ++p ) {
                void* mmapAddress = (void*)(uintptr_t)(p->sfm_address);
                size_t size = p->sfm_size;
+               //dyld::log("dyld: mapping address %p with size 0x%08lX\n", mmapAddress, size);
                int protection = 0;
                if ( p->sfm_init_prot & VM_PROT_EXECUTE )
                        protection   |= PROT_EXEC;
                int protection = 0;
                if ( p->sfm_init_prot & VM_PROT_EXECUTE )
                        protection   |= PROT_EXEC;
@@ -2168,45 +2768,57 @@ static int __attribute__((noinline)) _shared_region_map_np(int fd, uint32_t coun
                if ( p->sfm_init_prot & VM_PROT_WRITE )
                        protection   |= PROT_WRITE;
                off_t offset = p->sfm_file_offset;
                if ( p->sfm_init_prot & VM_PROT_WRITE )
                        protection   |= PROT_WRITE;
                off_t offset = p->sfm_file_offset;
-               mmapAddress = mmap(mmapAddress, size, protection, MAP_FIXED | MAP_PRIVATE, fd, offset);
-               if ( mmap(mmapAddress, size, protection, MAP_FIXED | MAP_PRIVATE, fd, offset) != mmapAddress )
-                       failed = true;
-       }
-       if ( !failed ) {
-               result = 0;
-               gLinkContext.sharedRegionMode = ImageLoader::kUsePrivateSharedRegion;
-       }
-       else {
-               result = -1;
-               gLinkContext.sharedRegionMode = ImageLoader::kDontUseSharedRegion;
-               if ( gLinkContext.verboseMapping ) 
-                       dyld::log("dyld: shared cached cannot be mapped\n");
+               if ( mmap(mmapAddress, size, protection, MAP_FIXED | MAP_PRIVATE, fd, offset) != mmapAddress ) {
+                       // failed to map some chunk of this shared cache file
+                       // clear shared region
+                       vm_deallocate(mach_task_self(), (vm_address_t)SHARED_REGION_BASE, SHARED_REGION_SIZE);
+                       // go back to not using shared region at all
+                       gLinkContext.sharedRegionMode = ImageLoader::kDontUseSharedRegion;
+                       if ( gLinkContext.verboseMapping ) {
+                               dyld::log("dyld: shared cached region cannot be mapped at address %p with size 0x%08lX\n",
+                                                       mmapAddress, size);
+                       }
+                       // return failure
+                       return -1;
+               }
+       }
+
+#if SLIDEABLE_CACHE_SUPPORT
+       // update all __DATA pages with slide info
+       if ( slide != 0 ) {
+               const uintptr_t dataPagesStart = mappings[1].sfm_address;
+               const dyld_cache_slide_info* slideInfoHeader = (dyld_cache_slide_info*)slideInfo;
+               const uint16_t* toc = (uint16_t*)((long)(slideInfoHeader) + slideInfoHeader->toc_offset);
+               const uint8_t* entries = (uint8_t*)((long)(slideInfoHeader) + slideInfoHeader->entries_offset);
+               for(uint32_t i=0; i < slideInfoHeader->toc_count; ++i) {
+                       const uint8_t* entry = &entries[toc[i]*slideInfoHeader->entries_size];
+                       const uint8_t* page = (uint8_t*)(long)(dataPagesStart + (4096*i));
+                       //dyld::log("page=%p toc[%d]=%d entries=%p\n", page, i, toc[i], entry);
+                       for(int j=0; j < 128; ++j) {
+                               uint8_t b = entry[j];
+                               //dyld::log("    entry[%d] = 0x%02X\n", j, b);
+                               if ( b != 0 ) {
+                                       for(int k=0; k < 8; ++k) {
+                                               if ( b & (1<<k) ) {
+                                                       uintptr_t* p = (uintptr_t*)(page + j*8*4 + k*4);
+                                                       uintptr_t value = *p;
+                                                       //dyld::log("        *%p was 0x%lX will be 0x%lX\n", p, value, value+sSharedCacheSlide);
+                                                       *p = value + slide;
+                                               }
+                                       }
+                               }
+                       }
+               }
        }
        }
+#endif // SLIDEABLE_CACHE_SUPPORT
 
 
-       return result;
+       // succesfully mapped shared cache for just this process
+       gLinkContext.sharedRegionMode = ImageLoader::kUsePrivateSharedRegion;
+       
+       return 0;
 }
 
 
 }
 
 
-
-#if __ppc__
-       #define ARCH_NAME                       "ppc"
-       #define ARCH_NAME_ROSETTA       "rosetta"
-       #define ARCH_VALUE                      CPU_TYPE_POWERPC
-       #define ARCH_CACHE_MAGIC        "dyld_v1     ppc"
-#elif __ppc64__
-       #define ARCH_NAME                       "ppc64"
-       #define ARCH_VALUE                      CPU_TYPE_POWERPC64
-       #define ARCH_CACHE_MAGIC        "dyld_v1   ppc64"
-#elif __i386__
-       #define ARCH_NAME                       "i386"
-       #define ARCH_VALUE                      CPU_TYPE_I386
-       #define ARCH_CACHE_MAGIC        "dyld_v1    i386"
-#elif __x86_64__
-       #define ARCH_NAME                       "x86_64"
-       #define ARCH_VALUE                      CPU_TYPE_X86_64
-       #define ARCH_CACHE_MAGIC        "dyld_v1  x86_64"
-#endif
-
 const void*    imMemorySharedCacheHeader()
 {
        return sSharedCache;
 const void*    imMemorySharedCacheHeader()
 {
        return sSharedCache;
@@ -2227,6 +2839,58 @@ int openSharedCacheFile()
        return ::open(path, O_RDONLY);
 }
 
        return ::open(path, O_RDONLY);
 }
 
+#if SLIDEABLE_CACHE_SUPPORT
+static long pickCacheSlide(uint32_t mappingsCount, shared_file_mapping_np mappings[])
+{
+       // get bounds of cache
+       uint64_t readOnlyLowAddress = 0;
+       uint64_t readOnlyHighAddress = 0;
+       uint64_t writableLowAddress = 0;
+       uint64_t writableHighAddress = 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;
+               }
+               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;
+                               }
+                       }
+               }
+       }
+       
+       // 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;
+       
+       // 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);
+       //dyld::log("slide=0x%0lX\n", slide);
+       
+       // update mappings
+       for(uint32_t i=0; i < mappingsCount; ++i) {
+               mappings[i].sfm_address += slide;
+       }
+       
+       return slide;
+}
+#endif // SLIDEABLE_CACHE_SUPPORT
+
 static void mapSharedCache()
 {
        uint64_t cacheBaseAddress;
 static void mapSharedCache()
 {
        uint64_t cacheBaseAddress;
@@ -2239,6 +2903,17 @@ static void mapSharedCache()
                        if ( gLinkContext.verboseMapping ) 
                                dyld::log("dyld: existing shared cached in memory is not compatible\n");
                }
                        if ( gLinkContext.verboseMapping ) 
                                dyld::log("dyld: existing shared cached in memory is not compatible\n");
                }
+               // check if cache file is slidable
+               dyld_cache_header* header = (dyld_cache_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::log("sSharedCacheSlide=0x%08lX, loadedAddress=%p, preferedLoadAddress=%p\n", sSharedCacheSlide, loadedAddress, preferedLoadAddress);
+               }
        }
        else {
 #if __i386__ || __x86_64__
        }
        else {
 #if __i386__ || __x86_64__
@@ -2251,13 +2926,13 @@ 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
                        // 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(DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME, &dyldCacheStatInfo) == 0 ) {
+                       if ( ::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) ) {
                                        // if the cache file was created before this boot, then throw it away and let it rebuild itself
                                        if ( dyldCacheStatInfo.st_mtime < bootTimeValue.tv_sec ) {
                                struct timeval bootTimeValue;
                                size_t bootTimeValueSize = sizeof(bootTimeValue);
                                if ( (sysctlbyname("kern.boottime", &bootTimeValue, &bootTimeValueSize, NULL, 0) == 0) && (bootTimeValue.tv_sec != 0) ) {
                                        // if the cache file was created before this boot, then throw it away and let it rebuild itself
                                        if ( dyldCacheStatInfo.st_mtime < bootTimeValue.tv_sec ) {
-                                               ::unlink(DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME);
+                                               ::unlink(MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME);
                                                gLinkContext.sharedRegionMode = ImageLoader::kDontUseSharedRegion;
                                                return;
                                        }
                                                gLinkContext.sharedRegionMode = ImageLoader::kDontUseSharedRegion;
                                                return;
                                        }
@@ -2272,22 +2947,48 @@ static void mapSharedCache()
                        if ( ::read(fd, firstPages, 8192) == 8192 ) {
                                dyld_cache_header* header = (dyld_cache_header*)firstPages;
                                if ( strcmp(header->magic, ARCH_CACHE_MAGIC) == 0 ) {
                        if ( ::read(fd, firstPages, 8192) == 8192 ) {
                                dyld_cache_header* header = (dyld_cache_header*)firstPages;
                                if ( strcmp(header->magic, ARCH_CACHE_MAGIC) == 0 ) {
-                                       const shared_file_mapping_np* mappings = (shared_file_mapping_np*)&firstPages[header->mappingOffset];
-                                       const shared_file_mapping_np* const end = &mappings[header->mappingCount];
+                                       const dyld_cache_mapping_info* const fileMappingsStart = (dyld_cache_mapping_info*)&firstPages[header->mappingOffset];
+                                       const dyld_cache_mapping_info* const fileMappingsEnd = &fileMappingsStart[header->mappingCount];
+                                       shared_file_mapping_np  mappings[header->mappingCount+1]; // add room for code-sig 
+                                       unsigned int mappingCount = header->mappingCount;
+                                       int codeSignatureMappingIndex = -1;
                                        // validate that the cache file has not been truncated
                                        bool goodCache = false;
                                        struct stat stat_buf;
                                        if ( fstat(fd, &stat_buf) == 0 ) {
                                                goodCache = true;
                                        // validate that the cache file has not been truncated
                                        bool goodCache = false;
                                        struct stat stat_buf;
                                        if ( fstat(fd, &stat_buf) == 0 ) {
                                                goodCache = true;
-                                               for (const shared_file_mapping_np* p = mappings; p < end; ++p) {
+                                               int i=0;
+                                               for (const dyld_cache_mapping_info* p = fileMappingsStart; p < fileMappingsEnd; ++p, ++i) {
+                                                       mappings[i].sfm_address         = p->address;
+                                                       mappings[i].sfm_size            = p->size;
+                                                       mappings[i].sfm_file_offset     = p->fileOffset;
+                                                       mappings[i].sfm_max_prot        = p->maxProt;
+                                                       mappings[i].sfm_init_prot       = p->initProt;
                                                        // rdar://problem/5694507 old update_dyld_shared_cache tool could make a cache file
                                                        // that is not page aligned, but otherwise ok.
                                                        // rdar://problem/5694507 old update_dyld_shared_cache tool could make a cache file
                                                        // that is not page aligned, but otherwise ok.
-                                                       if ( p->sfm_file_offset+p->sfm_size > (uint64_t)(stat_buf.st_size+4095 & (-4096)) ) {
+                                                       if ( p->fileOffset+p->size > (uint64_t)(stat_buf.st_size+4095 & (-4096)) ) {
                                                                dyld::log("dyld: shared cached file is corrupt: %s" DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME "\n", sSharedCacheDir);
                                                                goodCache = false;
                                                        }
                                                }
                                                                dyld::log("dyld: shared cached file is corrupt: %s" DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME "\n", sSharedCacheDir);
                                                                goodCache = false;
                                                        }
                                                }
+#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
+                                               if ( signatureSize == 0 )
+                                                       signatureSize = stat_buf.st_size - header->codeSignatureOffset;
+                                               if ( signatureSize != 0 ) {
+                            int linkeditMapping = mappingCount-1;
+                                                       codeSignatureMappingIndex = mappingCount++;
+                                                       mappings[codeSignatureMappingIndex].sfm_address         = mappings[linkeditMapping].sfm_address + mappings[linkeditMapping].sfm_size;
+                                                       mappings[codeSignatureMappingIndex].sfm_size            = (signatureSize+4095) & (-4096);
+                                                       mappings[codeSignatureMappingIndex].sfm_file_offset     = header->codeSignatureOffset;
+                                                       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;
                                        // 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;
@@ -2302,16 +3003,43 @@ static void mapSharedCache()
                                                        }                                       
                                                }
                                                if ( !sSharedCacheIgnoreInodeAndTimeStamp && !foundLibSystem ) {
                                                        }                                       
                                                }
                                                if ( !sSharedCacheIgnoreInodeAndTimeStamp && !foundLibSystem ) {
-                                                       dyld::log("dyld: shared cached file was build against a different libSystem.dylib, ignoring cache\n");
+                                                       dyld::log("dyld: shared cached file was built against a different libSystem.dylib, ignoring cache.\n"
+                                                                       "to update dyld shared cache run: 'sudo update_dyld_shared_cache' then reboot.\n");
                                                        goodCache = false;
                                                }
                                        }
                                                        goodCache = false;
                                                }
                                        }
-                                                                               
+#endif                                                                         
                                        if ( goodCache ) {
                                        if ( goodCache ) {
-                                               const shared_file_mapping_np* mappings = (shared_file_mapping_np*)&firstPages[header->mappingOffset];
-                                               if (_shared_region_map_np(fd, header->mappingCount, mappings) == 0) {
-                                                       // sucessfully mapped cache into shared region
+                                               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)
+                                                       if ( sMainExecutable->isPositionIndependentExecutable() && (sMainExecutable->getSlide() == 0) )
+                                                               cacheSlide = 0;
+                                                       else {
+                                                               // generate random slide amount
+                                                               cacheSlide = pickCacheSlide(mappingCount, mappings);
+                                                               slideInfo = (void*)(long)(mappings[2].sfm_address + (header->slideInfoOffset - mappings[2].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;
+                                                       }
+                                               }
+                                       #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;
                                                        sSharedCache = (dyld_cache_header*)mappings[0].sfm_address;
+                                                       sSharedCacheSlide = cacheSlide;
+                                                       dyld_all_image_infos.sharedCacheSlide = cacheSlide;
+                                                       //dyld::log("sSharedCache=%p sSharedCacheSlide=0x%08lX\n", sSharedCache, sSharedCacheSlide);
+                                               }
+                                               else {
+                                                       if ( gLinkContext.verboseMapping ) 
+                                                               dyld::log("dyld: shared cached file could not be mapped\n");
                                                }
                                        }
                                }
                                                }
                                        }
                                }
@@ -2339,44 +3067,66 @@ static void mapSharedCache()
        
        // tell gdb where the shared cache is
        if ( sSharedCache != NULL ) {
        
        // tell gdb where the shared cache is
        if ( sSharedCache != NULL ) {
-               const shared_file_mapping_np* const start = (shared_file_mapping_np*)((uint8_t*)sSharedCache + sSharedCache->mappingOffset);
+               const dyld_cache_mapping_info* const start = (dyld_cache_mapping_info*)((uint8_t*)sSharedCache + sSharedCache->mappingOffset);
                dyld_shared_cache_ranges.sharedRegionsCount = sSharedCache->mappingCount;
                // only room to tell gdb about first four regions
                if ( dyld_shared_cache_ranges.sharedRegionsCount > 4 )
                        dyld_shared_cache_ranges.sharedRegionsCount = 4;
                if ( gLinkContext.verboseMapping ) {
                        if ( gLinkContext.sharedRegionMode == ImageLoader::kUseSharedRegion )
                dyld_shared_cache_ranges.sharedRegionsCount = sSharedCache->mappingCount;
                // only room to tell gdb about first four regions
                if ( dyld_shared_cache_ranges.sharedRegionsCount > 4 )
                        dyld_shared_cache_ranges.sharedRegionsCount = 4;
                if ( gLinkContext.verboseMapping ) {
                        if ( gLinkContext.sharedRegionMode == ImageLoader::kUseSharedRegion )
-                               dyld::log("dyld: Mapping shared cache from %s" DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME "\n", sSharedCacheDir);
+                               dyld::log("dyld: Mapping shared cache from %s/" DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME "\n", sSharedCacheDir);
                        else if ( gLinkContext.sharedRegionMode == ImageLoader::kUsePrivateSharedRegion )
                        else if ( gLinkContext.sharedRegionMode == ImageLoader::kUsePrivateSharedRegion )
-                               dyld::log("dyld: Mapping private shared cache from %s" DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME "\n", sSharedCacheDir);
+                               dyld::log("dyld: Mapping private shared cache from %s/" DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME "\n", sSharedCacheDir);
                }
                }
-               const shared_file_mapping_np* const end = &start[dyld_shared_cache_ranges.sharedRegionsCount];
+               const dyld_cache_mapping_info* const end = &start[dyld_shared_cache_ranges.sharedRegionsCount];
                int index = 0;
                int index = 0;
-               for (const shared_file_mapping_np* p = start; p < end; ++p, ++index ) {
-                       dyld_shared_cache_ranges.ranges[index].start = p->sfm_address;
-                       dyld_shared_cache_ranges.ranges[index].length = p->sfm_size;
+               for (const dyld_cache_mapping_info* p = start; p < end; ++p, ++index ) {
+                       dyld_shared_cache_ranges.ranges[index].start = p->address+sSharedCacheSlide;
+                       dyld_shared_cache_ranges.ranges[index].length = p->size;
                        if ( gLinkContext.verboseMapping ) {
                        if ( gLinkContext.verboseMapping ) {
-                               dyld::log("        0x%08llX->0x%08llX %s%s%s init=%x, max=%x\n", p->sfm_address, p->sfm_address+p->sfm_size-1,
-                                       ((p->sfm_init_prot & VM_PROT_READ) ? "read " : ""),
-                                       ((p->sfm_init_prot & VM_PROT_WRITE) ? "write " : ""),
-                                       ((p->sfm_init_prot & VM_PROT_EXECUTE) ? "execute " : ""),  p->sfm_init_prot, p->sfm_max_prot);
+                               dyld::log("        0x%08llX->0x%08llX %s%s%s init=%x, max=%x\n", 
+                                       p->address+sSharedCacheSlide, p->address+sSharedCacheSlide+p->size-1,
+                                       ((p->initProt & VM_PROT_READ) ? "read " : ""),
+                                       ((p->initProt & VM_PROT_WRITE) ? "write " : ""),
+                                       ((p->initProt & VM_PROT_EXECUTE) ? "execute " : ""),  p->initProt, p->maxProt);
                        }
                #if __i386__
                        // If a non-writable and executable region is found in the R/W shared region, then this is __IMPORT segments
                        // This is an old cache.  Make writable.  dyld no longer supports turn W on and off as it binds
                        }
                #if __i386__
                        // If a non-writable and executable region is found in the R/W shared region, then this is __IMPORT segments
                        // This is an old cache.  Make writable.  dyld no longer supports turn W on and off as it binds
-                       if ( (p->sfm_init_prot == (VM_PROT_READ|VM_PROT_EXECUTE)) && ((p->sfm_address & 0xF0000000) == 0xA0000000) ) {
-                               if ( p->sfm_size != 0 ) {
+                       if ( (p->initProt == (VM_PROT_READ|VM_PROT_EXECUTE)) && ((p->address & 0xF0000000) == 0xA0000000) ) {
+                               if ( p->size != 0 ) {
                                        vm_prot_t prot = VM_PROT_EXECUTE | PROT_READ | VM_PROT_WRITE;
                                        vm_prot_t prot = VM_PROT_EXECUTE | PROT_READ | VM_PROT_WRITE;
-                                       vm_protect(mach_task_self(), p->sfm_address, p->sfm_size, false, prot);
+                                       vm_protect(mach_task_self(), p->address, p->size, false, prot);
                                        if ( gLinkContext.verboseMapping ) {
                                        if ( gLinkContext.verboseMapping ) {
-                                               dyld::log("%18s at 0x%08llX->0x%08llX altered permissions to %c%c%c\n", "", p->sfm_address, 
-                                                       p->sfm_address+p->sfm_size-1,
+                                               dyld::log("%18s at 0x%08llX->0x%08llX altered permissions to %c%c%c\n", "", p->address, 
+                                                       p->address+p->size-1,
                                                        (prot & PROT_READ) ? 'r' : '.',  (prot & PROT_WRITE) ? 'w' : '.',  (prot & PROT_EXEC) ? 'x' : '.' );
                                        }
                                }
                        }
                #endif
                }
                                                        (prot & PROT_READ) ? 'r' : '.',  (prot & PROT_WRITE) ? 'w' : '.',  (prot & PROT_EXEC) ? 'x' : '.' );
                                        }
                                }
                        }
                #endif
                }
+#if __IPHONE_OS_VERSION_MIN_REQUIRED   
+               if ( gLinkContext.verboseMapping ) {
+                       // list the code blob
+                       dyld_cache_header* header = (dyld_cache_header*)sSharedCache;
+                       uint32_t signatureSize = header->codeSignatureSize;
+                       // 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 ) 
+                                       signatureSize = stat_buf.st_size - header->codeSignatureOffset;
+                       }
+                       if ( signatureSize != 0 ) {
+                               const dyld_cache_mapping_info* const last = &start[dyld_shared_cache_ranges.sharedRegionsCount-1];
+                               uint64_t codeBlobStart = last->address + last->size;
+                               dyld::log("        0x%08llX->0x%08llX (code signature)\n", codeBlobStart, codeBlobStart+signatureSize);
+                       }
+               }
+               // 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 );
+#endif         
 
        }
 }
 
        }
 }
@@ -2404,8 +3154,8 @@ ImageLoader* cloneImage(ImageLoader* image)
        context.mustBeBundle            = true;
        context.mustBeDylib                     = false;
        context.canBePIE                        = false;
        context.mustBeBundle            = true;
        context.mustBeDylib                     = false;
        context.canBePIE                        = false;
-       context.origin                          = false;
-       context.rpath                           = false;
+       context.origin                          = NULL;
+       context.rpath                           = NULL;
        return loadPhase6(file.getFileDescriptor(), stat_buf, image->getPath(), context);
 }
 
        return loadPhase6(file.getFileDescriptor(), stat_buf, image->getPath(), context);
 }
 
@@ -2491,12 +3241,21 @@ void halt(const char* message)
        dyld::log("dyld: %s\n", message);
        setErrorMessage(message);
        uintptr_t terminationFlags = 0;
        dyld::log("dyld: %s\n", message);
        setErrorMessage(message);
        uintptr_t terminationFlags = 0;
-       if ( !gLinkContext.startedInitializingMainExecutable )
+       if ( !gLinkContext.startedInitializingMainExecutable ) 
                terminationFlags = 1;
        setAlImageInfosHalt(error_string, terminationFlags);
        dyld_fatal_error(error_string);
 }
 
                terminationFlags = 1;
        setAlImageInfosHalt(error_string, terminationFlags);
        dyld_fatal_error(error_string);
 }
 
+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;
+}
+
 
 uintptr_t bindLazySymbol(const mach_header* mh, uintptr_t* lazyPointer)
 {
 
 uintptr_t bindLazySymbol(const mach_header* mh, uintptr_t* lazyPointer)
 {
@@ -2537,7 +3296,6 @@ uintptr_t bindLazySymbol(const mach_header* mh, uintptr_t* lazyPointer)
 }
 
 
 }
 
 
-#if COMPRESSED_DYLD_INFO_SUPPORT
 uintptr_t fastBindLazySymbol(ImageLoader** imageLoaderCache, uintptr_t lazyBindingInfoOffset)
 {
        uintptr_t result = 0;
 uintptr_t fastBindLazySymbol(ImageLoader** imageLoaderCache, uintptr_t lazyBindingInfoOffset)
 {
        uintptr_t result = 0;
@@ -2554,7 +3312,9 @@ uintptr_t fastBindLazySymbol(ImageLoader** imageLoaderCache, uintptr_t lazyBindi
        
        // bind lazy pointer and return it
        try {
        
        // bind lazy pointer and return it
        try {
-               result = (*imageLoaderCache)->doBindFastLazySymbol(lazyBindingInfoOffset, gLinkContext);
+               result = (*imageLoaderCache)->doBindFastLazySymbol(lazyBindingInfoOffset, gLinkContext, 
+                                                               (dyld::gLibSystemHelpers != NULL) ? dyld::gLibSystemHelpers->acquireGlobalDyldLock : NULL,
+                                                               (dyld::gLibSystemHelpers != NULL) ? dyld::gLibSystemHelpers->releaseGlobalDyldLock : NULL);
        }
        catch (const char* message) {
                dyld::log("dyld: lazy symbol binding failed: %s\n", message);
        }
        catch (const char* message) {
                dyld::log("dyld: lazy symbol binding failed: %s\n", message);
@@ -2564,7 +3324,6 @@ uintptr_t fastBindLazySymbol(ImageLoader** imageLoaderCache, uintptr_t lazyBindi
        // return target address to glue which jumps to it with real parameters restored
        return result;
 }
        // return target address to glue which jumps to it with real parameters restored
        return result;
 }
-#endif // COMPRESSED_DYLD_INFO_SUPPORT
 
 
 
 
 
 
@@ -2771,6 +3530,7 @@ static void setContext(const macho_header* mainExecutableMH, int argc, const cha
 #if DYLD_SHARED_CACHE_SUPPORT
        gLinkContext.inSharedCache                      = &inSharedCache;
 #endif
 #if DYLD_SHARED_CACHE_SUPPORT
        gLinkContext.inSharedCache                      = &inSharedCache;
 #endif
+       gLinkContext.setErrorStrings            = &setErrorStrings;
 #if SUPPORT_OLD_CRT_INITIALIZATION
        gLinkContext.setRunInitialzersOldWay= &setRunInitialzersOldWay;
 #endif
 #if SUPPORT_OLD_CRT_INITIALIZATION
        gLinkContext.setRunInitialzersOldWay= &setRunInitialzersOldWay;
 #endif
@@ -2851,8 +3611,70 @@ static bool hasRestrictedSegment(const macho_header* mh)
                
        return false;
 }
                
        return false;
 }
+
+
+//
+// Peeks at a dylib file and returns its current_version and install_name.
+// Returns false on error.
+//                     
+static bool getDylibVersionAndInstallname(const char* dylibPath, uint32_t* version, char* installName)
+{
+       // open file (automagically closed when this function exits)
+       FileOpener file(dylibPath);
        
        
-                                                                                       
+       if ( file.getFileDescriptor() == -1 ) 
+               return false;
+       
+       uint8_t firstPage[4096];
+       if ( pread(file.getFileDescriptor(), firstPage, 4096, 0) != 4096 )
+               return false;
+
+       // if fat wrapper, find usable sub-file
+       const fat_header* fileStartAsFat = (fat_header*)firstPage;
+       if ( fileStartAsFat->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
+               uint64_t fileOffset;
+               uint64_t fileLength;
+               if ( fatFindBest(fileStartAsFat, &fileOffset, &fileLength) ) {
+                       if ( pread(file.getFileDescriptor(), firstPage, 4096, fileOffset) != 4096 )
+                               return false;
+               }
+               else {
+                       return false;
+               }
+       }
+
+       // check mach-o header
+       const mach_header* mh = (mach_header*)firstPage;
+       if ( mh->magic != sMainExecutableMachHeader->magic ) 
+               return false;
+       if ( mh->cputype != sMainExecutableMachHeader->cputype )
+               return false;
+
+       // scan load commands for LC_ID_DYLIB
+       const uint32_t cmd_count = mh->ncmds;
+       const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header));
+       const struct load_command* const cmdsReadEnd = (struct load_command*)(((char*)mh)+4096);
+       const struct load_command* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               switch (cmd->cmd) {
+                       case LC_ID_DYLIB:
+                       {
+                               const struct dylib_command* id = (struct dylib_command*)cmd;
+                               *version = id->dylib.current_version;
+                               if ( installName != NULL )
+                                       strlcpy(installName, (char *)id + id->dylib.name.offset, PATH_MAX);
+                               return true;
+                       }
+                       break;
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+               if ( cmd > cmdsReadEnd )
+                       return false;
+       }
+       
+       return false;
+}
+                                                               
 #if 0
 static void printAllImages()
 {
 #if 0
 static void printAllImages()
 {
@@ -2866,7 +3688,6 @@ static void printAllImages()
 }
 #endif
 
 }
 #endif
 
-
 void link(ImageLoader* image, bool forceLazysBound, const ImageLoader::RPathChain& loaderRPaths)
 {
        // add to list of known images.  This did not happen at creation time for bundles
 void link(ImageLoader* image, bool forceLazysBound, const ImageLoader::RPathChain& loaderRPaths)
 {
        // add to list of known images.  This did not happen at creation time for bundles
@@ -2891,7 +3712,9 @@ void link(ImageLoader* image, bool forceLazysBound, const ImageLoader::RPathChai
 void runInitializers(ImageLoader* image)
 {
        // do bottom up initialization
 void runInitializers(ImageLoader* image)
 {
        // do bottom up initialization
-       image->runInitializers(gLinkContext);
+       ImageLoader::InitializerTimingList initializerTimes[sAllImages.size()];
+       initializerTimes[0].count = 0;
+       image->runInitializers(gLinkContext, initializerTimes[0]);
 }
 
 void garbageCollectImages()
 }
 
 void garbageCollectImages()
@@ -2970,6 +3793,33 @@ static void loadInsertedDylib(const char* path)
        }
 }
 
        }
 }
 
+static bool processRestricted(const macho_header* mainExecutableMH)
+{
+    // all processes with setuid or setgid bit set are restricted
+    if ( issetugid() )
+        return true;
+        
+       if ( hasRestrictedSegment(mainExecutableMH) && (geteuid() != 0) ) {
+               // existence of __RESTRICT/__restrict section make process restricted
+               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)
+            return true;
+    }
+#endif
+    return false;
+}
+
+
 //
 // Entry point for dyld.  The kernel loads dyld and jumps to __dyld_start which
 // sets up some registers and call this function.
 //
 // Entry point for dyld.  The kernel loads dyld and jumps to __dyld_start which
 // sets up some registers and call this function.
@@ -2979,6 +3829,7 @@ static void loadInsertedDylib(const char* path)
 uintptr_t
 _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int argc, const char* argv[], const char* envp[], const char* apple[])
 {      
 uintptr_t
 _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int argc, const char* argv[], const char* envp[], const char* apple[])
 {      
+       CRSetCrashLogMessage("dyld: launch started");
 #ifdef ALTERNATIVE_LOGFILE
        sLogfile = open(ALTERNATIVE_LOGFILE, O_WRONLY | O_CREAT | O_APPEND);
        if ( sLogfile == -1 ) {
 #ifdef ALTERNATIVE_LOGFILE
        sLogfile = open(ALTERNATIVE_LOGFILE, O_WRONLY | O_CREAT | O_APPEND);
        if ( sLogfile == -1 ) {
@@ -2986,7 +3837,26 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int a
                dyld::log("error opening alternate log file %s, errno = %d\n", ALTERNATIVE_LOGFILE, errno);
        }
 #endif
                dyld::log("error opening alternate log file %s, errno = %d\n", ALTERNATIVE_LOGFILE, errno);
        }
 #endif
+
+#if LOG_BINDINGS
+       char bindingsLogPath[256];
        
        
+       const char* shortProgName = "unknown";
+       if ( argc > 0 ) {
+               shortProgName = strrchr(argv[0], '/');
+               if ( shortProgName == NULL )
+                       shortProgName = argv[0];
+               else 
+                       ++shortProgName;
+       }
+       mysprintf(bindingsLogPath, "/tmp/bindings/%d-%s", getpid(), shortProgName);
+       sBindingsLogfile = open(bindingsLogPath, O_WRONLY | O_CREAT, 0666);
+       if ( sBindingsLogfile == -1 ) {
+               ::mkdir("/tmp/bindings", 0777);
+               sBindingsLogfile = open(bindingsLogPath, O_WRONLY | O_CREAT, 0666);
+       }
+       //dyld::log("open(%s) => %d, errno = %d\n", bindingsLogPath, sBindingsLogfile, errno);
+#endif 
        setContext(mainExecutableMH, argc, argv, envp, apple);
 
        // Pickup the pointer to the exec path.
        setContext(mainExecutableMH, argc, argv, envp, apple);
 
        // Pickup the pointer to the exec path.
@@ -3016,13 +3886,18 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int a
        }
        uintptr_t result = 0;
        sMainExecutableMachHeader = mainExecutableMH;
        }
        uintptr_t result = 0;
        sMainExecutableMachHeader = mainExecutableMH;
-       sProcessIsRestricted = issetugid();
-       if ( geteuid() != 0 ) {
-               // if we are not root, see if the binary is requesting restricting the use of DYLD_ env vars.
-               sProcessIsRestricted |= hasRestrictedSegment(mainExecutableMH);
-       }
-       if ( sProcessIsRestricted )
+    sProcessIsRestricted = processRestricted(mainExecutableMH);
+    if ( sProcessIsRestricted ) {
+#if SUPPORT_LC_DYLD_ENVIRONMENT
+               checkLoadCommandEnvironmentVariables();
+#if SUPPORT_VERSIONED_PATHS
+               checkVersionedPaths();
+#endif 
+#endif         
                pruneEnvironmentVariables(envp, &apple);
                pruneEnvironmentVariables(envp, &apple);
+               // set again because envp and apple may have changed or moved
+               setContext(mainExecutableMH, argc, argv, envp, apple);
+       }
        else
                checkEnvironmentVariables(envp, ignoreEnvironmentVariables);
        if ( sEnv.DYLD_PRINT_OPTS ) 
        else
                checkEnvironmentVariables(envp, ignoreEnvironmentVariables);
        if ( sEnv.DYLD_PRINT_OPTS ) 
@@ -3032,6 +3907,7 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int a
        getHostInfo();
        // install gdb notifier
        stateToHandlers(dyld_image_state_dependents_mapped, sBatchHandlers)->push_back(notifyGDB);
        getHostInfo();
        // install gdb notifier
        stateToHandlers(dyld_image_state_dependents_mapped, sBatchHandlers)->push_back(notifyGDB);
+       stateToHandlers(dyld_image_state_mapped, sSingleHandlers)->push_back(updateAllImages);
        // make initial allocations large enough that it is unlikely to need to be re-alloced
        sAllImages.reserve(INITIAL_IMAGE_COUNT);
        sImageRoots.reserve(16);
        // make initial allocations large enough that it is unlikely to need to be re-alloced
        sAllImages.reserve(INITIAL_IMAGE_COUNT);
        sImageRoots.reserve(16);
@@ -3046,6 +3922,7 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int a
 #endif
        
        try {
 #endif
        
        try {
+               CRSetCrashLogMessage("dyld: launch, loading dependent libraries");
                // instantiate ImageLoader for main executable
                sMainExecutable = instantiateFromLoadedImage(mainExecutableMH, mainExecutableSlide, sExecPath);
                sMainExecutable->setNeverUnload();
                // instantiate ImageLoader for main executable
                sMainExecutable = instantiateFromLoadedImage(mainExecutableMH, mainExecutableSlide, sExecPath);
                sMainExecutable->setNeverUnload();
@@ -3083,9 +3960,12 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int a
                        for(unsigned int i=0; i < sInsertedDylibCount; ++i) {
                                ImageLoader* image = sAllImages[i+1];
                                link(image, sEnv.DYLD_BIND_AT_LAUNCH, ImageLoader::RPathChain(NULL, NULL));
                        for(unsigned int i=0; i < sInsertedDylibCount; ++i) {
                                ImageLoader* image = sAllImages[i+1];
                                link(image, sEnv.DYLD_BIND_AT_LAUNCH, ImageLoader::RPathChain(NULL, NULL));
+                               // only INSERTED libraries can interpose
+                               image->registerInterposing();
                        }
                }
                
                        }
                }
                
+               CRSetCrashLogMessage("dyld: launch, running initializers");
        #if SUPPORT_OLD_CRT_INITIALIZATION
                // Old way is to run initializers via a callback from crt1.o
                if ( ! gRunInitializersOldWay ) 
        #if SUPPORT_OLD_CRT_INITIALIZATION
                // Old way is to run initializers via a callback from crt1.o
                if ( ! gRunInitializersOldWay ) 
@@ -3093,6 +3973,7 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int a
                initializeMainExecutable(); // run all initializers
        }
        catch(const char* message) {
                initializeMainExecutable(); // run all initializers
        }
        catch(const char* message) {
+               syncAllImages();
                halt(message);
        }
        catch(...) {
                halt(message);
        }
        catch(...) {
@@ -3106,6 +3987,7 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int a
                sLogfile = STDERR_FILENO;
        }
 #endif
                sLogfile = STDERR_FILENO;
        }
 #endif
+       CRSetCrashLogMessage(NULL);
        
        return result;
 }
        
        return result;
 }
index 2deab7dbaf58df8faa474fce90f278ea22841264..9ad1ef8b7ea139da70dff3a0ca3cfc497e507a17 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2004-2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2004-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -59,6 +59,7 @@ namespace dyld {
 
        extern ImageLoader::LinkContext                 gLinkContext;
        extern bool                                                             gLogAPIs;
 
        extern ImageLoader::LinkContext                 gLinkContext;
        extern bool                                                             gLogAPIs;
+       extern bool                                                             gSharedCacheOverridden;
        extern const struct LibSystemHelpers*   gLibSystemHelpers;
 #if SUPPORT_OLD_CRT_INITIALIZATION
        extern bool                                                             gRunInitializersOldWay;
        extern const struct LibSystemHelpers*   gLibSystemHelpers;
 #if SUPPORT_OLD_CRT_INITIALIZATION
        extern bool                                                             gRunInitializersOldWay;
@@ -94,7 +95,7 @@ namespace dyld {
        extern void                                     clearErrorMessage();
        extern bool                                     mainExecutablePrebound();
        extern ImageLoader*                     mainExecutable();
        extern void                                     clearErrorMessage();
        extern bool                                     mainExecutablePrebound();
        extern ImageLoader*                     mainExecutable();
-       extern void                                     processDyldEnvironmentVarible(const char* key, const char* value);
+       extern void                                     processDyldEnvironmentVariable(const char* key, const char* value, const char* mainDir);
        extern void                                     registerImageStateSingleChangeHandler(dyld_image_states state, dyld_image_state_change_handler handler);
        extern void                                     registerImageStateBatchChangeHandler(dyld_image_states state, dyld_image_state_change_handler handler);
        extern void                                     garbageCollectImages();
        extern void                                     registerImageStateSingleChangeHandler(dyld_image_states state, dyld_image_state_change_handler handler);
        extern void                                     registerImageStateBatchChangeHandler(dyld_image_states state, dyld_image_state_change_handler handler);
        extern void                                     garbageCollectImages();
@@ -102,6 +103,8 @@ namespace dyld {
        extern const void*                      imMemorySharedCacheHeader();
        extern uintptr_t                        fastBindLazySymbol(ImageLoader** imageLoaderCache, uintptr_t lazyBindingInfoOffset);
        extern bool                                     inSharedCache(const char* path);
        extern const void*                      imMemorySharedCacheHeader();
        extern uintptr_t                        fastBindLazySymbol(ImageLoader** imageLoaderCache, uintptr_t lazyBindingInfoOffset);
        extern bool                                     inSharedCache(const char* path);
-
+#if LOG_BINDINGS
+       extern void                                     logBindings(const char* format, ...);
+#endif
 };
 
 };
 
diff --git a/src/dyld.order b/src/dyld.order
new file mode 100644 (file)
index 0000000..ba83697
--- /dev/null
@@ -0,0 +1,98 @@
+#
+#  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@
+#
+
+#
+#  Cluster these __DATA symbols in dyld to reduce pages dirtied
+#
+_sDyldInfo.0
+_sDyldInfo.1
+_sDyldInfo.2
+_sDyldInfo.3
+_sDyldInfo.4
+_sDyldTextEnd
+_mach_init_inited.7154.b
+__task_reply_port
+_mach_task_self_
+_mach_host_self_
+_vm_page_size
+_vm_page_mask
+_vm_page_shift
+___stack_chk_guard
+__ZN4dyldL23sFrameworkFallbackPathsE
+__ZN4dyldL21sLibraryFallbackPathsE
+__ZL11initialPool
+__ZN4dyld12gLinkContextE
+__ZN4dyld17gLibSystemHelpersE
+__ZN4dyldL17sSharedCacheSlideE
+_dyld_shared_cache_ranges
+__ZN11ImageLoader27fgImagesUsedFromSharedCacheE
+__ZN11ImageLoader19fgInterposingTuplesE
+__ZN11ImageLoader24fgTotalLoadLibrariesTimeE
+__ZN11ImageLoader24fgTotalLoadLibrariesTimeE
+__ZN11ImageLoader17fgTotalRebaseTimeE
+__ZN11ImageLoader15fgTotalBindTimeE
+__ZN11ImageLoader19fgTotalWeakBindTimeE
+__ZN11ImageLoader10fgTotalDOFE
+__ZN11ImageLoader15fgTotalInitTimeE
+__ZN11ImageLoader22fgTotalBytesPreFetchedE
+__ZN11ImageLoader18fgTotalBytesMappedE
+__ZN11ImageLoader21fgTotalSegmentsMappedE
+__ZN11ImageLoader19fgTotalRebaseFixupsE
+__ZN11ImageLoader17fgTotalBindFixupsE
+__ZN11ImageLoader26fgTotalBindSymbolsResolvedE
+__ZN11ImageLoader24fgTotalBindImageSearchesE
+__ZN11ImageLoader29fgTotalPossibleLazyBindFixupsE
+__ZN11ImageLoader21fgTotalLazyBindFixupsE
+__ZN11ImageLoader27fgImagesRequiringCoalescingE
+__ZN11ImageLoader21fgNextPIEDylibAddressE
+__ZN11ImageLoader26fgImagesWithUsedPrebindingE
+__ZN11ImageLoader26fgImagesHasWeakDefinitionsE
+__ZN16ImageLoaderMachO26fgSymbolTableBinarySearchsE
+__ZN16ImageLoaderMachO19fgSymbolTrieSearchsE
+__ZN11ImageLoader13fgLoadOrdinalE
+__ZN4dyldL9sExecPathE
+__ZN4dyldL25sMainExecutableMachHeaderE
+__ZN4dyldL12sSharedCacheE
+__ZN4dyldL17sUndefinedHandlerE
+__ZN4dyldL10sAllImagesE
+__ZN4dyldL18sAddImageCallbacksE
+__ZN4dyldL11sImageRootsE
+__ZN4dyldL29sImageFilesNeedingTerminationE
+__ZN4dyldL35sImageFilesNeedingDOFUnregistrationE
+__ZN4dyldL35sImageFilesNeedingDOFUnregistrationE
+__ZN4dyldL21sRemoveImageCallbacksE
+__ZN4dyldL15sSingleHandlersE
+__ZN4dyldL14sBatchHandlersE
+__ZN4dyldL15sMainExecutableE
+__ZN4dyldL4sEnvE
+__ZL11sImageInfos
+__ZL11sImageUUIDs
+__ZN4dyldL19sInsertedDylibCountE
+__ZN4dyldL20sProcessIsRestrictedE
+__ZL17sObjectFileImages
+__ZN11ImageLoader23fgDynamicImageReExportsE
+__ZN4dyldL15sDylibOverridesE
+__ZN4dyldL19sInsertedDylibCountE
+__ZN4dyldL20sProcessIsRestrictedE
+__ZN4dyldL18sMappedRangesStartE
+__thread
index 609f0b32b0b53636ed9285d1414440f8c1c12f0b..0d0dbc73219f89599803fd302cf72cd1cf03f989 100644 (file)
 #undef _POSIX_C_SOURCE
 #include "dlfcn.h"
 
 #undef _POSIX_C_SOURCE
 #include "dlfcn.h"
 
+// from dyldExceptions.c
+extern "C" void __Unwind_SjLj_SetThreadKey(pthread_key_t key);
+
+// from dyld_gdb.cpp 
+extern void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[]);
 
 // deprecated APIs are still availble on Mac OS X, but not on iPhone OS
 #if __IPHONE_OS_VERSION_MIN_REQUIRED   
 
 // deprecated APIs are still availble on Mac OS X, but not on iPhone OS
 #if __IPHONE_OS_VERSION_MIN_REQUIRED   
@@ -80,7 +85,6 @@ static int sLastErrorNo;
 
 // The following functions have no prototype in any header.  They are special cases
 // where _dyld_func_lookup() is used directly.
 
 // The following functions have no prototype in any header.  They are special cases
 // where _dyld_func_lookup() is used directly.
-static void _dyld_fork_child();
 static void _dyld_make_delayed_module_initializer_calls();
 static void registerThreadHelpers(const dyld::LibSystemHelpers*);
 #if DEPRECATED_APIS_SUPPORTED
 static void _dyld_make_delayed_module_initializer_calls();
 static void registerThreadHelpers(const dyld::LibSystemHelpers*);
 #if DEPRECATED_APIS_SUPPORTED
@@ -97,7 +101,9 @@ static void _dyld_call_module_initializers_for_dylib(const struct mach_header* m
 static void            client_dyld_lookup_and_bind(const char* symbolName, void** address, NSModule* module);
 static bool            client_NSIsSymbolNameDefined(const char* symbolName);
 #endif // DEPRECATED_APIS_SUPPORTED
 static void            client_dyld_lookup_and_bind(const char* symbolName, void** address, NSModule* module);
 static bool            client_NSIsSymbolNameDefined(const char* symbolName);
 #endif // DEPRECATED_APIS_SUPPORTED
+#if !__arm__
 static bool client_dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info);
 static bool client_dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info);
+#endif
 
 static void unimplemented()
 {
 
 static void unimplemented()
 {
@@ -118,7 +124,6 @@ static struct dyld_func dyld_funcs[] = {
     {"__dyld_dlopen",                                                                  (void*)dlopen },
     {"__dyld_dlsym",                                                                   (void*)dlsym },
     {"__dyld_dlopen_preflight",                                                        (void*)dlopen_preflight },
     {"__dyld_dlopen",                                                                  (void*)dlopen },
     {"__dyld_dlsym",                                                                   (void*)dlsym },
     {"__dyld_dlopen_preflight",                                                        (void*)dlopen_preflight },
-    {"__dyld_get_image_header_containing_address",             (void*)_dyld_get_image_header_containing_address },
        {"__dyld_image_count",                                                          (void*)_dyld_image_count },
     {"__dyld_get_image_header",                                                        (void*)_dyld_get_image_header },
     {"__dyld_get_image_vmaddr_slide",                                  (void*)_dyld_get_image_vmaddr_slide },
        {"__dyld_image_count",                                                          (void*)_dyld_image_count },
     {"__dyld_get_image_header",                                                        (void*)_dyld_get_image_header },
     {"__dyld_get_image_vmaddr_slide",                                  (void*)_dyld_get_image_vmaddr_slide },
@@ -136,13 +141,17 @@ static struct dyld_func dyld_funcs[] = {
 #if !__arm__
        {"__dyld_find_unwind_sections",                                         (void*)client_dyld_find_unwind_sections },
 #endif
 #if !__arm__
        {"__dyld_find_unwind_sections",                                         (void*)client_dyld_find_unwind_sections },
 #endif
-#if __i386__ || __x86_64__
+#if __i386__ || __x86_64__ || __arm__
        {"__dyld_fast_stub_entry",                                                      (void*)dyld::fastBindLazySymbol },
 #endif
        {"__dyld_image_path_containing_address",                        (void*)dyld_image_path_containing_address },
        {"__dyld_fast_stub_entry",                                                      (void*)dyld::fastBindLazySymbol },
 #endif
        {"__dyld_image_path_containing_address",                        (void*)dyld_image_path_containing_address },
+#if __IPHONE_OS_VERSION_MIN_REQUIRED   
+       {"__dyld_shared_cache_some_image_overridden",           (void*)dyld_shared_cache_some_image_overridden },
+#endif
 
        // deprecated
 #if DEPRECATED_APIS_SUPPORTED
 
        // deprecated
 #if DEPRECATED_APIS_SUPPORTED
+    {"__dyld_get_image_header_containing_address",             (void*)_dyld_get_image_header_containing_address },
     {"__dyld_lookup_and_bind",                                         (void*)client_dyld_lookup_and_bind },
     {"__dyld_lookup_and_bind_with_hint",                       (void*)_dyld_lookup_and_bind_with_hint },
     {"__dyld_lookup_and_bind_fully",                           (void*)_dyld_lookup_and_bind_fully },
     {"__dyld_lookup_and_bind",                                         (void*)client_dyld_lookup_and_bind },
     {"__dyld_lookup_and_bind_with_hint",                       (void*)_dyld_lookup_and_bind_with_hint },
     {"__dyld_lookup_and_bind_fully",                           (void*)_dyld_lookup_and_bind_fully },
@@ -970,10 +979,17 @@ NSModule NSLinkModule(NSObjectFileImage objectFileImage, const char* moduleName,
                        // already linked, so clone a new one and link it
                        objectFileImage->image = dyld::cloneImage(objectFileImage->image);
                }
                        // already linked, so clone a new one and link it
                        objectFileImage->image = dyld::cloneImage(objectFileImage->image);
                }
-                       
+               
                // for memory based images, set moduleName as the name anyone calling _dyld_get_image_name() will see
                // for memory based images, set moduleName as the name anyone calling _dyld_get_image_name() will see
-               if ( objectFileImage->image->getPath() == NULL )
+               if ( objectFileImage->image->getPath() == NULL ) {
                        objectFileImage->image->setPath(moduleName);
                        objectFileImage->image->setPath(moduleName);
+                       // <rdar://problem/8812589> dyld has NULL paths in image info array
+                       dyld_image_info info;
+                       info.imageLoadAddress = objectFileImage->image->machHeader();
+                       info.imageFilePath = moduleName;
+                       info.imageFileModDate = 0;
+                       addImagesToAllImages(1, &info);
+               }
 
                // support private bundles
                if ( (options & NSLINKMODULE_OPTION_PRIVATE) != 0 )
 
                // support private bundles
                if ( (options & NSLINKMODULE_OPTION_PRIVATE) != 0 )
@@ -1150,7 +1166,7 @@ static void _dyld_register_binding_handler(void * (*bindingHandler)(const char *
 
 
 // Call by fork() in libSystem after the kernel trap is done on the child side
 
 
 // Call by fork() in libSystem after the kernel trap is done on the child side
-static void _dyld_fork_child()
+void _dyld_fork_child()
 {
        if ( dyld::gLogAPIs )
                dyld::log("%s()\n", __func__);
 {
        if ( dyld::gLogAPIs )
                dyld::log("%s()\n", __func__);
@@ -1243,12 +1259,23 @@ bool lookupDyldFunction(const char* name, uintptr_t* address)
        return false;
 }
 
        return false;
 }
 
+
 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;       
 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;       
+       
+#if __arm__
+       if ( helpers->version >= 5 )  {
+               // create key use by dyld exception handling
+               pthread_key_t key;
+               int result = helpers->pthread_key_create(&key, NULL);
+               if ( result == 0 )
+                       __Unwind_SjLj_SetThreadKey(key);
+       }
+#endif
 }
 
 
 }
 
 
@@ -1287,6 +1314,8 @@ bool dlopen_preflight(const char* path)
                return true;
 #endif
        
                return true;
 #endif
        
+       CRSetCrashLogMessage("dyld: in dlopen_preflight()");
+       
        bool result = false;
        std::vector<const char*> rpathsFromCallerImage;
        try {
        bool result = false;
        std::vector<const char*> rpathsFromCallerImage;
        try {
@@ -1303,6 +1332,27 @@ bool dlopen_preflight(const char* path)
                ImageLoader*    image = NULL;
                const bool leafName = (strchr(path, '/') == NULL);
                const bool absolutePath = (path[0] == '/');
                ImageLoader*    image = NULL;
                const bool leafName = (strchr(path, '/') == NULL);
                const bool absolutePath = (path[0] == '/');
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
+               char canonicalPath[PATH_MAX]; 
+               // <rdar://problem/7017050> dlopen() not opening frameworks from shared cache with // or ./ in path
+               if ( !leafName ) {
+                       // make path canonical if it contains a // or ./
+                       if ( (strstr(path, "//") != NULL) || (strstr(path, "./") != NULL) ) {
+                               const char* lastSlash = strrchr(path, '/');
+                               char dirPath[PATH_MAX]; 
+                               if ( strlcpy(dirPath, path, sizeof(dirPath)) < sizeof(dirPath) ) {
+                                       dirPath[lastSlash-path] = '\0';
+                                       if ( realpath(dirPath, canonicalPath) ) {
+                                               strlcat(canonicalPath, "/", sizeof(canonicalPath));
+                                               if ( strlcat(canonicalPath, lastSlash+1, sizeof(canonicalPath)) < sizeof(canonicalPath) ) {
+                                                       // if all fit in buffer, use new canonical path
+                                                       path = canonicalPath;
+                                               }
+                                       }
+                               }
+                       }
+               }
+#endif
                dyld::LoadContext context;
                context.useSearchPaths  = true;
                context.useFallbackPaths= leafName;                                     // a partial path implies don't use fallback paths
                dyld::LoadContext context;
                context.useSearchPaths  = true;
                context.useFallbackPaths= leafName;                                     // a partial path implies don't use fallback paths
@@ -1333,6 +1383,7 @@ bool dlopen_preflight(const char* path)
                const char* str = *it;
                free((void*)str);
        }
                const char* str = *it;
                free((void*)str);
        }
+       CRSetCrashLogMessage(NULL);
        return result;
 }
 
        return result;
 }
 
@@ -1357,6 +1408,7 @@ void* dlopen(const char* path, int mode)
        bool lockHeld = false;
        if ( (dyld::gLibSystemHelpers != NULL) && (dyld::gLibSystemHelpers->version >= 4) ) {
                dyld::gLibSystemHelpers->acquireGlobalDyldLock();
        bool lockHeld = false;
        if ( (dyld::gLibSystemHelpers != NULL) && (dyld::gLibSystemHelpers->version >= 4) ) {
                dyld::gLibSystemHelpers->acquireGlobalDyldLock();
+               CRSetCrashLogMessage("dyld: in dlopen()");
                lockHeld = true;
        }
                
                lockHeld = true;
        }
                
@@ -1376,6 +1428,27 @@ void* dlopen(const char* path, int mode)
  
                const bool leafName = (strchr(path, '/') == NULL);
                const bool absolutePath = (path[0] == '/');
  
                const bool leafName = (strchr(path, '/') == NULL);
                const bool absolutePath = (path[0] == '/');
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
+               char canonicalPath[PATH_MAX]; 
+               // <rdar://problem/7017050> dlopen() not opening frameworks from shared cache with // or ./ in path
+               if ( !leafName ) {
+                       // make path canonical if it contains a // or ./
+                       if ( (strstr(path, "//") != NULL) || (strstr(path, "./") != NULL) ) {
+                               const char* lastSlash = strrchr(path, '/');
+                               char dirPath[PATH_MAX]; 
+                               if ( strlcpy(dirPath, path, sizeof(dirPath)) < sizeof(dirPath) ) {
+                                       dirPath[lastSlash-path] = '\0';
+                                       if ( realpath(dirPath, canonicalPath) ) {
+                                               strlcat(canonicalPath, "/", sizeof(canonicalPath));
+                                               if ( strlcat(canonicalPath, lastSlash+1, sizeof(canonicalPath)) < sizeof(canonicalPath) ) {
+                                                       // if all fit in buffer, use new canonical path
+                                                       path = canonicalPath;
+                                               }
+                                       }
+                               }
+                       }
+               }
+#endif
                dyld::LoadContext context;
                context.useSearchPaths  = true;
                context.useFallbackPaths= leafName;                             // a partial path means no fallback paths
                dyld::LoadContext context;
                context.useSearchPaths  = true;
                context.useFallbackPaths= leafName;                             // a partial path means no fallback paths
@@ -1416,6 +1489,7 @@ void* dlopen(const char* path, int mode)
                        
                        // release global dyld lock early, this enables initializers to do threaded operations
                        if ( lockHeld ) {
                        
                        // release global dyld lock early, this enables initializers to do threaded operations
                        if ( lockHeld ) {
+                               CRSetCrashLogMessage(NULL);
                                dyld::gLibSystemHelpers->releaseGlobalDyldLock();
                                lockHeld = false;
                        }
                                dyld::gLibSystemHelpers->releaseGlobalDyldLock();
                                lockHeld = false;
                        }
@@ -1462,8 +1536,10 @@ void* dlopen(const char* path, int mode)
                dlerrorSet("image not already loaded");
        }
        
                dlerrorSet("image not already loaded");
        }
        
-       if ( lockHeld ) 
+       if ( lockHeld ) {
+               CRSetCrashLogMessage(NULL);
                dyld::gLibSystemHelpers->releaseGlobalDyldLock();
                dyld::gLibSystemHelpers->releaseGlobalDyldLock();
+       }
        return result;
 }
 
        return result;
 }
 
@@ -1505,6 +1581,7 @@ int dladdr(const void* address, Dl_info* info)
        if ( dyld::gLogAPIs )
                dyld::log("%s(%p, %p)\n", __func__, address, info);
 
        if ( dyld::gLogAPIs )
                dyld::log("%s(%p, %p)\n", __func__, address, info);
 
+       CRSetCrashLogMessage("dyld: in dladdr()");
        ImageLoader* image = dyld::findImageContainingAddress(address);
        if ( image != NULL ) {
                info->dli_fname = image->getPath();
        ImageLoader* image = dyld::findImageContainingAddress(address);
        if ( image != NULL ) {
                info->dli_fname = image->getPath();
@@ -1513,6 +1590,7 @@ int dladdr(const void* address, Dl_info* info)
                        // special case lookup of header
                        info->dli_sname = "__dso_handle";
                        info->dli_saddr = info->dli_fbase;
                        // special case lookup of header
                        info->dli_sname = "__dso_handle";
                        info->dli_saddr = info->dli_fbase;
+                       CRSetCrashLogMessage(NULL);
                        return 1; // success
                }
                // find closest symbol in the image
                        return 1; // success
                }
                // find closest symbol in the image
@@ -1521,12 +1599,15 @@ int dladdr(const void* address, Dl_info* info)
                        if ( info->dli_sname[0] == '_' )
                                info->dli_sname = info->dli_sname +1; // strip off leading underscore
                        //dyld::log("dladdr(%p) => %p %s\n", address, info->dli_saddr, info->dli_sname);
                        if ( info->dli_sname[0] == '_' )
                                info->dli_sname = info->dli_sname +1; // strip off leading underscore
                        //dyld::log("dladdr(%p) => %p %s\n", address, info->dli_saddr, info->dli_sname);
+                       CRSetCrashLogMessage(NULL);
                        return 1; // success
                }
                info->dli_sname = NULL;
                info->dli_saddr = NULL;
                        return 1; // success
                }
                info->dli_sname = NULL;
                info->dli_saddr = NULL;
+               CRSetCrashLogMessage(NULL);
                return 1; // success
        }
                return 1; // success
        }
+       CRSetCrashLogMessage(NULL);
        return 0;  // failure
 }
 
        return 0;  // failure
 }
 
@@ -1552,6 +1633,7 @@ void* dlsym(void* handle, const char* symbolName)
        if ( dyld::gLogAPIs )
                dyld::log("%s(%p, %s)\n", __func__, handle, symbolName);
 
        if ( dyld::gLogAPIs )
                dyld::log("%s(%p, %s)\n", __func__, handle, symbolName);
 
+       CRSetCrashLogMessage("dyld: in dlsym()");
        dlerrorClear();
 
        const ImageLoader* image;
        dlerrorClear();
 
        const ImageLoader* image;
@@ -1566,11 +1648,13 @@ void* dlsym(void* handle, const char* symbolName)
        // magic "search all" handle
        if ( handle == RTLD_DEFAULT ) {
                if ( dyld::flatFindExportedSymbol(underscoredName, &sym, &image) ) {
        // magic "search all" handle
        if ( handle == RTLD_DEFAULT ) {
                if ( dyld::flatFindExportedSymbol(underscoredName, &sym, &image) ) {
+                       CRSetCrashLogMessage(NULL);
                        return (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
                }
                const char* str = dyld::mkstringf("dlsym(RTLD_DEFAULT, %s): symbol not found", symbolName);
                dlerrorSet(str);
                free((void*)str);
                        return (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
                }
                const char* str = dyld::mkstringf("dlsym(RTLD_DEFAULT, %s): symbol not found", symbolName);
                dlerrorSet(str);
                free((void*)str);
+               CRSetCrashLogMessage(NULL);
                return NULL;
        }
        
                return NULL;
        }
        
@@ -1579,25 +1663,37 @@ void* dlsym(void* handle, const char* symbolName)
                image = dyld::mainExecutable();
                sym = image->findExportedSymbol(underscoredName, true, &image); // search RTLD_FIRST way
                if ( sym != NULL ) {
                image = dyld::mainExecutable();
                sym = image->findExportedSymbol(underscoredName, true, &image); // search RTLD_FIRST way
                if ( sym != NULL ) {
+                       CRSetCrashLogMessage(NULL);
                        return (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
                }
                const char* str = dyld::mkstringf("dlsym(RTLD_MAIN_ONLY, %s): symbol not found", symbolName);
                dlerrorSet(str);
                free((void*)str);
                        return (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
                }
                const char* str = dyld::mkstringf("dlsym(RTLD_MAIN_ONLY, %s): symbol not found", symbolName);
                dlerrorSet(str);
                free((void*)str);
+               CRSetCrashLogMessage(NULL);
                return NULL;
        }
        
        // magic "search what I would see" handle
        if ( handle == RTLD_NEXT ) {
                return NULL;
        }
        
        // magic "search what I would see" handle
        if ( handle == RTLD_NEXT ) {
+#if __ppc__
+               // <rdar://problem/7628929> work around for llvmgcc bug
+               void* fa = __builtin_frame_address(0);
+               fa = *(void**)fa;
+               fa = *(void**)fa;
+               void* callerAddress = *((void**)(((int)fa)+8));
+#else  
                void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
                void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
+#endif
                ImageLoader* callerImage = dyld::findImageContainingAddress(callerAddress);
                sym = callerImage->findExportedSymbolInDependentImages(underscoredName, dyld::gLinkContext, &image); // don't search image, but do search what it links against
                if ( sym != NULL ) {
                ImageLoader* callerImage = dyld::findImageContainingAddress(callerAddress);
                sym = callerImage->findExportedSymbolInDependentImages(underscoredName, dyld::gLinkContext, &image); // don't search image, but do search what it links against
                if ( sym != NULL ) {
+                       CRSetCrashLogMessage(NULL);
                        return (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
                }
                const char* str = dyld::mkstringf("dlsym(RTLD_NEXT, %s): symbol not found", symbolName);
                dlerrorSet(str);
                free((void*)str);
                        return (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
                }
                const char* str = dyld::mkstringf("dlsym(RTLD_NEXT, %s): symbol not found", symbolName);
                dlerrorSet(str);
                free((void*)str);
+               CRSetCrashLogMessage(NULL);
                return NULL;
        }
        // magic "search me, then what I would see" handle
                return NULL;
        }
        // magic "search me, then what I would see" handle
@@ -1606,11 +1702,13 @@ void* dlsym(void* handle, const char* symbolName)
                ImageLoader* callerImage = dyld::findImageContainingAddress(callerAddress);
                sym = callerImage->findExportedSymbolInImageOrDependentImages(underscoredName, dyld::gLinkContext, &image); // search image and what it links against
                if ( sym != NULL ) {
                ImageLoader* callerImage = dyld::findImageContainingAddress(callerAddress);
                sym = callerImage->findExportedSymbolInImageOrDependentImages(underscoredName, dyld::gLinkContext, &image); // search image and what it links against
                if ( sym != NULL ) {
+                       CRSetCrashLogMessage(NULL);
                        return (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
                }
                const char* str = dyld::mkstringf("dlsym(RTLD_SELF, %s): symbol not found", symbolName);
                dlerrorSet(str);
                free((void*)str);
                        return (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
                }
                const char* str = dyld::mkstringf("dlsym(RTLD_SELF, %s): symbol not found", symbolName);
                dlerrorSet(str);
                free((void*)str);
+               CRSetCrashLogMessage(NULL);
                return NULL;
        }
        // real handle
                return NULL;
        }
        // real handle
@@ -1622,6 +1720,7 @@ void* dlsym(void* handle, const char* symbolName)
                        sym = image->findExportedSymbolInImageOrDependentImages(underscoredName, dyld::gLinkContext, &image); // search image and what it links against
                
                if ( sym != NULL ) {
                        sym = image->findExportedSymbolInImageOrDependentImages(underscoredName, dyld::gLinkContext, &image); // search image and what it links against
                
                if ( sym != NULL ) {
+                       CRSetCrashLogMessage(NULL);
                        return (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
                }
                const char* str = dyld::mkstringf("dlsym(%p, %s): symbol not found", handle, symbolName);
                        return (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
                }
                const char* str = dyld::mkstringf("dlsym(%p, %s): symbol not found", handle, symbolName);
@@ -1631,6 +1730,7 @@ void* dlsym(void* handle, const char* symbolName)
        else {
                dlerrorSet("invalid handle passed to dlsym()");
        }
        else {
                dlerrorSet("invalid handle passed to dlsym()");
        }
+       CRSetCrashLogMessage(NULL);
        return NULL;
 }
 
        return NULL;
 }
 
@@ -1675,7 +1775,6 @@ void dyld_register_image_state_change_handler(dyld_image_states state, bool batc
                dyld::registerImageStateSingleChangeHandler(state, handler);
 }
 
                dyld::registerImageStateSingleChangeHandler(state, handler);
 }
 
-
 const char* dyld_image_path_containing_address(const void* address)
 {
        if ( dyld::gLogAPIs )
 const char* dyld_image_path_containing_address(const void* address)
 {
        if ( dyld::gLogAPIs )
@@ -1688,3 +1787,13 @@ const char* dyld_image_path_containing_address(const void* address)
 }
 
 
 }
 
 
+
+#if __IPHONE_OS_VERSION_MIN_REQUIRED   
+bool dyld_shared_cache_some_image_overridden()
+{
+       return dyld::gSharedCacheOverridden;
+}
+#endif
+
+
+
index e14a6efdd9724cb973fd0ef19d60d927c995a58c..cb99cdd75564ebfde28062a1c3884bb3439efe76 100644 (file)
 
 #include "dyldLock.h"
 
 
 #include "dyldLock.h"
 
-extern "C" int __cxa_atexit(void (*func)(void *), void *arg, void *dso);
+extern "C" int  __cxa_atexit(void (*func)(void *), void *arg, void *dso);
+extern "C" void __cxa_finalize(const void *dso);
 
 
-#define DYLD_SHARED_CACHE_SUPPORT (__ppc__ || __i386__ || __ppc64__ || __x86_64__)
+#ifndef LC_LOAD_UPWARD_DYLIB
+       #define LC_LOAD_UPWARD_DYLIB (0x23|LC_REQ_DYLD) /* load of dylib whose initializers run later */
+#endif
+
+#define DYLD_SHARED_CACHE_SUPPORT (__ppc__ || __i386__ || __ppc64__ || __x86_64__ || __arm__)
 
 // deprecated APIs are still availble on Mac OS X, but not on iPhone OS
 #if __IPHONE_OS_VERSION_MIN_REQUIRED   
 
 // deprecated APIs are still availble on Mac OS X, but not on iPhone OS
 #if __IPHONE_OS_VERSION_MIN_REQUIRED   
@@ -104,15 +109,16 @@ void NSInstallLinkEditErrorHandlers(
 const NSLinkEditErrorHandlers* handlers)
 {
        DYLD_LOCK_THIS_BLOCK;
 const NSLinkEditErrorHandlers* handlers)
 {
        DYLD_LOCK_THIS_BLOCK;
-    static void (*p)(
-       void     (*undefined)(const char* symbol_name),
-       NSModule (*multiple)(NSSymbol s, NSModule old, NSModule newhandler),
-       void     (*linkEdit)(NSLinkEditErrors c, int errorNumber,
-                    const char* fileName, const char* errorString)) = NULL;
+       typedef void (*ucallback_t)(const char* symbol_name);
+       typedef NSModule (*mcallback_t)(NSSymbol s, NSModule old, NSModule newhandler);
+       typedef void (*lcallback_t)(NSLinkEditErrors c, int errorNumber,
+                                                               const char* fileName, const char* errorString);
+       static void (*p)(ucallback_t undefined, mcallback_t multiple, lcallback_t linkEdit) = NULL;
 
        if(p == NULL)
            _dyld_func_lookup("__dyld_install_handlers", (void**)&p);
 
        if(p == NULL)
            _dyld_func_lookup("__dyld_install_handlers", (void**)&p);
-       p(handlers->undefined, handlers->multiple, handlers->linkEdit);
+       mcallback_t m = handlers->multiple;
+       p(handlers->undefined, m, handlers->linkEdit);
 }
 
 const char* 
 }
 
 const char* 
@@ -346,6 +352,7 @@ const char* libraryName)
                switch ( lc->cmd ) { 
                        case LC_LOAD_DYLIB:
                        case LC_LOAD_WEAK_DYLIB:
                switch ( lc->cmd ) { 
                        case LC_LOAD_DYLIB:
                        case LC_LOAD_WEAK_DYLIB:
+                       case LC_LOAD_UPWARD_DYLIB:
                                dl = (struct dylib_command *)lc;
                                install_name = (char *)dl + dl->dylib.name.offset;
                                if(names_match(install_name, libraryName) == TRUE)
                                dl = (struct dylib_command *)lc;
                                install_name = (char *)dl + dl->dylib.name.offset;
                                if(names_match(install_name, libraryName) == TRUE)
@@ -765,7 +772,8 @@ _dyld_register_func_for_add_image(
 void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide))
 {
        DYLD_LOCK_THIS_BLOCK;
 void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide))
 {
        DYLD_LOCK_THIS_BLOCK;
-    static void (*p)(void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide)) = NULL;
+       typedef void (*callback_t)(const struct mach_header *mh, intptr_t vmaddr_slide);
+    static void (*p)(callback_t func) = NULL;
 
        if(p == NULL)
            _dyld_func_lookup("__dyld_register_func_for_add_image", (void**)&p);
 
        if(p == NULL)
            _dyld_func_lookup("__dyld_register_func_for_add_image", (void**)&p);
@@ -782,7 +790,8 @@ _dyld_register_func_for_remove_image(
 void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide))
 {
        DYLD_LOCK_THIS_BLOCK;
 void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide))
 {
        DYLD_LOCK_THIS_BLOCK;
-    static void (*p)(void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide)) = NULL;
+       typedef void (*callback_t)(const struct mach_header *mh, intptr_t vmaddr_slide);
+    static void (*p)(callback_t func) = NULL;
 
        if(p == NULL)
            _dyld_func_lookup("__dyld_register_func_for_remove_image", (void**)&p);
 
        if(p == NULL)
            _dyld_func_lookup("__dyld_register_func_for_remove_image", (void**)&p);
@@ -972,7 +981,8 @@ void _dyld_moninit(
 void (*monaddition)(char *lowpc, char *highpc))
 {
        DYLD_LOCK_THIS_BLOCK;
 void (*monaddition)(char *lowpc, char *highpc))
 {
        DYLD_LOCK_THIS_BLOCK;
-    static void (*p)(void (*monaddition)(char *lowpc, char *highpc)) = NULL;
+       typedef void (*monproc)(char *lowpc, char *highpc);
+    static void (*p)(monproc monaddition) = NULL;
 
        if(p == NULL)
            _dyld_func_lookup("__dyld_moninit", (void**)&p);
 
        if(p == NULL)
            _dyld_func_lookup("__dyld_moninit", (void**)&p);
@@ -1067,7 +1077,7 @@ static void shared_cache_out_of_date()
 
 
 // the table passed to dyld containing thread helpers
 
 
 // the table passed to dyld containing thread helpers
-static dyld::LibSystemHelpers sHelpers = { 6, &dyldGlobalLockAcquire, &dyldGlobalLockRelease,  
+static dyld::LibSystemHelpers sHelpers = { 8, &dyldGlobalLockAcquire, &dyldGlobalLockRelease,  
                                                                        &getPerThreadBufferFor_dlerror, &malloc, &free, &__cxa_atexit,
                                                #if DYLD_SHARED_CACHE_SUPPORT
                                                                        &shared_cache_missing, &shared_cache_out_of_date,
                                                                        &getPerThreadBufferFor_dlerror, &malloc, &free, &__cxa_atexit,
                                                #if DYLD_SHARED_CACHE_SUPPORT
                                                                        &shared_cache_missing, &shared_cache_out_of_date,
@@ -1076,14 +1086,17 @@ static dyld::LibSystemHelpers sHelpers = { 6, &dyldGlobalLockAcquire, &dyldGloba
                                                #endif
                                                                        NULL, NULL,
                                                                        &pthread_key_create, &pthread_setspecific,
                                                #endif
                                                                        NULL, NULL,
                                                                        &pthread_key_create, &pthread_setspecific,
-                                                                       &malloc_size };
+                                                                       &malloc_size,
+                                                                       &pthread_getspecific,
+                                                                       &__cxa_finalize};
 
 
 //
 // during initialization of libSystem this routine will run
 // and call dyld, registering the helper functions.
 //
 
 
 //
 // during initialization of libSystem this routine will run
 // and call dyld, registering the helper functions.
 //
-extern "C" void _dyld_initializer() __attribute__((visibility("hidden")));
+extern "C" void tlv_initializer();
+extern "C" void _dyld_initializer();
 void _dyld_initializer()
 {
        DYLD_LOCK_INITIALIZER;
 void _dyld_initializer()
 {
        DYLD_LOCK_INITIALIZER;
@@ -1093,6 +1106,8 @@ void _dyld_initializer()
        _dyld_func_lookup("__dyld_register_thread_helpers", (void**)&p);
        if(p != NULL)
                p(&sHelpers);
        _dyld_func_lookup("__dyld_register_thread_helpers", (void**)&p);
        if(p != NULL)
                p(&sHelpers);
+               
+       tlv_initializer();
 }
 
 
 }
 
 
@@ -1187,7 +1202,6 @@ const struct dyld_all_image_infos* _dyld_get_all_image_infos()
 }
 
 #if !__arm__
 }
 
 #if !__arm__
-__attribute__((visibility("hidden"))) 
 bool _dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info)
 {
        DYLD_NO_LOCK_THIS_BLOCK;
 bool _dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info)
 {
        DYLD_NO_LOCK_THIS_BLOCK;
@@ -1200,7 +1214,7 @@ bool _dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info)
 #endif
 
 
 #endif
 
 
-#if __i386__ || __x86_64__
+#if __i386__ || __x86_64__ || __arm__
 __attribute__((visibility("hidden"))) 
 void* _dyld_fast_stub_entry(void* loadercache, long lazyinfo)
 {
 __attribute__((visibility("hidden"))) 
 void* _dyld_fast_stub_entry(void* loadercache, long lazyinfo)
 {
@@ -1224,4 +1238,30 @@ const char* dyld_image_path_containing_address(const void* addr)
        return p(addr);
 }
 
        return p(addr);
 }
 
+#if __IPHONE_OS_VERSION_MIN_REQUIRED   
+bool dyld_shared_cache_some_image_overridden()
+{
+       DYLD_NO_LOCK_THIS_BLOCK;
+    static bool (*p)() = NULL;
+
+       if(p == NULL)
+           _dyld_func_lookup("__dyld_shared_cache_some_image_overridden", (void**)&p);
+       return p();
+}
+#endif
+
+
+// SPI called __fork
+void _dyld_fork_child()
+{
+       DYLD_NO_LOCK_THIS_BLOCK;
+    static void (*p)() = NULL;
+
+       if(p == NULL)
+           _dyld_func_lookup("__dyld_fork_child", (void**)&p);
+       return p();
+}
+
+
+
 
 
index 0cf1a18ec44fcc5e76a59a342b340dfc31069889..cff7dbe7474d1d66e7e49d162bed3384b295d2b9 100644 (file)
@@ -30,6 +30,7 @@
 #include <stdbool.h>
 #include <stdarg.h>
 #include <pthread.h>
 #include <stdbool.h>
 #include <stdarg.h>
 #include <pthread.h>
+#include <Availability.h>
 
 #include "mach-o/dyld_priv.h"
 #include "dyldLibSystemInterface.h"
 
 #include "mach-o/dyld_priv.h"
 #include "dyldLibSystemInterface.h"
@@ -52,12 +53,57 @@ extern struct LibSystemHelpers* _ZN4dyld17gLibSystemHelpersE;
 #endif
 
 
 #endif
 
 
-#if __i386__ || __x86_64 || __ppc__
+//
+//  The standard versions of __cxa_get_globals*() from libstdc++-static.a cannot be used.
+//  On Mac OS X, they use keymgr which dyld does not implement.
+//  On iPhoneOS, they use pthread_key_create which dyld cannot use.
+//
+//   Implement these ourselves to make upcalls into libSystem to malloc and create a pthread key
+//
+static pthread_key_t                           sCxaKey = 0;
+static char                                                    sPreMainCxaGlobals[2*sizeof(long)];
+
+// called by libstdc++.a 
+char* __cxa_get_globals() 
+{      
+       // if libSystem.dylib not yet initialized, or is old libSystem, use shared global
+       if ( (_ZN4dyld17gLibSystemHelpersE == NULL) || (_ZN4dyld17gLibSystemHelpersE->version < 5) )
+               return sPreMainCxaGlobals;
+
+       if ( sCxaKey == 0 ) {
+               // create key
+               // 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);
+       if ( data == NULL ) {
+               data = calloc(2,sizeof(void*));
+               _ZN4dyld17gLibSystemHelpersE->pthread_setspecific(sCxaKey, data);
+       }
+       return data; 
+}
+
+// called by libstdc++.a 
+char* __cxa_get_globals_fast() 
+{ 
+       // if libSystem.dylib not yet initialized, or is old libSystem, use shared global
+       if ( (_ZN4dyld17gLibSystemHelpersE == NULL) || (_ZN4dyld17gLibSystemHelpersE->version < 5) )
+               return sPreMainCxaGlobals;
+
+       return pthread_getspecific(sCxaKey); 
+}
+
+
+
+
+#if __x86_64__ || __i386__ || __ppc__
+//
+//  The intel/ppc versions of dyld uses zero-cost exceptions which are handled by
+//  linking with a special copy of libunwind.a
+//
 
 static struct dyld_unwind_sections     sDyldInfo;
 static void*                                           sDyldTextEnd;
 
 static struct dyld_unwind_sections     sDyldInfo;
 static void*                                           sDyldTextEnd;
-static pthread_key_t                           sCxaKey = 0;
-static char                                                    sPreMainCxaGlobals[2*sizeof(long)];
 
 // called by dyldStartup.s very early
 void dyld_exceptions_init(struct mach_header* mh, intptr_t slide)
 
 // called by dyldStartup.s very early
 void dyld_exceptions_init(struct mach_header* mh, intptr_t slide)
@@ -102,225 +148,89 @@ bool _dyld_find_unwind_sections(void* addr, struct dyld_unwind_sections* info)
        }
 }
 
        }
 }
 
-
-
-// called by libstdc++.a 
-char* __cxa_get_globals() 
-{      
-       // if libSystem.dylib not yet initialized, or is old libSystem, use shared global
-       if ( (_ZN4dyld17gLibSystemHelpersE == NULL) || (_ZN4dyld17gLibSystemHelpersE->version < 5) )
-               return sPreMainCxaGlobals;
-
-       if ( sCxaKey == 0 ) {
-               // create key
-               // 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);
-       if ( data == NULL ) {
-               data = calloc(2,sizeof(void*));
-               _ZN4dyld17gLibSystemHelpersE->pthread_setspecific(sCxaKey, data);
-       }
-       return data; 
-}
-
-// called by libstdc++.a 
-char* __cxa_get_globals_fast() 
-{ 
-       // if libSystem.dylib not yet initialized, or is old libSystem, use shared global
-       if ( (_ZN4dyld17gLibSystemHelpersE == NULL) || (_ZN4dyld17gLibSystemHelpersE->version < 5) )
-               return sPreMainCxaGlobals;
-
-       return pthread_getspecific(sCxaKey); 
-}
-
 #if __ppc__
        // the ppc version of _Znwm in libstdc++.a uses keymgr
        // need to override that
        void* _Znwm(size_t size) { return malloc(size); }
 #endif
 
 #if __ppc__
        // the ppc version of _Znwm in libstdc++.a uses keymgr
        // need to override that
        void* _Znwm(size_t size) { return malloc(size); }
 #endif
 
+#endif // __MAC_OS_X_VERSION_MIN_REQUIRED
 
 
 
 
+#if __arm__
 
 
+struct _Unwind_FunctionContext
+{
+       // next function in stack of handlers
+       struct _Unwind_FunctionContext*         prev;
 
 
-#else /*  __i386__ || __x86_64 || __ppc__ */
-
-
-
-
-
-
-//
-// BEGIN copy of code from libgcc.a source file unwind-dw2-fde-darwin.c
-//
-#define KEYMGR_API_MAJOR_GCC3           3       
-/* ... with these keys.  */
-#define KEYMGR_GCC3_LIVE_IMAGE_LIST    301     /* loaded images  */
-#define KEYMGR_GCC3_DW2_OBJ_LIST       302     /* Dwarf2 object list  */   
-#define KEYMGR_EH_GLOBALS_KEY           13 
-
-/* Node of KEYMGR_GCC3_LIVE_IMAGE_LIST.  Info about each resident image.  */
-struct live_images {
-  unsigned long this_size;                      /* sizeof (live_images)  */
-  struct mach_header *mh;                       /* the image info  */
-  unsigned long vm_slide;
-  void (*destructor)(struct live_images *);     /* destructor for this  */
-  struct live_images *next;
-  unsigned int examined_p;
-  void *fde;
-  void *object_info;
-  unsigned long info[2];                        /* Future use.  */
 };
 };
-//
-// END copy of code from libgcc.a source file unwind-dw2-fde-darwin.c
-//
 
 
-
-//
-// dyld is built as stand alone executable with a static copy of libc, libstdc++, and libgcc.
 //
 //
-// In order for C++ exceptions to work within dyld, the C++ exception handling code
-// must be able to find the exception handling frame data inside dyld.  The standard
-// exception handling code uses crt and keymgr to keep track of all images and calls
-// getsectdatafromheader("__eh_frame") to find the EH data for each image. We implement
-// our own copy of those functions below to enable exceptions within dyld.
+//  The ARM of dyld use SL-LJ based exception handling
+//  which does not require any initialization until libSystem is initialized.
 //
 //
-// Note: This exception handling is completely separate from any user code exception .
-//              handling which has its own keymgr (in libSystem).
-// 
-
-
-static struct live_images   sDyldImage;  // zero filled
-static void*                           sObjectList = NULL;
-#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4))
-static void*                           sEHGlobals = NULL;
-#endif
-
-
-// called by dyldStartup.s very early
 void dyld_exceptions_init(struct mach_header *mh, uintptr_t slide)
 {
 void dyld_exceptions_init(struct mach_header *mh, uintptr_t slide)
 {
-       sDyldImage.this_size = sizeof(struct live_images);
-       sDyldImage.mh = mh;
-       sDyldImage.vm_slide = slide;
 }
 
 }
 
+static pthread_key_t                                           sThreadChainKey = 0; 
+static struct _Unwind_FunctionContext*         sStaticThreadChain = NULL; 
 
 
-
-//  Hack for gcc 3.5's use of keymgr includes accessing __keymgr_global
-#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4))
-typedef struct Sinfo_Node {
-  uint32_t size;               /* Size of this node.  */
-  uint16_t major_version; /* API major version.  */
-  uint16_t minor_version;      /* API minor version.  */
-} Tinfo_Node;
-static const Tinfo_Node keymgr_info = { sizeof (Tinfo_Node), KEYMGR_API_MAJOR_GCC3, 0 };
-const Tinfo_Node* __keymgr_global[3] = { NULL, NULL, &keymgr_info };
-#endif
-
-static __attribute__((noreturn)) 
-void dyld_abort() 
-{
-       //dyld::log("internal dyld error\n");
-       _exit(1);
-}
-
-void* _keymgr_get_and_lock_processwide_ptr(unsigned int key)
+//
+// When libSystem's initializers are run, they call back into dyld's 
+// registerThreadHelpers which creates a pthread key and calls 
+//  __Unwind_SjLj_SetThreadKey().
+//
+void __Unwind_SjLj_SetThreadKey(pthread_key_t key)
 {
 {
-       // The C++ exception handling code uses two keys. No other keys should be seen
-       if ( key == KEYMGR_GCC3_LIVE_IMAGE_LIST ) {
-               return &sDyldImage;
-       }
-       else if ( key == KEYMGR_GCC3_DW2_OBJ_LIST ) {
-               return sObjectList;
-       }
-       dyld_abort();
+       sThreadChainKey = key;
+       //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetThreadKey(key=%d), sStaticThreadChain=%p\n", key, sStaticThreadChain);
+       // switch static chain to be per thread
+       _ZN4dyld17gLibSystemHelpersE->pthread_setspecific(sThreadChainKey, sStaticThreadChain);
+       sStaticThreadChain = NULL;
+       //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetThreadKey(key=%d), result=%d, new top=%p\n", key, result, pthread_getspecific(sThreadChainKey));
 }
 
 }
 
-void _keymgr_set_and_unlock_processwide_ptr(unsigned int key, void* value)
-{
-       // The C++ exception handling code uses just this key. No other keys should be seen
-       if ( key == KEYMGR_GCC3_DW2_OBJ_LIST ) {
-               sObjectList = value;
-               return;
-       }
-       dyld_abort();
-}
 
 
-void _keymgr_unlock_processwide_ptr(unsigned int key)
-{
-       // The C++ exception handling code uses just this key. No other keys should be seen
-       if ( key == KEYMGR_GCC3_LIVE_IMAGE_LIST ) {
-               return;
-       }
-       dyld_abort();
-}
-       
-void* _keymgr_get_per_thread_data(unsigned int key)
-{
-#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4))
-       // gcc 3.5 and later use this key
-       if ( key == KEYMGR_EH_GLOBALS_KEY )
-               return sEHGlobals;
-#endif
+//static void printChain()
+//{
+//     _ZN4dyld3logEPKcz("chain: ");
+//     struct _Unwind_FunctionContext* start = sStaticThreadChain;
+//     if ( sThreadChainKey != 0 ) {
+//             start = (struct _Unwind_FunctionContext*)pthread_getspecific(sThreadChainKey);
+//     }
+//     for (struct _Unwind_FunctionContext* p = start; p != NULL; p = p->prev) {
+//             _ZN4dyld3logEPKcz("%p -> ", p);
+//     }
+//     _ZN4dyld3logEPKcz("\n");
+//}
 
 
-       // used by std::termination which dyld does not use
-       dyld_abort();
-}
 
 
-void _keymgr_set_per_thread_data(unsigned int key, void *keydata)
+struct _Unwind_FunctionContext* __Unwind_SjLj_GetTopOfFunctionStack()
 {
 {
-#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4))
-       // gcc 3.5 and later use this key
-       if ( key == KEYMGR_EH_GLOBALS_KEY ) {
-               sEHGlobals = keydata;
-               return;
+       //_ZN4dyld3logEPKcz("__Unwind_SjLj_GetTopOfFunctionStack(),           key=%d, ", sThreadChainKey);
+       //printChain();
+       if ( sThreadChainKey != 0 ) {
+               return (struct _Unwind_FunctionContext*)pthread_getspecific(sThreadChainKey);
+       }
+       else {
+               return sStaticThreadChain;
        }
        }
-#endif
-       // used by std::termination which dyld does not use
-       dyld_abort();
 }
 
 }
 
-
-// needed by C++ exception handling code to find __eh_frame section
-const void* getsectdatafromheader(struct mach_header* mh, const char* segname, const char* sectname, unsigned long* size)
+void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext* fc)
 {
 {
-       const struct load_command* cmd;
-       unsigned long i;
-        
-       cmd = (struct load_command*) ((char *)mh + sizeof(struct macho_header));
-       for(i = 0; i < mh->ncmds; i++) {
-           if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
-                       const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
-                       if ( strcmp(seg->segname, segname) == 0 ) {
-                               const struct macho_section* sect = (struct macho_section*)( (char*)seg + sizeof(struct macho_segment_command) );
-                               unsigned long j;
-                               for (j = 0; j < seg->nsects; j++) {
-                                       if ( strcmp(sect[j].sectname, sectname) == 0 ) {
-                                               *size = sect[j].size;
-                                               return (void*)(sect[j].addr);
-                                       }
-                               }
-                   }
-               }
-           cmd = (struct load_command*)( (char*)cmd + cmd->cmdsize );
-       }
-       return NULL;
+       //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetTopOfFunctionStack(%p), key=%d, prev=%p\n", 
+       //      fc, sThreadChainKey, (fc != NULL) ? fc->prev : NULL);
+       if ( sThreadChainKey != 0 )
+               _ZN4dyld17gLibSystemHelpersE->pthread_setspecific(sThreadChainKey, fc);
+       else
+               sStaticThreadChain = fc;
+       //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetTopOfFunctionStack(%p), key=%d, ", fc, sThreadChainKey);
+       //printChain();
 }
 
 }
 
-
-// Hack for transition of rdar://problem/3933738
-// Can be removed later.
-// Allow C++ runtime to call getsectdatafromheader or getsectdatafromheader_64
-#if __LP64__
-       #undef getsectdatafromheader
-       const void* getsectdatafromheader(struct mach_header* mh, const char* segname, const char* sectname, unsigned long* size)
-       {
-               return getsectdatafromheader_64(mh, segname, sectname, size);
-       }
-#endif
-
 #endif
 
 
 #endif
 
 
index a112d18389b88a0dcda1f7f034ebbd4d2b057302..e40b1e84c7159a986ca3651a5cf20af8f0e0bee2 100644 (file)
@@ -112,6 +112,28 @@ static void runDyldInitializers(const struct macho_header* mh, intptr_t slide, i
        }
 }
 
        }
 }
 
+
+//
+//  The kernel may have slid a Position Independent Executable
+//
+static uintptr_t slideOfMainExecutable(const struct 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_SEGMENT_COMMAND ) {
+                       const struct macho_segment_command* segCmd = (struct macho_segment_command*)cmd;
+                       if ( strcmp(segCmd->segname, "__TEXT") == 0 ) {
+                               return (uintptr_t)mh - segCmd->vmaddr;
+                       }
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+       }
+       return 0;
+}
+
+
 //
 // If the kernel does not load dyld at its preferred address, we need to apply 
 // fixups to various initialized parts of the __DATA segment
 //
 // If the kernel does not load dyld at its preferred address, we need to apply 
 // fixups to various initialized parts of the __DATA segment
@@ -186,136 +208,6 @@ static void rebaseDyld(const struct macho_header* mh, intptr_t slide)
 }
 
 
 }
 
 
-//
-// For some reason the kernel loads dyld with __TEXT and __LINKEDIT writable
-// rdar://problem/3702311 
-//
-static void segmentProtectDyld(const struct macho_header* mh, intptr_t slide)
-{
-       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;
-                                       vm_address_t addr = seg->vmaddr + slide;
-                                       vm_size_t size = seg->vmsize;
-                                       const bool setCurrentPermissions = false;
-                                       vm_protect(mach_task_self(), addr, size, setCurrentPermissions, seg->initprot);
-                                       //dyld::log("dyld: segment %s, 0x%08X -> 0x%08X, set to %d\n", seg->segname, addr, addr+size-1, seg->initprot);
-                               }
-                               break;
-               }
-               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
-       }
-       
-}
-
-
-//
-// re-map the main executable to a new random address
-//
-static const struct macho_header* randomizeExecutableLoadAddress(const struct macho_header* orgMH, const char* envp[], uintptr_t* appsSlide)
-{
-#if __ppc__
-       // don't slide PIE programs running under rosetta
-       if ( dyld::isRosetta() )
-               return orgMH;
-#endif
-       // environment variable DYLD_NO_PIE can disable PIE
-       for(const char** p = envp; *p != NULL; p++) {
-               if ( strncmp(*p, "DYLD_NO_PIE=", 12) == 0 )
-                       return orgMH;
-       }
-       
-       // count segments
-       uint32_t segCount = 0;
-       const uint32_t cmd_count = orgMH->ncmds;
-       const struct load_command* const cmds = (struct load_command*)(((char*)orgMH)+sizeof(macho_header));
-       const struct load_command* cmd = cmds;
-       for (uint32_t i = 0; i < cmd_count; ++i) {
-               if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
-                       const struct macho_segment_command* segCmd = (struct macho_segment_command*)cmd;
-                       // page-zero and custom stacks don't move
-                       if ( (strcmp(segCmd->segname, "__PAGEZERO") != 0) && (strcmp(segCmd->segname, "__UNIXSTACK") != 0) ) 
-                               ++segCount;
-               }
-               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
-       }
-       
-       // make copy of segment info
-       macho_segment_command segs[segCount];
-       uint32_t index = 0;
-       uintptr_t highestAddressUsed = 0;
-       uintptr_t lowestAddressUsed = UINTPTR_MAX;
-       cmd = cmds;
-       for (uint32_t i = 0; i < cmd_count; ++i) {
-               if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
-                       const struct macho_segment_command* segCmd = (struct macho_segment_command*)cmd;
-                       if ( (strcmp(segCmd->segname, "__PAGEZERO") != 0) && (strcmp(segCmd->segname, "__UNIXSTACK") != 0) ) {
-                               segs[index++] = *segCmd;
-                               if ( (segCmd->vmaddr + segCmd->vmsize) > highestAddressUsed )
-                                       highestAddressUsed = ((segCmd->vmaddr + segCmd->vmsize) + 4095) & -4096;
-                               if ( segCmd->vmaddr < lowestAddressUsed )
-                                       lowestAddressUsed = segCmd->vmaddr;
-                               // do nothing if kernel has already randomized load address
-                               if ( (strcmp(segCmd->segname, "__TEXT") == 0) && (segCmd->vmaddr != (uintptr_t)orgMH) )
-                                       return orgMH;
-                       }
-               }
-               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
-       }
-       
-       // choose a random new base address
-#if __LP64__
-       uintptr_t highestAddressPossible = highestAddressUsed + 0x100000000ULL;
-#elif __arm__
-       uintptr_t highestAddressPossible = 0x2fe00000;
-#else
-       uintptr_t highestAddressPossible = 0x80000000;
-#endif
-       uintptr_t sizeNeeded = highestAddressUsed-lowestAddressUsed;
-       if ( (highestAddressPossible-sizeNeeded) < highestAddressUsed ) {
-               // new and old segments will overlap 
-               // need better algorithm for remapping
-               // punt and don't re-map
-               return orgMH;
-       }
-       uintptr_t possibleRange = (highestAddressPossible-sizeNeeded) - highestAddressUsed;
-       uintptr_t newBaseAddress = highestAddressUsed + ((arc4random() % possibleRange) & -4096);
-       
-       vm_address_t addr = newBaseAddress;
-       // reserve new address range
-       if ( vm_allocate(mach_task_self(), &addr, sizeNeeded, VM_FLAGS_FIXED) == KERN_SUCCESS ) {
-               // copy each segment to new address
-               for (uint32_t i = 0; i < segCount; ++i) {
-                       uintptr_t newSegAddress = segs[i].vmaddr - lowestAddressUsed + newBaseAddress;
-                       if ( (vm_copy(mach_task_self(), segs[i].vmaddr, segs[i].vmsize, newSegAddress) != KERN_SUCCESS)
-               #if !__arm__  // work around for <rdar://problem/5736393>
-                               || (vm_protect(mach_task_self(), newSegAddress, segs[i].vmsize, true, segs[i].maxprot) != KERN_SUCCESS) 
-               #endif
-                               || (vm_protect(mach_task_self(), newSegAddress, segs[i].vmsize, false, segs[i].initprot) != KERN_SUCCESS) ) {
-                               // can't copy so dealloc new region and run with original base address
-                               vm_deallocate(mach_task_self(), newBaseAddress, sizeNeeded);
-                               dyld::warn("could not relocate position independent executable\n");
-                               return orgMH;
-                       }
-               }
-               // unmap original segments
-               vm_deallocate(mach_task_self(), lowestAddressUsed, highestAddressUsed-lowestAddressUsed);
-       
-               // run with newly mapped executable
-               *appsSlide = newBaseAddress - lowestAddressUsed;
-               return (const struct macho_header*)newBaseAddress;
-       }
-       
-       // can't get new range, so don't slide to random address
-       return orgMH;
-}
-
-
 extern "C" void dyld_exceptions_init(const struct macho_header*, uintptr_t slide); // in dyldExceptions.cpp
 extern "C" void mach_init();
 
 extern "C" void dyld_exceptions_init(const struct macho_header*, uintptr_t slide); // in dyldExceptions.cpp
 extern "C" void mach_init();
 
@@ -335,28 +227,27 @@ extern "C" {
 //  This is code to bootstrap dyld.  This work in normally done for a program by dyld and crt.
 //  In dyld we have to do this manually.
 //
 //  This is code to bootstrap dyld.  This work in normally done for a program by dyld and crt.
 //  In dyld we have to do this manually.
 //
-uintptr_t start(const struct macho_header* appsMachHeader, int argc, const char* argv[], intptr_t slide)
+uintptr_t start(const struct macho_header* appsMachHeader, int argc, const char* argv[], 
+                                                               intptr_t slide, const struct macho_header* dyldsMachHeader)
 {
 {
-       // _mh_dylinker_header is magic symbol defined by static linker (ld), see <mach-o/ldsyms.h>
-       const struct macho_header* dyldsMachHeader =  (const struct macho_header*)(((char*)&_mh_dylinker_header)+slide);
-       
        // if kernel had to slide dyld, we need to fix up load sensitive locations
        // we have to do this before using any global variables
        if ( slide != 0 ) {
                rebaseDyld(dyldsMachHeader, slide);
        }
        // if kernel had to slide dyld, we need to fix up load sensitive locations
        // we have to do this before using any global variables
        if ( slide != 0 ) {
                rebaseDyld(dyldsMachHeader, slide);
        }
-       
-       uintptr_t appsSlide = 0;
-               
+
+#if __IPHONE_OS_VERSION_MIN_REQUIRED           
+       // set pthread keys to dyld range
+       __pthread_tsd_first = 1;
+       _pthread_keys_init();
+#endif
+
        // enable C++ exceptions to work inside dyld
        dyld_exceptions_init(dyldsMachHeader, slide);
        
        // allow dyld to use mach messaging
        mach_init();
 
        // enable C++ exceptions to work inside dyld
        dyld_exceptions_init(dyldsMachHeader, slide);
        
        // allow dyld to use mach messaging
        mach_init();
 
-       // set protection on segments (has to be done after mach_init)
-       segmentProtectDyld(dyldsMachHeader, slide);
-       
        // kernel sets up env pointer to be just past end of agv array
        const char** envp = &argv[argc+1];
        
        // kernel sets up env pointer to be just past end of agv array
        const char** envp = &argv[argc+1];
        
@@ -367,12 +258,9 @@ uintptr_t start(const struct macho_header* appsMachHeader, int argc, const char*
 
        // run all C++ initializers inside dyld
        runDyldInitializers(dyldsMachHeader, slide, argc, argv, envp, apple);
 
        // run all C++ initializers inside dyld
        runDyldInitializers(dyldsMachHeader, slide, argc, argv, envp, apple);
-       
-       // if main executable was linked -pie, then randomize its load address
-       if ( appsMachHeader->flags & MH_PIE )
-               appsMachHeader = randomizeExecutableLoadAddress(appsMachHeader, envp, &appsSlide);
-       
+               
        // now that we are done bootstrapping dyld, call dyld's main
        // 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);
 }
 
        return dyld::_main(appsMachHeader, appsSlide, argc, argv, envp, apple);
 }
 
index 2628673476f01ebd57a985701436856d2c8bb67c..bbd8b01389693dfb44b648e7c34de566cebb1536 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
 
  * @APPLE_LICENSE_HEADER_END@
  */
 
-#include <stdlib.h>
+#include <Availability.h>
 
 //
 
 //
-// <rdar://problem/6536810> Alter libdyld.a to not need libsystem to link with dylib1.o
 // This is the temporary private interface between libSystem.B.dylib and dyld
 //
 
 // This is the temporary private interface between libSystem.B.dylib and dyld
 //
 
-#if __i386__ || __x86_64__
-// The compiler driver will continue to add -ldylib1.o to ppc and arm links
-// so only i386 and x86_64 need this extra glue.
-
+//
+// Long ago, the compiler driver added -ldylib1.o to every dylib which caused a
+// __DATA,__dyld section to be added every dylib.  The new LINKEDIT format no longer requires
+// images to have a __DATA,__dyld section.  But until libdyld.dylib and dyld update
+// to some sort of vtable based interface, libdyld still needs a __DATA,__dyld section.
+// The code below adds that section.
+//
 struct __DATA__dyld { long lazy; int (*lookup)(const char*, void**); };
 
 struct __DATA__dyld { long lazy; int (*lookup)(const char*, void**); };
 
-static struct __DATA__dyld  myDyldSection __attribute__ ((section ("__DATA,__dyld"))) = { 0, NULL };
+static volatile struct __DATA__dyld  myDyldSection __attribute__ ((section ("__DATA,__dyld"))) = { 0, 0 };
 
 
-
-__attribute__((weak, visibility("hidden"))) int _dyld_func_lookup(const char* dyld_func_name, void **address)
+#if __arm__ && __MAC_OS_X_VERSION_MIN_REQUIRED
+// <rdar://problem/8755380>
+// For historical reasons, gcc and llvm-gcc added -ldylib1.o to the link line of armv6 
+// dylibs when targeting MacOSX (but not iOS).  clang cleans up that mistake, but doing
+// so would break the libdyld build.  Making _dyld_func_lookup weak,hidden means if
+// dylib1.o is used, it overrides this, otherwise this implementation is used.
+__attribute__((weak))
+#endif
+__attribute__((visibility("hidden")))
+int _dyld_func_lookup(const char* dyld_func_name, void **address)
 {
        return (*myDyldSection.lookup)(dyld_func_name, address);
 }
 
 {
        return (*myDyldSection.lookup)(dyld_func_name, address);
 }
 
-#endif
 
 
 
 
 
 
index 94062fc044b7328c6280e5b0ac2b49c91bfb8c93..874c49782eec0fe0e0c3daf4295bb4bdb69c34f7 100644 (file)
@@ -53,10 +53,14 @@ namespace dyld {
                void            (*acquireDyldInitializerLock)();
                void            (*releaseDyldInitializerLock)();
                // added in version 5
                void            (*acquireDyldInitializerLock)();
                void            (*releaseDyldInitializerLock)();
                // added in version 5
-               int             (*pthread_key_create)(pthread_key_t*, void (*destructor)(void*));
-               int             (*pthread_setspecific)(pthread_key_t, const void*);
+               int                     (*pthread_key_create)(pthread_key_t*, void (*destructor)(void*));
+               int                     (*pthread_setspecific)(pthread_key_t, const void*);
                // added in version 6
                size_t          (*malloc_size)(const void *ptr);
                // added in version 6
                size_t          (*malloc_size)(const void *ptr);
+               // added in version 7
+               void*           (*pthread_getspecific)(pthread_key_t);
+               // added in version 8
+               void            (*cxa_finalize)(const void*);
        };
 #if __cplusplus
 };
        };
 #if __cplusplus
 };
index e1214f80e32d3337883801cbfbd1def670e3e533..cf296ef3c69d0ec9fd43b55a805d2ebc5fbcbabf 100644 (file)
@@ -82,7 +82,7 @@ _dyld_all_image_infos:        .long 0
        .data
 __dyld_start_static_picbase: 
        .long   L__dyld_start_picbase
        .data
 __dyld_start_static_picbase: 
        .long   L__dyld_start_picbase
-
+Lmh:   .long   ___dso_handle
 
        .text
        .align 2
 
        .text
        .align 2
@@ -115,12 +115,16 @@ __dyld_start:
        movl    %esp,%ebp       # pointer to base of kernel frame
        andl    $-16,%esp       # force SSE alignment
        
        movl    %esp,%ebp       # pointer to base of kernel frame
        andl    $-16,%esp       # force SSE alignment
        
-       # call dyldbootstrap::start(app_mh, argc, argv, slide)
+       # call dyldbootstrap::start(app_mh, argc, argv, slide, dyld_mh)
+       subl    $12,%esp
        call    L__dyld_start_picbase
 L__dyld_start_picbase: 
        popl    %ebx            # set %ebx to runtime value of picbase
        call    L__dyld_start_picbase
 L__dyld_start_picbase: 
        popl    %ebx            # set %ebx to runtime value of picbase
-       movl    __dyld_start_static_picbase-L__dyld_start_picbase(%ebx), %eax
-       subl    %eax, %ebx      # slide = L__dyld_start_picbase - [__dyld_start_static_picbase]
+       movl    Lmh-L__dyld_start_picbase(%ebx), %ecx # ecx = prefered load address
+       movl    __dyld_start_static_picbase-L__dyld_start_picbase(%ebx), %eax
+       subl    %eax, %ebx      # ebx = slide = L__dyld_start_picbase - [__dyld_start_static_picbase]
+       addl    %ebx, %ecx      # ecx = actual load address
+       pushl   %ecx            # param5 = actual load address
        pushl   %ebx            # param4 = slide
        lea     12(%ebp),%ebx   
        pushl   %ebx            # param3 = argv
        pushl   %ebx            # param4 = slide
        lea     12(%ebp),%ebx   
        pushl   %ebx            # param3 = argv
@@ -128,7 +132,7 @@ L__dyld_start_picbase:
        pushl   %ebx            # param2 = argc
        movl    4(%ebp),%ebx    
        pushl   %ebx            # param1 = mh
        pushl   %ebx            # param2 = argc
        movl    4(%ebp),%ebx    
        pushl   %ebx            # param1 = mh
-       call    __ZN13dyldbootstrap5startEPK12macho_headeriPPKcl        
+       call    __ZN13dyldbootstrap5startEPK12macho_headeriPPKclS2_     
 
        # clean up stack and jump to result
        movl    %ebp,%esp       # restore the unaligned stack pointer
 
        # clean up stack and jump to result
        movl    %ebp,%esp       # restore the unaligned stack pointer
@@ -182,14 +186,15 @@ __dyld_start:
        movq    %rsp,%rbp       # pointer to base of kernel frame
        andq    $-16,%rsp       # force SSE alignment
        
        movq    %rsp,%rbp       # pointer to base of kernel frame
        andq    $-16,%rsp       # force SSE alignment
        
-       # call dyldbootstrap::start(app_mh, argc, argv, slide)
+       # call dyldbootstrap::start(app_mh, argc, argv, slide, dyld_mh)
        movq    8(%rbp),%rdi    # param1 = mh into %rdi
        movl    16(%rbp),%esi   # param2 = argc into %esi
        leaq    24(%rbp),%rdx   # param3 = &argv[0] into %rdx
        movq    __dyld_start_static(%rip), %r8
        leaq    __dyld_start(%rip), %rcx
        subq     %r8, %rcx      # param4 = slide into %rcx
        movq    8(%rbp),%rdi    # param1 = mh into %rdi
        movl    16(%rbp),%esi   # param2 = argc into %esi
        leaq    24(%rbp),%rdx   # param3 = &argv[0] into %rdx
        movq    __dyld_start_static(%rip), %r8
        leaq    __dyld_start(%rip), %rcx
        subq     %r8, %rcx      # param4 = slide into %rcx
-       call    __ZN13dyldbootstrap5startEPK12macho_headeriPPKcl        
+       leaq    ___dso_handle(%rip),%r8 # param5 = dyldsMachHeader
+       call    __ZN13dyldbootstrap5startEPK12macho_headeriPPKclS2_     
 
        # clean up stack and jump to result
        movq    %rbp,%rsp       # restore the unaligned stack pointer
 
        # clean up stack and jump to result
        movq    %rbp,%rsp       # restore the unaligned stack pointer
@@ -206,7 +211,8 @@ __dyld_start:
        .data
        .align 2
 __dyld_start_static_picbase: 
        .data
        .align 2
 __dyld_start_static_picbase: 
-       .g_long   L__dyld_start_picbase
+       .g_long     L__dyld_start_picbase
+Lmh:   .g_long     ___dso_handle
 
 #if __ppc__    
        .set L_mh_offset,0
 
 #if __ppc__    
        .set L_mh_offset,0
@@ -246,7 +252,7 @@ __dyld_start:
        stg     r0,0(r1)        ; terminate initial stack frame
        stgu    r1,-SF_MINSIZE(r1); allocate minimal stack frame
                
        stg     r0,0(r1)        ; terminate initial stack frame
        stgu    r1,-SF_MINSIZE(r1); allocate minimal stack frame
                
-       ; call dyldbootstrap::start(app_mh, argc, argv, slide)
+       # call dyldbootstrap::start(app_mh, argc, argv, slide, dyld_mh)
        lg      r3,L_mh_offset(r26)     ; r3 = mach_header
        lwz     r4,L_argc_offset(r26)   ; r4 = argc (int == 4 bytes)
        addi    r5,r26,L_argv_offset    ; r5 = argv
        lg      r3,L_mh_offset(r26)     ; r3 = mach_header
        lwz     r4,L_argc_offset(r26)   ; r4 = argc (int == 4 bytes)
        addi    r5,r26,L_argv_offset    ; r5 = argv
@@ -256,7 +262,10 @@ L__dyld_start_picbase:
        addis   r6,r31,ha16(__dyld_start_static_picbase-L__dyld_start_picbase)
        lg      r6,lo16(__dyld_start_static_picbase-L__dyld_start_picbase)(r6)
        subf    r6,r6,r31       ; r6 = slide
        addis   r6,r31,ha16(__dyld_start_static_picbase-L__dyld_start_picbase)
        lg      r6,lo16(__dyld_start_static_picbase-L__dyld_start_picbase)(r6)
        subf    r6,r6,r31       ; r6 = slide
-       bl      __ZN13dyldbootstrap5startEPK12macho_headeriPPKcl        
+       addis   r7,r31,ha16(Lmh-L__dyld_start_picbase)
+       lg      r7,lo16(Lmh-L__dyld_start_picbase)(r7)
+       add     r7,r6,r7        ; r7 = dyld_mh
+       bl      __ZN13dyldbootstrap5startEPK12macho_headeriPPKclS2_     
        
        ; clean up stack and jump to result
        mtctr   r3              ; Put entry point in count register
        
        ; clean up stack and jump to result
        mtctr   r3              ; Put entry point in count register
@@ -296,10 +305,23 @@ _offset_to_dyld_all_image_infos:
        .space  16
     
     
        .space  16
     
     
+       // Hack to make ___dso_handle work
+       // Without this local symbol, assembler will error out about in subtraction expression
+       // The real ___dso_handle (non-weak) sythesized by the linker
+       // Since this one is weak, the linker will throw this one away and use the real one instead.
+       .data
+       .globl ___dso_handle
+       .weak_definition ___dso_handle
+___dso_handle: .long 0
+
        .text
        .align 2
 __dyld_start:
        .text
        .align 2
 __dyld_start:
-       // call dyldbootstrap::start(app_mh, argc, argv, slide)         
+       mov     r8, sp          // save stack pointer
+       sub     sp, #8          // make room for outgoing dyld_mh parameter
+       bic     sp, sp, #7      // force 8-byte alignment
+
+       // call dyldbootstrap::start(app_mh, argc, argv, slide, dyld_mh)
 
        ldr     r3, L__dyld_start_picbase_ptr
 L__dyld_start_picbase:
 
        ldr     r3, L__dyld_start_picbase_ptr
 L__dyld_start_picbase:
@@ -307,23 +329,25 @@ L__dyld_start_picbase:
        ldr     r3, [r0, r3]    // load expected PC
        sub     r3, r0, r3      // r3 = slide
 
        ldr     r3, [r0, r3]    // load expected PC
        sub     r3, r0, r3      // r3 = slide
 
-       ldr     r0, [sp]        // r0 = mach_header
-       ldr     r1, [sp, #4]    // r1 = argc
-       add     r2, sp, #8      // r2 = argv
+       ldr     r0, [r8]        // r0 = mach_header
+       ldr     r1, [r8, #4]    // r1 = argc
+       add     r2, r8, #8      // r2 = argv
 
 
-       mov     r8, sp          // save stack pointer
-       bic     sp, sp, #7      // force 8-byte alignment
+       ldr     r4, Lmh
+L3:    add     r4, r4, pc      // r4 = dyld_mh
+       str     r4, [sp, #0]
        
        
-       bl      __ZN13dyldbootstrap5startEPK12macho_headeriPPKcl
+       bl      __ZN13dyldbootstrap5startEPK12macho_headeriPPKclS2_
        
        // clean up stack and jump to result
        add     sp, r8, #4      // remove the mach_header argument.
        bx      r0              // jump to the program's entry point
 
        
        // clean up stack and jump to result
        add     sp, r8, #4      // remove the mach_header argument.
        bx      r0              // jump to the program's entry point
 
+
        .align 2
 L__dyld_start_picbase_ptr:
        .long   __dyld_start_static_picbase-L__dyld_start_picbase
        .align 2
 L__dyld_start_picbase_ptr:
        .long   __dyld_start_static_picbase-L__dyld_start_picbase
-
+Lmh:   .long   ___dso_handle-L3-8
        
        .text
        .align 2
        
        .text
        .align 2
@@ -366,7 +390,16 @@ _dyld_fatal_error:
     #error unknown architecture
 #endif
 
     #error unknown architecture
 #endif
 
-    
-    
+#if __arm__
+       // work around for:  <rdar://problem/6530727> gdb-1109: notifier in dyld does not work if it is in thumb
+       .text
+       .align 2
+       .globl  _gdb_image_notifier
+       .private_extern _gdb_image_notifier
+_gdb_image_notifier:
+       bx  lr
+#endif
+
+
 
 
 
 
index 632efab9fbe6d579d6e479c77abeb7653f48e974..9db993f5f5c33bc3ce7ea6e74f8fa6dd27a0dc48 100644 (file)
@@ -39,6 +39,7 @@ int dummy_dyld_symbol = 1;
 
 #include "mach-o/dyld_debug.h"
 #include "mach-o/dyld_gdb.h"
 
 #include "mach-o/dyld_debug.h"
 #include "mach-o/dyld_gdb.h"
+#include "mach-o/dyld_priv.h"
 
 // global state set up by _dyld_debug_subscribe_to_events() and accessed by _dyld_debug_module_name()
 static const struct dyld_image_info*   sImages = NULL;
 
 // global state set up by _dyld_debug_subscribe_to_events() and accessed by _dyld_debug_module_name()
 static const struct dyld_image_info*   sImages = NULL;
index 7d79aade137ea0d290d8682b6a1d295bec59318d..2afa79cc9b8562d28c541c9b5492b6bd34b7011a 100644 (file)
 #include "mach-o/dyld_images.h"
 #include "ImageLoader.h"
 
 #include "mach-o/dyld_images.h"
 #include "ImageLoader.h"
 
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
+       #define INITIAL_UUID_IMAGE_COUNT 4
+#else
+       #define INITIAL_UUID_IMAGE_COUNT 32
+#endif
 
 static std::vector<dyld_image_info> sImageInfos;
 
 static std::vector<dyld_image_info> sImageInfos;
+static std::vector<dyld_uuid_info>  sImageUUIDs;
 
 void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[])
 {
 
 void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[])
 {
-       // make initial size large enought that we probably won't need to re-alloc it
+       // make initial size large enough that we probably won't need to re-alloc it
        if ( sImageInfos.size() == 0 )
                sImageInfos.reserve(INITIAL_IMAGE_COUNT);
        if ( sImageInfos.size() == 0 )
                sImageInfos.reserve(INITIAL_IMAGE_COUNT);
-
+       if ( sImageUUIDs.capacity() == 0 )
+               sImageUUIDs.reserve(4);
        // set infoArray to NULL to denote it is in-use
        dyld_all_image_infos.infoArray = NULL;
        
        // set infoArray to NULL to denote it is in-use
        dyld_all_image_infos.infoArray = NULL;
        
@@ -51,11 +58,35 @@ void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[])
                sImageInfos.push_back(info[i]);
        dyld_all_image_infos.infoArrayCount = sImageInfos.size();
        
                sImageInfos.push_back(info[i]);
        dyld_all_image_infos.infoArrayCount = sImageInfos.size();
        
-       // set infoArray back to base address of vector
+       // set infoArray back to base address of vector (other process can now read)
        dyld_all_image_infos.infoArray = &sImageInfos[0];
        dyld_all_image_infos.infoArray = &sImageInfos[0];
+}
 
 
+
+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);
        // tell gdb that about the new images
        dyld_all_image_infos.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;
+       return NULL;
+}
+
+
+
+void addNonSharedCacheImageUUID(const dyld_uuid_info& info)
+{
+       // set uuidArray to NULL to denote it is in-use
+       dyld_all_image_infos.uuidArray = NULL;
+       
+       // append all new images
+       sImageUUIDs.push_back(info);
+       dyld_all_image_infos.uuidArrayCount = sImageUUIDs.size();
+       
+       // set uuidArray back to base address of vector (other process can now read)
+       dyld_all_image_infos.uuidArray = &sImageUUIDs[0];
 }
 
 void removeImageFromAllImages(const struct mach_header* loadAddress)
 }
 
 void removeImageFromAllImages(const struct mach_header* loadAddress)
@@ -78,11 +109,30 @@ void removeImageFromAllImages(const struct mach_header* loadAddress)
        // set infoArray back to base address of vector
        dyld_all_image_infos.infoArray = &sImageInfos[0];
 
        // set infoArray back to base address of vector
        dyld_all_image_infos.infoArray = &sImageInfos[0];
 
+
+       // set uuidArrayCount to NULL to denote it is in-use
+       dyld_all_image_infos.uuidArray = NULL;
+       
+       // remove image from infoArray
+       for (std::vector<dyld_uuid_info>::iterator it=sImageUUIDs.begin(); it != sImageUUIDs.end(); it++) {
+               if ( it->imageLoadAddress == loadAddress ) {
+                       sImageUUIDs.erase(it);
+                       break;
+               }
+       }
+       dyld_all_image_infos.uuidArrayCount = sImageUUIDs.size();
+       
+       // set infoArray back to base address of vector
+       dyld_all_image_infos.uuidArray = &sImageUUIDs[0];
+
        // tell gdb that about the new images
        dyld_all_image_infos.notification(dyld_image_removing, 1, &goingAway);
 }
 
        // tell gdb that about the new images
        dyld_all_image_infos.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
 static void gdb_image_notifier(enum dyld_image_mode mode, uint32_t infoCount, const dyld_image_info info[])
 {
        // do nothing
@@ -93,6 +143,7 @@ static void gdb_image_notifier(enum dyld_image_mode mode, uint32_t infoCount, co
        //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);
 }
        //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)
 {
 
 void setAlImageInfosHalt(const char* message, uintptr_t flags)
 {
@@ -106,8 +157,11 @@ extern void* __dso_handle;
 #define XSTR(s) STR(s)
 
 struct dyld_all_image_infos  dyld_all_image_infos __attribute__ ((section ("__DATA,__all_image_info"))) 
 #define XSTR(s) STR(s)
 
 struct dyld_all_image_infos  dyld_all_image_infos __attribute__ ((section ("__DATA,__all_image_info"))) 
-                                                       = { 7, 0, NULL, &gdb_image_notifier, false, false, (const mach_header*)&__dso_handle, NULL, 
-                                                               XSTR(DYLD_VERSION) , NULL, 0, 0 };
+                                                       = { 
+                                                               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
+                                                               };
 
 struct dyld_shared_cache_ranges dyld_shared_cache_ranges;
 
 
 struct dyld_shared_cache_ranges dyld_shared_cache_ranges;
 
index 6d7f182973efd9328a0999b4a39a45e6b13e9fc3..0636dbd738b01e5d5be441ca77f7e1415155f6ec 100644 (file)
@@ -125,6 +125,7 @@ dyld_stub_binder:
        movq            %r8,R8_SAVE(%rsp)
        movq            %r9,R9_SAVE(%rsp)
        movq            %rax,RAX_SAVE(%rsp)
        movq            %r8,R8_SAVE(%rsp)
        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          %xmm0,XMMM0_SAVE(%rsp)
        movdqa          %xmm1,XMMM1_SAVE(%rsp)
        movdqa          %xmm2,XMMM2_SAVE(%rsp)
@@ -133,6 +134,7 @@ dyld_stub_binder:
        movdqa          %xmm5,XMMM5_SAVE(%rsp)
        movdqa          %xmm6,XMMM6_SAVE(%rsp)
        movdqa          %xmm7,XMMM7_SAVE(%rsp)
        movdqa          %xmm5,XMMM5_SAVE(%rsp)
        movdqa          %xmm6,XMMM6_SAVE(%rsp)
        movdqa          %xmm7,XMMM7_SAVE(%rsp)
+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            MH_PARAM_BP(%rbp),%rdi  # call fastBindLazySymbol(loadercache, lazyinfo)
        movq            LP_PARAM_BP(%rbp),%rsi
        call            __Z21_dyld_fast_stub_entryPvl
@@ -160,4 +162,30 @@ dyld_stub_binder:
 #endif
 
 
 #endif
 
 
+#if __arm__
+ /*    
+ * sp+4        lazy binding info offset
+ * sp+0        address of ImageLoader cache
+ */
+  
+       .text
+       .align 2
+       .globl  dyld_stub_binder
+dyld_stub_binder:
+       stmfd   sp!, {r0,r1,r2,r3,r7,lr}        // save registers
+       add     r7, sp, #16                     // point FP to previous FP
+
+       ldr     r0, [sp, #24]                   // move address ImageLoader cache to 1st parameter
+       ldr     r1, [sp, #28]                   // move lazy info offset 2nd parameter
+
+       // call dyld::fastBindLazySymbol(loadercache, lazyinfo)
+       bl      __Z21_dyld_fast_stub_entryPvl
+       mov     ip, r0                          // move the symbol`s address into ip
+
+       ldmfd   sp!, {r0,r1,r2,r3,r7,lr}        // restore registers
+       add     sp, sp, #8                      // remove meta-parameters
+
+       bx      ip                              // jump to the symbol`s address that was bound
+
+#endif /* __arm__ */
 
 
index 399ad2497f6c424a541e61e194ac3a5cacf946c3..9f65555d059b406708411b6756ece73421e4aba7 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2004-2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -29,6 +29,7 @@
 #include <unistd.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <mach/mach_error.h>
 
 // from _simple.h in libc
 typedef struct _SIMPLE*        _SIMPLE_STRING;
 
 // from _simple.h in libc
 typedef struct _SIMPLE*        _SIMPLE_STRING;
@@ -148,14 +149,46 @@ struct tm* localtime(const time_t* t)
        return (struct tm*)NULL;
 }
 
        return (struct tm*)NULL;
 }
 
+// malloc calls exit(-1) in case of errors...
+void exit(int x)
+{
+       _ZN4dyld4haltEPKc("exit()");
+}
+
+// static initializers make calls to __cxa_atexit
+void __cxa_atexit()
+{
+       // do nothing, dyld never terminates
+}
 
 //
 // The stack protector routines in lib.c bring in too much stuff, so 
 // make our own custom ones.
 //
 long __stack_chk_guard = 0;
 
 //
 // The stack protector routines in lib.c bring in too much stuff, so 
 // make our own custom ones.
 //
 long __stack_chk_guard = 0;
-static __attribute__((constructor)) void __guard_setup(void)
+static __attribute__((constructor)) 
+void __guard_setup(int argc, const char* argv[], const char* envp[], const char* apple[])
 {
 {
+       for (const char** p = apple; *p != NULL; ++p) {
+               if ( strncmp(*p, "stack_guard=", 12) == 0 ) {
+                       // kernel has provide a random value for us
+                       for (const char* s = *p + 12; *s != '\0'; ++s) {
+                               char c = *s;
+                               long value = 0;
+                               if ( (c >= 'a') && (c <= 'f') )
+                                       value = c - 'a' + 10;
+                               else if ( (c >= 'A') && (c <= 'F') )
+                                       value = c - 'A' + 10;
+                               else if ( (c >= '0') && (c <= '9') )
+                                       value = c - '0';
+                               __stack_chk_guard <<= 4;
+                               __stack_chk_guard |= value;
+                       }
+                       if ( __stack_chk_guard != 0 )
+                               return;
+               }
+       }
+       
 #if __LP64__
        __stack_chk_guard = ((long)arc4random() << 32) | arc4random();
 #else
 #if __LP64__
        __stack_chk_guard = ((long)arc4random() << 32) | arc4random();
 #else
@@ -169,3 +202,62 @@ void __stack_chk_fail()
 }
 
 
 }
 
 
+// std::_throw_bad_alloc()
+void _ZSt17__throw_bad_allocv()
+{
+       _ZN4dyld4haltEPKc("__throw_bad_alloc()");
+}
+
+// std::_throw_length_error(const char* x)
+void _ZSt20__throw_length_errorPKc()
+{
+       _ZN4dyld4haltEPKc("_throw_length_error()");
+}
+
+// the libc.a version of this drags in ASL
+void __chk_fail()
+{
+       _ZN4dyld4haltEPKc("__chk_fail()");
+}
+
+
+// referenced by libc.a(pthread.o) but unneeded in dyld
+void _init_cpu_capabilities() { }
+void _cpu_capabilities() {}
+void set_malloc_singlethreaded() {}
+int PR_5243343_flag = 0;
+
+
+// used by some pthread routines
+char* mach_error_string(mach_error_t err)
+{
+       return (char *)"unknown error code";
+}
+char* mach_error_type(mach_error_t err)
+{
+       return (char *)"(unknown/unknown)";
+}
+
+// _pthread_reap_thread calls fprintf(stderr). 
+// We map fprint to _simple_vdprintf and ignore FILE* stream, so ok for it to be NULL
+#if !__ppc__
+FILE* __stderrp = NULL;
+FILE* __stdoutp = NULL;
+#endif
+
+// work with c++abi.a
+void (*__cxa_terminate_handler)() = _ZSt9terminatev;
+void (*__cxa_unexpected_handler)() = _ZSt10unexpectedv;
+
+void abort_message(const char* format, ...)
+{
+       va_list list;
+       va_start(list, format);
+       _simple_vdprintf(STDERR_FILENO, format, list);
+       va_end(list);
+}      
+
+void __cxa_bad_typeid()
+{
+       _ZN4dyld4haltEPKc("__cxa_bad_typeid()");
+}
diff --git a/src/threadLocalHelpers.s b/src/threadLocalHelpers.s
new file mode 100644 (file)
index 0000000..b5bc9d5
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * 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@
+ */
+#if __x86_64__
+       // returns address of TLV in %rax, all other registers preserved
+       .globl _tlv_get_addr
+       .private_extern _tlv_get_addr
+_tlv_get_addr:
+       movq    8(%rdi),%rax                    // get key from descriptor
+       movq    %gs:0x0(,%rax,8),%rax   // get thread value
+       testq   %rax,%rax                               // if NULL, lazily allocate
+       je              LlazyAllocate
+       addq    16(%rdi),%rax                   // add offset from descriptor
+       ret
+LlazyAllocate:
+       pushq   %rbp
+       movq    %rsp, %rbp
+       subq    $592,%rsp
+       movq    %rdi,-8(%rbp)
+       movq    %rsi,-16(%rbp)
+       movq    %rdx,-24(%rbp)
+       movq    %rcx,-32(%rbp)
+       movq    %r8,-40(%rbp)
+       movq    %r9,-48(%rbp)
+       movq    %r10,-56(%rbp)
+       movq    %r11,-64(%rbp)
+       fxsave  -592(%rbp)
+       movq    8(%rdi),%rdi                    // get key from descriptor
+       call    _tlv_allocate_and_initialize_for_key  
+       fxrstor -592(%rbp)  
+       movq    -64(%rbp),%r11
+       movq    -56(%rbp),%r10
+       movq    -48(%rbp),%r9
+       movq    -40(%rbp),%r8
+       movq    -32(%rbp),%rcx
+       movq    -24(%rbp),%rdx
+       movq    -16(%rbp),%rsi
+       movq    -8(%rbp),%rdi
+       addq    16(%rdi),%rax                   // result = buffer + offset
+       addq    $592,%rsp
+       popq    %rbp
+       ret
+#endif
+
+
+
+#if __i386__
+       // returns address of TLV in %eax, all other registers (except %ecx) preserved
+       .globl _tlv_get_addr
+       .private_extern _tlv_get_addr
+_tlv_get_addr:
+       movl    4(%eax),%ecx                    // get key from descriptor
+       movl    %gs:0x0(,%ecx,4),%ecx   // get thread value
+       testl   %ecx,%ecx                               // if NULL, lazily allocate
+       je              LlazyAllocate
+       movl    8(%eax),%eax                    // add offset from descriptor
+       addl    %ecx,%eax
+       ret
+LlazyAllocate:
+       pushl   %ebp
+       movl    %esp,%ebp
+       pushl   %edx                                    // save edx
+       subl    $548,%esp
+       movl    %eax,-8(%ebp)               // save descriptor
+       lea             -528(%ebp),%ecx             // get 512 byte buffer in frame
+       and             $-16, %ecx                          // 16-byte align buffer for fxsave
+       fxsave  (%ecx)
+       movl    4(%eax),%ecx                    // get key from descriptor
+       movl    %ecx,(%esp)                 // push key parameter, also leaves stack aligned properly
+       call    _tlv_allocate_and_initialize_for_key
+       movl    -8(%ebp),%ecx                   // get descriptor
+       movl    8(%ecx),%ecx                    // get offset from descriptor
+       addl    %ecx,%eax                               // add offset to buffer
+       lea     -528(%ebp),%ecx
+       and     $-16, %ecx              // 16-byte align buffer for fxrstor
+       fxrstor (%ecx)
+       addl    $548,%esp
+       popl    %edx                    // restore edx
+       popl    %ebp
+       ret
+#endif
+
+
+#if 0
+#if __arm__
+       // returns address of TLV in r0, all other registers preserved
+       .globl _tlv_get_addr
+       .private_extern _tlv_get_addr
+_tlv_get_addr:
+       push    {r1,r2,r3,r7,lr}                                
+       mov             r7,r0                                                   // save descriptor in r7
+       ldr             r0, [r7, #4]                                    // get key from descriptor
+       bl              _pthread_getspecific                    // get thread value
+       cmp             r0, #0
+       bne             L2                                                              // if NULL, lazily allocate
+       ldr             r0, [r7, #4]                                    // get key from descriptor
+       bl              _tlv_allocate_and_initialize_for_key
+L2:    ldr             r1, [r7, #8]                                    // get offset from descriptor
+       add             r0, r1, r0                                              // add offset into allocation block
+       pop             {r1,r2,r3,r7,pc}
+#endif
+#endif
+
+
diff --git a/src/threadLocalVariables.c b/src/threadLocalVariables.c
new file mode 100644 (file)
index 0000000..2586455
--- /dev/null
@@ -0,0 +1,471 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * 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>
+#include <stdint.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <Block.h>
+#include <malloc/malloc.h>
+#include <mach-o/loader.h>
+#include <libkern/OSAtomic.h>
+
+#include "dyld_priv.h"
+
+
+#if __LP64__
+       typedef struct mach_header_64           macho_header;
+       #define LC_SEGMENT_COMMAND                      LC_SEGMENT_64
+       typedef struct segment_command_64       macho_segment_command;
+       typedef struct section_64                       macho_section;
+#else
+       typedef struct mach_header                      macho_header;
+       #define LC_SEGMENT_COMMAND                      LC_SEGMENT
+       typedef struct segment_command          macho_segment_command;
+       typedef struct section                          macho_section;
+#endif
+
+#ifndef S_THREAD_LOCAL_REGULAR
+#define S_THREAD_LOCAL_REGULAR                   0x11
+#endif
+
+#ifndef S_THREAD_LOCAL_ZEROFILL
+#define S_THREAD_LOCAL_ZEROFILL                  0x12
+#endif
+
+#ifndef S_THREAD_LOCAL_VARIABLES
+#define S_THREAD_LOCAL_VARIABLES                 0x13
+#endif
+
+#ifndef S_THREAD_LOCAL_VARIABLE_POINTERS
+#define S_THREAD_LOCAL_VARIABLE_POINTERS         0x14
+#endif
+
+#ifndef S_THREAD_LOCAL_INIT_FUNCTION_POINTERS
+#define S_THREAD_LOCAL_INIT_FUNCTION_POINTERS    0x15
+#endif
+
+#ifndef MH_HAS_TLV_DESCRIPTORS
+       #define MH_HAS_TLV_DESCRIPTORS 0x800000
+#endif
+
+#if __i386__ || __x86_64__
+
+typedef struct TLVHandler {
+       struct TLVHandler *next;
+       dyld_tlv_state_change_handler handler;
+       enum dyld_tlv_states state;
+} TLVHandler;
+
+// lock-free prepend-only linked list
+static TLVHandler * volatile tlv_handlers = NULL;
+
+
+struct TLVDescriptor
+{
+       void*                   (*thunk)(struct TLVDescriptor*);
+       unsigned long   key;
+       unsigned long   offset;
+};
+typedef struct TLVDescriptor  TLVDescriptor;
+
+
+// implemented in assembly
+extern void* tlv_get_addr(TLVDescriptor*);
+
+struct TLVImageInfo
+{
+       pthread_key_t                           key;
+       const struct mach_header*       mh;
+};
+typedef struct TLVImageInfo            TLVImageInfo;
+
+static TLVImageInfo*   tlv_live_images = NULL;
+static unsigned int            tlv_live_image_alloc_count = 0;
+static unsigned int            tlv_live_image_used_count = 0;
+static pthread_mutex_t tlv_live_image_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static void tlv_set_key_for_image(const struct mach_header* mh, pthread_key_t key)
+{
+       pthread_mutex_lock(&tlv_live_image_lock);
+               if ( tlv_live_image_used_count == tlv_live_image_alloc_count ) {
+                       unsigned int newCount = (tlv_live_images == NULL) ? 8 : 2*tlv_live_image_alloc_count;
+                       struct TLVImageInfo* newBuffer = malloc(sizeof(TLVImageInfo)*newCount);
+                       if ( tlv_live_images != NULL ) {
+                               memcpy(newBuffer, tlv_live_images, sizeof(TLVImageInfo)*tlv_live_image_used_count);
+                               free(tlv_live_images);
+                       }
+                       tlv_live_images = newBuffer;
+                       tlv_live_image_alloc_count = newCount;
+               }
+               tlv_live_images[tlv_live_image_used_count].key = key;
+               tlv_live_images[tlv_live_image_used_count].mh = mh;
+               ++tlv_live_image_used_count;
+       pthread_mutex_unlock(&tlv_live_image_lock);
+}
+
+static const struct mach_header* tlv_get_image_for_key(pthread_key_t key)
+{
+       const struct mach_header* result = NULL;
+       pthread_mutex_lock(&tlv_live_image_lock);
+               for(unsigned int i=0; i < tlv_live_image_used_count; ++i) {
+                       if ( tlv_live_images[i].key == key ) {
+                               result = tlv_live_images[i].mh;
+                               break;
+                       }
+               }
+       pthread_mutex_unlock(&tlv_live_image_lock);
+       return result;
+}
+
+
+static void
+tlv_notify(enum dyld_tlv_states state, void *buffer)
+{
+       if (!tlv_handlers) return;
+
+       // Always use malloc_size() to ensure allocated and deallocated states 
+       // send the same size. tlv_free() doesn't have anything else recorded.
+       dyld_tlv_info info = { sizeof(info), buffer, malloc_size(buffer) };
+       
+       for (TLVHandler *h = tlv_handlers; h != NULL; h = h->next) {
+               if (h->state == state  &&  h->handler) {
+                       h->handler(h->state, &info);
+               }
+       }
+}
+
+
+// called lazily when TLV is first accessed
+__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);
+       // first pass, find size and template
+       uint8_t*                start = NULL;
+       unsigned long   size;
+       intptr_t                slide = 0;
+       bool                    slideComputed = false;
+       bool                    hasInitializers = false;
+       const uint32_t  cmd_count = mh->ncmds;
+       const struct load_command* const cmds = (struct load_command*)(((uint8_t*)mh) + sizeof(macho_header));
+       const struct load_command* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               if ( cmd->cmd == LC_SEGMENT_COMMAND) {
+                       const macho_segment_command* seg = (macho_segment_command*)cmd;
+                       if ( !slideComputed && (seg->filesize != 0) ) {
+                               slide = (uintptr_t)mh - seg->vmaddr;
+                               slideComputed = true;
+                       }
+                       const macho_section* const sectionsStart = (macho_section*)((char*)seg + sizeof(macho_segment_command));
+                       const macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
+                       for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+                               switch ( sect->flags & SECTION_TYPE ) {
+                                       case S_THREAD_LOCAL_INIT_FUNCTION_POINTERS:
+                                               hasInitializers = true;
+                                               break;
+                                       case S_THREAD_LOCAL_ZEROFILL:
+                                       case S_THREAD_LOCAL_REGULAR:
+                                               if ( start == NULL ) {
+                                                       // first of N contiguous TLV template sections, record as if this was only section
+                                                       start = (uint8_t*)(sect->addr + slide);
+                                                       size = sect->size;
+                                               }
+                                               else {
+                                                       // non-first of N contiguous TLV template sections, accumlate values
+                                                       const uint8_t* newEnd = (uint8_t*)(sect->addr + slide + sect->size);
+                                                       size = newEnd - start;
+                                               }
+                                               break;
+                               }
+                       }
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+       }
+       
+       // allocate buffer and fill with template
+       void* buffer = malloc(size);
+       memcpy(buffer, start, size);
+       
+       // set this thread's value for key to be the new buffer.
+       pthread_setspecific(key, buffer);
+
+       // send tlv state notifications
+       tlv_notify(dyld_tlv_state_allocated, buffer);
+       
+       // second pass, run initializers
+       if ( hasInitializers ) {
+               cmd = cmds;
+               for (uint32_t i = 0; i < cmd_count; ++i) {
+                       if ( cmd->cmd == LC_SEGMENT_COMMAND) {
+                               const macho_segment_command* seg = (macho_segment_command*)cmd;
+                               const macho_section* const sectionsStart = (macho_section*)((char*)seg + sizeof(macho_segment_command));
+                               const macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
+                               for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+                                       if ( (sect->flags & SECTION_TYPE) == S_THREAD_LOCAL_INIT_FUNCTION_POINTERS ) {
+                                               typedef void (*InitFunc)(void);
+                                               InitFunc* funcs = (InitFunc*)(sect->addr + slide);
+                                               const uint32_t count = sect->size / sizeof(uintptr_t);
+                                               for (uint32_t i=count; i > 0; --i) {
+                                                       InitFunc func = funcs[i-1];
+                                                       func();
+                                               }
+                                       }
+                               }
+                       }
+                       cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+               }
+       }
+       return buffer;
+}
+
+
+// pthread destructor for TLV storage
+static void
+tlv_free(void *storage)
+{
+       tlv_notify(dyld_tlv_state_deallocated, storage);
+       free(storage);
+}
+
+
+// called when image is loaded
+static void tlv_initialize_descriptors(const struct mach_header* mh)
+{
+       pthread_key_t   key = 0;
+       intptr_t                slide = 0;
+       bool                    slideComputed = false;
+       const uint32_t cmd_count = mh->ncmds;
+       const struct load_command* const cmds = (struct load_command*)(((uint8_t*)mh) + sizeof(macho_header));
+       const struct load_command* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               if ( cmd->cmd == LC_SEGMENT_COMMAND) {
+                       const macho_segment_command* seg = (macho_segment_command*)cmd;
+                       if ( !slideComputed && (seg->filesize != 0) ) {
+                               slide = (uintptr_t)mh - seg->vmaddr;
+                               slideComputed = true;
+                       }
+                       const macho_section* const sectionsStart = (macho_section*)((char*)seg + sizeof(macho_segment_command));
+                       const macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
+                       for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+                               if ( (sect->flags & SECTION_TYPE) == S_THREAD_LOCAL_VARIABLES ) {
+                                       if ( sect->size != 0 ) {
+                                               // allocate pthread key when we first discover this image has TLVs
+                                               if ( key == 0 ) {
+                                                       int result = pthread_key_create(&key, &tlv_free);
+                                                       if ( result != 0 )
+                                                               abort();
+                                                       tlv_set_key_for_image(mh, key);
+                                               }
+                                               // initialize each descriptor
+                                               TLVDescriptor* start = (TLVDescriptor*)(sect->addr + slide);
+                                               TLVDescriptor* end = (TLVDescriptor*)(sect->addr + sect->size + slide);
+                                               for (TLVDescriptor* d=start; d < end; ++d) {
+                                                       d->thunk = tlv_get_addr;
+                                                       d->key = key;
+                                                       //d->offset = d->offset;  // offset unchanged
+                                               }
+                                       }
+                               }
+                       }
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+       }
+}
+
+// called by dyld when a image is loaded
+static const char* tlv_load_notification(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+{
+       // this is called on all images, even those without TLVs, so we want
+       // this to be fast.  The linker sets MH_HAS_TLV_DESCRIPTORS so we don't
+       // have to search images just to find the don't have TLVs.
+       for (uint32_t i=0; i < infoCount; ++i) {
+               if ( info[i].imageLoadAddress->flags & MH_HAS_TLV_DESCRIPTORS )
+                       tlv_initialize_descriptors(info[i].imageLoadAddress);
+       }
+       return NULL;
+}
+
+
+void dyld_register_tlv_state_change_handler(enum dyld_tlv_states state, dyld_tlv_state_change_handler handler)
+{
+       TLVHandler *h = malloc(sizeof(TLVHandler));
+       h->state = state;
+       h->handler = Block_copy(handler);
+
+       TLVHandler *old;
+       do {
+               old = tlv_handlers;
+               h->next = old;
+       } while (! OSAtomicCompareAndSwapPtrBarrier(old, h, (void * volatile *)&tlv_handlers));
+}
+
+
+void dyld_enumerate_tlv_storage(dyld_tlv_state_change_handler handler)
+{
+       pthread_mutex_lock(&tlv_live_image_lock);
+               unsigned int count = tlv_live_image_used_count;
+               void *list[count];
+               for (unsigned int i = 0; i < count; ++i) {
+                       list[i] = pthread_getspecific(tlv_live_images[i].key);
+               }
+       pthread_mutex_unlock(&tlv_live_image_lock);
+
+       for (unsigned int i = 0; i < count; ++i) {
+               if (list[i]) {
+                       dyld_tlv_info info = { sizeof(info), list[i], malloc_size(list[i]) };
+                       handler(dyld_tlv_state_allocated, &info);
+               }
+       }
+}
+
+
+//
+//  thread_local terminators
+//
+// C++ 0x allows thread_local C++ objects which have constructors run
+// on the thread before any use of the object and the object's destructor
+// is run on the thread when the thread terminates.
+//
+// To support this libdyld gets a pthread key early in process start up and
+// uses tlv_finalize and the key's destructor function.  This key must be
+// allocated before any thread local variables are instantiated because when
+// a thread is terminated, the pthread package runs the destructor function
+// on each key's storage values in key allocation order.  Since we want
+// C++ objects to be destructred before they are deallocated, we need the 
+// destructor key to come before the deallocation key.
+//
+
+typedef void (*TermFunc)(void*);
+struct TLVTerminatorListEntry
+{
+    TermFunc    termFunc;
+    void*       objAddr;
+};
+
+struct TLVTerminatorList
+{
+    uint32_t                        allocCount;
+    uint32_t                        useCount;
+    struct TLVTerminatorListEntry   entries[1];  // variable length
+};
+
+
+static pthread_key_t tlv_terminators_key = 0;
+
+void _tlv_atexit(TermFunc func, void* objAddr)
+{
+    // NOTE: this does not need locks because it only operates on current thread data
+       struct TLVTerminatorList* list = (struct TLVTerminatorList*)pthread_getspecific(tlv_terminators_key);
+    if ( list == NULL ) {
+        // handle first allocation
+        list = (struct TLVTerminatorList*)malloc(offsetof(struct TLVTerminatorList, entries[1]));
+        list->allocCount = 1;
+        list->useCount = 1;
+        list->entries[0].termFunc = func;
+        list->entries[0].objAddr = objAddr;
+        pthread_setspecific(tlv_terminators_key, list);
+    }
+    else {
+        if ( list->allocCount == list->allocCount ) {
+            // handle resizing allocation 
+            uint32_t newAllocCount = list->allocCount * 2;
+            uint32_t newAllocSize = offsetof(struct TLVTerminatorList, entries[newAllocCount]);
+            struct TLVTerminatorList* newlist = (struct TLVTerminatorList*)malloc(newAllocSize);
+            newlist->allocCount = newAllocCount;
+            newlist->useCount = list->useCount;
+            for(uint32_t i=0; i < list->useCount; ++i)
+                newlist->entries[i] = list->entries[i];
+            pthread_setspecific(tlv_terminators_key, newlist);
+            free(list);
+            list = newlist;
+        }
+        // handle appending new entry
+        list->entries[list->useCount].termFunc = func;
+        list->entries[list->useCount].objAddr = objAddr;
+        list->useCount += 1;
+    }
+}
+
+// called by pthreads when the current thread is going way 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];
+        if ( entry->termFunc != NULL ) {
+            (*entry->termFunc)(entry->objAddr);
+        }
+    }
+    free(storage);
+}
+
+
+__attribute__((visibility("hidden")))
+void tlv_initializer()
+{
+    // create pthread key to handle thread_local destructors
+    // NOTE: this key must be allocated before any keys for TLV
+    // so that _pthread_tsd_cleanup will run destructors before deallocation
+    (void)pthread_key_create(&tlv_terminators_key, &tlv_finalize);
+       
+    // register with dyld for notification when images are loaded
+    dyld_register_image_state_change_handler(dyld_image_state_bound, true, tlv_load_notification);
+}
+
+
+// linked images with TLV have references to this symbol, but it is never used at runtime
+void _tlv_bootstrap()
+{
+       abort();
+}
+
+
+// __i386__ || __x86_64__
+#else
+// !(__i386__ || __x86_64__)
+
+
+void dyld_register_tlv_state_change_handler(enum dyld_tlv_states state, dyld_tlv_state_change_handler handler)
+{
+}
+
+void dyld_enumerate_tlv_storage(dyld_tlv_state_change_handler handler)
+{
+}
+
+__attribute__((visibility("hidden")))
+void tlv_initializer()
+{
+}
+
+
+// !(__i386__ || __x86_64__)
+#endif
+
+
diff --git a/unit-tests/bin/build-results-filter.pl b/unit-tests/bin/build-results-filter.pl
new file mode 100755 (executable)
index 0000000..fa6d106
--- /dev/null
@@ -0,0 +1,114 @@
+#!/usr/bin/perl -w
+
+use strict;
+use Data::Dumper;
+use File::Find;
+use Cwd;
+
+$Data::Dumper::Terse = 1;
+
+my $root = undef;
+my $entry = '';
+my $pass_count = 0;
+my $total_count = 0;
+
+# first match "root: "
+
+# a line starting with "cwd:" marks the beginning of a new test case
+# call process_entry() on each test case
+while(<>)
+{
+    if(m/^root:\s+(.*?)$/)
+    {
+       $root = $1;
+    }
+    elsif(m/^cwd:\s+(.*?)$/)
+    {
+       if(length($entry))
+       {
+           &process_entry($root, $entry);
+           $entry = '';
+       }
+       $entry .= $_;
+    }
+    else
+    {
+       $entry .= $_;
+    }
+}
+# don't forget last test case (no cwd: to mark end)
+if(length($entry))
+{
+    &process_entry($root, $entry);
+}
+
+# show totals
+my $percentage = $pass_count * 100 / $total_count;
+printf " * * * %d of %d unit-tests passed (%.1f percent) * * *\n", $pass_count, $total_count, $percentage;
+
+
+sub process_entry
+{
+    my ($root, $lines) = @_;
+
+    # build an associative array of keys to value(s) 
+    my $lines_seq = [split /\n/, $lines];
+    #print Dumper($lines_seq);
+    my $tbl = { 'root' => $root, 'stdout' => [], 'stderr' => [] };
+    my $line;
+    foreach $line (@$lines_seq)
+    {
+       if($line =~ m/^(\w+):\s+(.*)$/)
+       {
+           my $key = $1;
+           my $val = $2;
+           if(!exists($$tbl{$key}))
+           { $$tbl{$key} = ''; }
+
+           if($key eq 'stdout' || $key eq 'stderr') # if type is @array
+           {
+               push @{$$tbl{$key}}, $val;
+           }
+           else
+           {
+               $$tbl{$key} .= $val;
+           }
+       }
+       else
+       {
+           print "ERROR: $line";
+       }
+    }
+    #print Dumper($tbl);
+    #return;
+
+    my $test_name = $$tbl{cwd};
+    if ($test_name =~ m|.*/([a-zA-Z0-9-+_]+)$|)
+    {
+       $test_name = $1;
+    }
+    
+    #if there was any output to stderr, mark this as a failure
+    my $some_errors = 0;
+    foreach $line (@{$$tbl{stderr}})
+    {
+       printf "%-40s FAIL spurious stderr failure: %s\n", $test_name, $line;
+       $total_count++;
+       $some_errors = 1;
+    }
+    if ( $some_errors )
+    {
+       return;
+    }
+    
+    #if make failed (exit was non-zero), mark this as a failure
+    if(0 ne $$tbl{exit})
+    {
+       printf "%-40s FAIL Makefile failure\n", $test_name;
+       $total_count++;
+       return;
+    }
+    
+    $pass_count++;
+    $total_count++;
+}
index f29a1bca6187c341086f7f37730cf607f1eb41ab..7a09a1b5361b8bffdb44c9652e97629d062b35f8 100755 (executable)
@@ -39,5 +39,6 @@ while(<OUT>)
        print $_;
 }
 close(OUT) || die("$!");
        print $_;
 }
 close(OUT) || die("$!");
+unlink "/tmp/exit-non-zero.tmp";
 exit 0;
 
 exit 0;
 
index 43de2a339aee46439e8fa522dd077b222f6e32af..bc0a99d857c26df85cd86c6639d9f93f11d870c1 100755 (executable)
@@ -38,5 +38,6 @@ while(<OUT>)
        print $_;
 }
 close(OUT) || die("$!");
        print $_;
 }
 close(OUT) || die("$!");
+unlink "/tmp/exit-zero-pass.tmp";
 exit 0;
 
 exit 0;
 
diff --git a/unit-tests/build-and-run-iPhoneOS-unit-tests b/unit-tests/build-and-run-iPhoneOS-unit-tests
new file mode 100755 (executable)
index 0000000..a572912
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+# need to be root to build test suite
+sudo ./build-iPhoneOS-unit-tests
+
+# transfer to device
+echo " * * * Transfering to device * * *"
+rsync -a /tmp/unpack-and-run-all-tests /tmp/dyld-testing.cpgz rsync://root@localhost:10873/root/tmp
+
+
+# running on device
+echo " * * * Running on device * * *"
+/Developer/Platforms/iPhoneOS.platform/usr/local/bin/PurpleExec /tmp/unpack-and-run-all-tests
+
diff --git a/unit-tests/build-iPhoneOS-unit-tests b/unit-tests/build-iPhoneOS-unit-tests
new file mode 100755 (executable)
index 0000000..21415cd
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/sh 
+
+# cd into test-cases directory
+TEST_CASE_DIR=`echo "$0" | sed 's/build-iPhoneOS-unit-tests/test-cases/'`
+cd ${TEST_CASE_DIR}
+TEST_CASE_DIR=`pwd`
+
+# make clean
+../bin/make-recursive.pl clean > /dev/null
+
+# clean staging area
+rm -rf /var/root/testing
+mkdir /var/root/testing
+
+# create scripts to run test cases on device
+echo "#!/bin/sh" > /var/root/testing/run-all-tests
+chmod +x /var/root/testing/run-all-tests
+
+# do every combination of OS version and architectures
+for os in "4.3" "3.0" 
+do
+       for arch in armv6 thumb armv7 thumb2
+       do
+               # make copy of tests
+               cp -r ${TEST_CASE_DIR}/../../unit-tests  /var/root/testing/unit-tests-${arch}-${os}
+               # build but don't run test cases
+               echo " * * * Building all unit tests for ${arch} iPhoneOS ${os} * * *"
+               cd /var/root/testing/unit-tests-${arch}-${os}/test-cases
+               ../bin/make-recursive.pl ARCH=${arch} OS_VERSION=${os} OS_NAME=iPhoneOS all | ../bin/build-results-filter.pl
+               # update script
+               echo "cd /var/root/testing/unit-tests-${arch}-${os}"                           >> /var/root/testing/run-all-tests
+               echo "echo \" * * * Running all unit tests for ${arch} iPhoneOS ${os} * * *\"" >> /var/root/testing/run-all-tests
+               echo "bin/make-recursive.pl OS_NAME=iPhoneOS check | bin/result-filter.pl"     >> /var/root/testing/run-all-tests
+       done
+done
+
+# tar up all test cases
+echo " * * * Making archive * * *"
+cd /var/root
+ditto -c -z testing /tmp/dyld-testing.cpgz
+
+# create script to unpack on device
+echo "#!/bin/sh" > /tmp/unpack-and-run-all-tests
+echo "echo \" * * * Unpacking test cases * * *\""                          >> /tmp/unpack-and-run-all-tests
+echo "/sbin/mount -u /private/var"                                         >> /tmp/unpack-and-run-all-tests
+echo "chmod +x /var/root"                                                  >> /tmp/unpack-and-run-all-tests
+echo "cd /var/root"                                                        >> /tmp/unpack-and-run-all-tests
+echo "rm -rf /var/root/testing"                                            >> /tmp/unpack-and-run-all-tests
+echo "ditto -x /tmp/dyld-testing.cpgz testing"                             >> /tmp/unpack-and-run-all-tests
+echo "/var/root/testing/run-all-tests"                                     >> /tmp/unpack-and-run-all-tests
+chmod +x /tmp/unpack-and-run-all-tests
+
index f94abba7dca7e28b2971aa2f0d9049d119cb7e43..461ebb0f2602c95d504660588e6c1e2e4ccd703e 100644 (file)
@@ -2,21 +2,66 @@
 
 SHELL = /bin/sh
 
 
 SHELL = /bin/sh
 
-# set default to be host
-ARCH ?= $(shell arch)
+# set default OS to be current Mac OS X 
+OS_NAME ?= MacOSX
+ifeq "$(OS_NAME)" "iPhoneOS"
+       OS_VERSION ?= 3.1
+       ifeq "$(OS_VERSION)" "4.3"
+               OS_BAROLO_FEATURES = 1
+       endif
+       ARCH ?= armv6
+       VALID_ARCHS ?= armv6
+else
+       OS_VERSION ?= 10.7
+       ifeq "$(OS_VERSION)" "10.7"
+               OS_BAROLO_FEATURES = 1
+       endif
+       ARCH ?= $(shell arch)
+       VALID_ARCHS ?= "i386 x86_64"
+endif
 
 
-# set default to be all
-VALID_ARCHS ?= "ppc i386 x86_64"
+ifeq "$(OS_NAME)" "iPhoneOS"
+       CC                      = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc-4.2 -arch ${ARCH} -miphoneos-version-min=$(OS_VERSION) -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.Internal.sdk
+       CXX                     = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/g++-4.2 -arch ${ARCH} -miphoneos-version-min=$(OS_VERSION) -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.Internal.sdk
+#      CC                      = gcc-4.2 -arch ${ARCH} -miphoneos-version-min=$(OS_VERSION)
+#      CXX                     = g++-4.2 -arch ${ARCH} -miphoneos-version-min=$(OS_VERSION)
+else
+       CC                      = gcc-4.2 -arch ${ARCH} -mmacosx-version-min=$(OS_VERSION)
+       CXX                     = g++-4.2 -arch ${ARCH} -mmacosx-version-min=$(OS_VERSION)
+endif
 
 
-CC              = gcc-4.2 -arch ${ARCH}
-CCFLAGS = -Wall -std=c99
-
-CXX              = g++-4.2 -arch ${ARCH}
-CXXFLAGS = -Wall 
+CCFLAGS                = -Wall -std=c99
+CXXFLAGS       = -Wall 
 
 RM      = rm
 RMFLAGS = -rf
 
 SAFE_RUN       = ${TESTROOT}/bin/fail-if-non-zero.pl
 PASS_IFF       = ${TESTROOT}/bin/pass-iff-exit-zero.pl
 
 RM      = rm
 RMFLAGS = -rf
 
 SAFE_RUN       = ${TESTROOT}/bin/fail-if-non-zero.pl
 PASS_IFF       = ${TESTROOT}/bin/pass-iff-exit-zero.pl
+PASS_IFF_FAILURE = $(TESTROOT)/bin/exit-non-zero-pass.pl
+
+ifeq ($(ARCH),armv7)
+  CCFLAGS += -mno-thumb
+  CXXFLAGS += -mno-thumb
+  override FILEARCH = arm
+else
+  FILEARCH = $(ARCH)
+endif
+
+ifeq ($(ARCH),thumb)
+  CCFLAGS += -mthumb
+  CXXFLAGS += -mthumb
+  override ARCH = armv6
+  override FILEARCH = arm
+else
+  FILEARCH = $(ARCH)
+endif
 
 
+ifeq ($(ARCH),thumb2)
+  CCFLAGS += -mthumb
+  CXXFLAGS += -mthumb
+  override ARCH = armv7
+  override FILEARCH = arm
+else
+  FILEARCH = $(ARCH)
+endif
index 45f846fb8467e5061aac52ee8dbac5e961e776c5..91659ba8c6b82369bc42497441a1eefd17036ff9 100755 (executable)
@@ -7,57 +7,32 @@ cd `echo "$0" | sed 's/run-all-unit-tests/test-cases/'`
 CRSTATE=`defaults read com.apple.CrashReporter DialogType`
 defaults write com.apple.CrashReporter DialogType basic
 
 CRSTATE=`defaults read com.apple.CrashReporter DialogType`
 defaults write com.apple.CrashReporter DialogType basic
 
-echo ""
-echo " * * * Running all unit tests for 32-bits * * *"
-
-# make clean
-../bin/make-recursive.pl clean > /dev/null
-
-# build default architecture
-../bin/make-recursive.pl | ../bin/result-filter.pl
-
-# if G5, then also run all test cases built for ppc64
-if [ `machine` = "ppc970" ] 
-then
+# run test targeting different OS versions
+for OSVERSION in 10.7 10.6 10.5 10.4
+do 
        echo ""
        echo ""
-       echo " * * * Running all unit tests for 64-bits * * *"
-       
+       echo " * * * Running all unit tests i386 built for $OSVERSION * * *"
+
        # make clean
        ../bin/make-recursive.pl clean > /dev/null
 
        # make clean
        ../bin/make-recursive.pl clean > /dev/null
 
-       # build 64-bit architecture
-       ../bin/make-recursive.pl ARCH="ppc64" | ../bin/result-filter.pl
-fi
-
-# if Intel, then also run all test cases under emulation
-if [ "`sysctl -n hw.machine`" = "i386" ] 
-then
-
-       if [ -x /usr/libexec/oah/translate ] 
-       then
-               echo ""
-               echo " * * * Running all unit tests for emulated 32-bits * * *"
-               
-               # make clean
-               ../bin/make-recursive.pl clean > /dev/null
-
-               # build ppc architecture
-               ../bin/make-recursive.pl ARCH="ppc" | ../bin/result-filter.pl
-       fi
+       # build default architecture
+       ../bin/make-recursive.pl ARCH="i386" OS_VERSION=$OSVERSION OS_NAME=MacOSX | ../bin/result-filter.pl
 
        # if 64-bit capable Intel, then also run all test cases for 64-bits
        if [ `sysctl -n hw.optional.x86_64` = "1" ] 
        then
                echo ""
 
        # if 64-bit capable Intel, then also run all test cases for 64-bits
        if [ `sysctl -n hw.optional.x86_64` = "1" ] 
        then
                echo ""
-               echo " * * * Running all unit tests for 64-bits * * *"
+               echo " * * * Running all unit tests x86_64 built for $OSVERSION * * *"
                
                # make clean
                ../bin/make-recursive.pl clean > /dev/null
 
                # build x86_64 architecture
                
                # make clean
                ../bin/make-recursive.pl clean > /dev/null
 
                # build x86_64 architecture
-               ../bin/make-recursive.pl ARCH="x86_64" | ../bin/result-filter.pl
+               ../bin/make-recursive.pl ARCH="x86_64" OS_VERSION=$OSVERSION OS_NAME=MacOSX | ../bin/result-filter.pl
        fi
        fi
-fi
+
+done
 
 # restore crash reporter state
 defaults write com.apple.CrashReporter DialogType ${CRSTATE}
 
 # restore crash reporter state
 defaults write com.apple.CrashReporter DialogType ${CRSTATE}
diff --git a/unit-tests/test-cases/DYLD_LIBRARY_PATH-dyld_env/Makefile b/unit-tests/test-cases/DYLD_LIBRARY_PATH-dyld_env/Makefile
new file mode 100644 (file)
index 0000000..44befa7
--- /dev/null
@@ -0,0 +1,61 @@
+##
+# 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
+
+PWD = $(shell pwd)
+
+all-check: all check
+
+check:
+       ./main10 10
+       ./main11 11
+       ./main911 9
+       ./main911b 9
+       ./main1112 11
+       ./main1112b 11
+       ./main1211 12
+       ./main1211b 12
+       export DYLD_LIBRARY_PATH=${PWD}/alt11 && ./main10 11
+       export DYLD_LIBRARY_PATH=${PWD}/alt9 && ./main11 9
+       export DYLD_LIBRARY_PATH=${PWD}/alt20 && ./main11 11
+
+all: 
+       mkdir -p alt11 alt9 alt12
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -DRESULT=10 -current_version 10 -o "${PWD}/libfoo.dylib"
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -DRESULT=11 -current_version 11 -install_name "${PWD}/libfoo.dylib" -o alt11/libfoo.dylib  
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -DRESULT=9  -current_version 9  -install_name "${PWD}/libfoo.dylib" -o alt9/libfoo.dylib  
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -DRESULT=12 -current_version 12 -install_name "${PWD}/libfoo.dylib" -o alt12/libfoo.dylib  
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main10 main.c libfoo.dylib 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main11 main.c libfoo.dylib -Wl,-dyld_env,DYLD_LIBRARY_PATH=@loader_path/alt11
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main911 main.c libfoo.dylib -Wl,-dyld_env,DYLD_LIBRARY_PATH=@loader_path/alt9 -Wl,-dyld_env,DYLD_LIBRARY_PATH=@loader_path/alt11
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main911b main.c libfoo.dylib -Wl,-dyld_env,DYLD_LIBRARY_PATH=@loader_path/alt9:@loader_path/alt11
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main1112 main.c libfoo.dylib -Wl,-dyld_env,DYLD_LIBRARY_PATH=@loader_path/alt11 -Wl,-dyld_env,DYLD_LIBRARY_PATH=@loader_path/alt12
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main1112b main.c libfoo.dylib -Wl,-dyld_env,DYLD_LIBRARY_PATH=@loader_path/alt11:@loader_path/alt12
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main1211 main.c libfoo.dylib -Wl,-dyld_env,DYLD_LIBRARY_PATH=@loader_path/alt12 -Wl,-dyld_env,DYLD_LIBRARY_PATH=@loader_path/alt11
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main1211b main.c libfoo.dylib -Wl,-dyld_env,DYLD_LIBRARY_PATH=@loader_path/alt12:@loader_path/alt11
+
+
+clean:
+       ${RM} -rf libfoo.dylib alt9 alt11 alt12 main10 main11 main9 main911 main911b main1112 main1112b main1211 main1211b
+
diff --git a/unit-tests/test-cases/DYLD_LIBRARY_PATH-dyld_env/foo.c b/unit-tests/test-cases/DYLD_LIBRARY_PATH-dyld_env/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/DYLD_LIBRARY_PATH-dyld_env/main.c b/unit-tests/test-cases/DYLD_LIBRARY_PATH-dyld_env/main.c
new file mode 100644 (file)
index 0000000..a903b04
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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 <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("DYLD_VERSIONED_LIBRARY_PATH-basic using wrong dylib. foo() returned %d, expected %d", actualResult, expectedResult);
+       else
+               PASS("DYLD_VERSIONED_LIBRARY_PATH-basic");
+               
+       return EXIT_SUCCESS;
+}
+
diff --git a/unit-tests/test-cases/DYLD_VERSIONED_FRAMEWORK_PATH-basic/Makefile b/unit-tests/test-cases/DYLD_VERSIONED_FRAMEWORK_PATH-basic/Makefile
new file mode 100644 (file)
index 0000000..36bf14e
--- /dev/null
@@ -0,0 +1,48 @@
+##
+# 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
+
+PWD = $(shell pwd)
+
+all-check: all check
+
+check:
+       ./main 10
+       export DYLD_VERSIONED_FRAMEWORK_PATH="${PWD}/alt11" && ./main 11
+       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
+       ${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=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  
+
+
+clean:
+       ${RM} -rf main Foo.framework alt9 alt11 alt12
+
diff --git a/unit-tests/test-cases/DYLD_VERSIONED_FRAMEWORK_PATH-basic/foo.c b/unit-tests/test-cases/DYLD_VERSIONED_FRAMEWORK_PATH-basic/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/DYLD_VERSIONED_FRAMEWORK_PATH-basic/main.c b/unit-tests/test-cases/DYLD_VERSIONED_FRAMEWORK_PATH-basic/main.c
new file mode 100644 (file)
index 0000000..a903b04
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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 <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("DYLD_VERSIONED_LIBRARY_PATH-basic using wrong dylib. foo() returned %d, expected %d", actualResult, expectedResult);
+       else
+               PASS("DYLD_VERSIONED_LIBRARY_PATH-basic");
+               
+       return EXIT_SUCCESS;
+}
+
diff --git a/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-basic/Makefile b/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-basic/Makefile
new file mode 100644 (file)
index 0000000..2be1439
--- /dev/null
@@ -0,0 +1,48 @@
+##
+# 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
+
+PWD = $(shell pwd)
+
+all-check: all check
+
+check:
+       ./main 10
+       export DYLD_VERSIONED_LIBRARY_PATH="${PWD}/alt11" && ./main 11
+       export DYLD_VERSIONED_LIBRARY_PATH="${PWD}/alt9" && ./main 10
+       export DYLD_VERSIONED_LIBRARY_PATH="${PWD}/alt9:${PWD}/alt11" && ./main 11
+       export DYLD_VERSIONED_LIBRARY_PATH="${PWD}/alt11:${PWD}/alt12" && ./main 12
+
+all: 
+       mkdir -p alt11 alt9 alt12
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -DRESULT=10 -current_version 10 -o "${PWD}/libfoo.dylib"
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libfoo.dylib 
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -DRESULT=11 -current_version 11 -install_name "${PWD}/libfoo.dylib" -o alt11/libfoo.dylib  
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -DRESULT=9  -current_version 9  -install_name "${PWD}/libfoo.dylib" -o alt9/libfoo.dylib  
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -DRESULT=12 -current_version 12 -install_name "${PWD}/libfoo.dylib" -o alt12/libfoo.dylib  
+
+
+clean:
+       ${RM} -rf main libfoo.dylib alt9 alt11 alt12
+
diff --git a/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-basic/foo.c b/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-basic/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/DYLD_VERSIONED_LIBRARY_PATH-basic/main.c b/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-basic/main.c
new file mode 100644 (file)
index 0000000..a903b04
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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 <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("DYLD_VERSIONED_LIBRARY_PATH-basic using wrong dylib. foo() returned %d, expected %d", actualResult, expectedResult);
+       else
+               PASS("DYLD_VERSIONED_LIBRARY_PATH-basic");
+               
+       return EXIT_SUCCESS;
+}
+
diff --git a/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env-restrict/Makefile b/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env-restrict/Makefile
new file mode 100644 (file)
index 0000000..eeaef6e
--- /dev/null
@@ -0,0 +1,58 @@
+##
+# 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
+
+PWD = $(shell pwd)
+
+all-check: all check
+
+check:
+       ./main10 10
+       ./main11 11
+       ./main911 11
+       ./main911b 11
+       ./main1112 12
+       ./main1112b 12
+       ./main1211 12
+       ./main1211b 12
+
+all: 
+       mkdir -p alt11 alt9 alt12
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -DRESULT=10 -current_version 10 -o "${PWD}/libfoo.dylib"
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -DRESULT=11 -current_version 11 -install_name "${PWD}/libfoo.dylib" -o alt11/libfoo.dylib  
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -DRESULT=9  -current_version 9  -install_name "${PWD}/libfoo.dylib" -o alt9/libfoo.dylib  
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -DRESULT=12 -current_version 12 -install_name "${PWD}/libfoo.dylib" -o alt12/libfoo.dylib  
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main10 main.c libfoo.dylib -Wl,-sectcreate,__RESTRICT,__restrict,/dev/null
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main11 main.c libfoo.dylib -Wl,-sectcreate,__RESTRICT,__restrict,/dev/null -Wl,-dyld_env,DYLD_VERSIONED_LIBRARY_PATH=@loader_path/alt11
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main911 main.c libfoo.dylib -Wl,-sectcreate,__RESTRICT,__restrict,/dev/null -Wl,-dyld_env,DYLD_VERSIONED_LIBRARY_PATH=@loader_path/alt9 -Wl,-dyld_env,DYLD_VERSIONED_LIBRARY_PATH=@loader_path/alt11
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main911b main.c libfoo.dylib -Wl,-sectcreate,__RESTRICT,__restrict,/dev/null -Wl,-dyld_env,DYLD_VERSIONED_LIBRARY_PATH=@loader_path/alt9:@loader_path/alt11
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main1112 main.c libfoo.dylib -Wl,-sectcreate,__RESTRICT,__restrict,/dev/null -Wl,-dyld_env,DYLD_VERSIONED_LIBRARY_PATH=@loader_path/alt11 -Wl,-dyld_env,DYLD_VERSIONED_LIBRARY_PATH=@loader_path/alt12
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main1112b main.c libfoo.dylib -Wl,-sectcreate,__RESTRICT,__restrict,/dev/null -Wl,-dyld_env,DYLD_VERSIONED_LIBRARY_PATH=@loader_path/alt11:@loader_path/alt12
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main1211 main.c libfoo.dylib -Wl,-sectcreate,__RESTRICT,__restrict,/dev/null -Wl,-dyld_env,DYLD_VERSIONED_LIBRARY_PATH=@loader_path/alt12 -Wl,-dyld_env,DYLD_VERSIONED_LIBRARY_PATH=@loader_path/alt11
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main1211b main.c libfoo.dylib -Wl,-sectcreate,__RESTRICT,__restrict,/dev/null -Wl,-dyld_env,DYLD_VERSIONED_LIBRARY_PATH=@loader_path/alt12:@loader_path/alt11
+
+
+clean:
+       ${RM} -rf libfoo.dylib alt9 alt11 alt12 main10 main11 main9 main911 main911b main1112 main1112b main1211 main1211b
+
diff --git a/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env-restrict/foo.c b/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env-restrict/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/DYLD_VERSIONED_LIBRARY_PATH-dyld_env-restrict/main.c b/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env-restrict/main.c
new file mode 100644 (file)
index 0000000..a903b04
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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 <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("DYLD_VERSIONED_LIBRARY_PATH-basic using wrong dylib. foo() returned %d, expected %d", actualResult, expectedResult);
+       else
+               PASS("DYLD_VERSIONED_LIBRARY_PATH-basic");
+               
+       return EXIT_SUCCESS;
+}
+
diff --git a/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env/Makefile b/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env/Makefile
new file mode 100644 (file)
index 0000000..357a34e
--- /dev/null
@@ -0,0 +1,61 @@
+##
+# 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
+
+PWD = $(shell pwd)
+
+all-check: all check
+
+check:
+       ./main10 10
+       ./main11 11
+       ./main911 11
+       ./main911b 11
+       ./main911c 11
+       ./main1112 12
+       ./main1112b 12
+       ./main1211 12
+       ./main1211b 12
+       export DYLD_LIBRARY_PATH=./alt9 && ./main11 9
+
+all: 
+       mkdir -p alt11 alt9 alt12
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -DRESULT=10 -current_version 10 -o "${PWD}/libfoo.dylib"
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -DRESULT=11 -current_version 11 -install_name "${PWD}/libfoo.dylib" -o alt11/libfoo.dylib  
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -DRESULT=9  -current_version 9  -install_name "${PWD}/libfoo.dylib" -o alt9/libfoo.dylib  
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -DRESULT=12 -current_version 12 -install_name "${PWD}/libfoo.dylib" -o alt12/libfoo.dylib  
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main10 main.c libfoo.dylib 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main11 main.c libfoo.dylib -Wl,-dyld_env,DYLD_VERSIONED_LIBRARY_PATH=@loader_path/alt11
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main911 main.c libfoo.dylib -Wl,-dyld_env,DYLD_VERSIONED_LIBRARY_PATH=@loader_path/alt9 -Wl,-dyld_env,DYLD_VERSIONED_LIBRARY_PATH=@loader_path/alt11
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main911b main.c libfoo.dylib -Wl,-dyld_env,DYLD_VERSIONED_LIBRARY_PATH=@loader_path/alt9:@loader_path/alt11
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main911c main.c libfoo.dylib -Wl,-dyld_env,DYLD_VERSIONED_LIBRARY_PATH=@executable_path/alt9:@executable_path/alt11
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main1112 main.c libfoo.dylib -Wl,-dyld_env,DYLD_VERSIONED_LIBRARY_PATH=@loader_path/alt11 -Wl,-dyld_env,DYLD_VERSIONED_LIBRARY_PATH=@loader_path/alt12
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main1112b main.c libfoo.dylib -Wl,-dyld_env,DYLD_VERSIONED_LIBRARY_PATH=@loader_path/alt11:@loader_path/alt12
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main1211 main.c libfoo.dylib -Wl,-dyld_env,DYLD_VERSIONED_LIBRARY_PATH=@loader_path/alt12 -Wl,-dyld_env,DYLD_VERSIONED_LIBRARY_PATH=@loader_path/alt11
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main1211b main.c libfoo.dylib -Wl,-dyld_env,DYLD_VERSIONED_LIBRARY_PATH=@loader_path/alt12:@loader_path/alt11
+
+
+clean:
+       ${RM} -rf libfoo.dylib alt9 alt11 alt12 main10 main11 main9 main911 main911b main911c main1112 main1112b main1211 main1211b
+
diff --git a/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env/foo.c b/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env/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/DYLD_VERSIONED_LIBRARY_PATH-dyld_env/main.c b/unit-tests/test-cases/DYLD_VERSIONED_LIBRARY_PATH-dyld_env/main.c
new file mode 100644 (file)
index 0000000..a903b04
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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 <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("DYLD_VERSIONED_LIBRARY_PATH-basic using wrong dylib. foo() returned %d, expected %d", actualResult, expectedResult);
+       else
+               PASS("DYLD_VERSIONED_LIBRARY_PATH-basic");
+               
+       return EXIT_SUCCESS;
+}
+
index 9442bf1e7596865f82dd31b3d014f66974bbd9b8..bcb2bea3a2dbd736ff0f7043618725ea23afda9b 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <stdio.h>
 #include <stdlib.h>
 #include <mach-o/dyld.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <mach-o/dyld.h>
-
+#include <Availability.h>
 #include "test.h"
 
 /// rdar://problem/4058724
 
 int main()
 {
 #include "test.h"
 
 /// rdar://problem/4058724
 
 int main()
 {
+// NSAddImage is only available on Mac OS X - not iPhone OS
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        // test that image can be found via install path
        const struct mach_header * mh1 = NSAddImage("libbar.dylib", NSADDIMAGE_OPTION_RETURN_ON_ERROR | NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME);
        const struct mach_header * mh2 = NSAddImage("libfoo.dylib", NSADDIMAGE_OPTION_RETURN_ON_ERROR | NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME);
        // test that image can be found via install path
        const struct mach_header * mh1 = NSAddImage("libbar.dylib", NSADDIMAGE_OPTION_RETURN_ON_ERROR | NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME);
        const struct mach_header * mh2 = NSAddImage("libfoo.dylib", NSADDIMAGE_OPTION_RETURN_ON_ERROR | NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME);
-       if ( mh2 != NULL )
-               PASS("NSAddImage-MATCH_BY_INSTALLNAME");
-       else
+       if ( mh2 == NULL )
                FAIL("NSAddImage-MATCH_BY_INSTALLNAME");
                FAIL("NSAddImage-MATCH_BY_INSTALLNAME");
+       else
+#endif
+               PASS("NSAddImage-MATCH_BY_INSTALLNAME");
        return EXIT_SUCCESS;
 }
        return EXIT_SUCCESS;
 }
index e8a33207c35863f4c8f636f1aea553d38a026ced..3f84ea14d22043d774635ac9722197a3eb561a49 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <mach-o/dyld.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <mach-o/dyld.h>
+#include <Availability.h>
 
 #include "test.h"
 
 
 #include "test.h"
 
 
 int main()
 {
 
 int main()
 {
+// NSAddImage is only available on Mac OS X - not iPhone OS
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        // test that NSAddImage() does not crash if image is not loaded
        const struct mach_header * mh = NSAddImage("/System/Library/Frameworks/Cocoa.framework/Cocoa", NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED);
        // test that NSAddImage() does not crash if image is not loaded
        const struct mach_header * mh = NSAddImage("/System/Library/Frameworks/Cocoa.framework/Cocoa", NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED);
-       if ( mh == NULL )
-               PASS("NSAddImage-RETURN_ONLY_IF_LOADED");
-       else
+       if ( mh != NULL )
                FAIL("NSAddImage-RETURN_ONLY_IF_LOADED");
                FAIL("NSAddImage-RETURN_ONLY_IF_LOADED");
+       else
+#endif
+               PASS("NSAddImage-RETURN_ONLY_IF_LOADED");
        return EXIT_SUCCESS;
 }
        return EXIT_SUCCESS;
 }
index 28922aff37bb2522ea066230e6f4990f55c7232e..f1ad6308dff0b4a41564cbe7a34edfe4b8438608 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <mach-o/dyld.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <mach-o/dyld.h>
+#include <Availability.h>
 
 #include "test.h"
 
 
 #include "test.h"
 
 
 int main()
 {
 
 int main()
 {
+// NSAddImage is only available on Mac OS X - not iPhone OS
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        // test that NSAddImage() uses fallback path when given a leaf name
        const struct mach_header * mh = NSAddImage("libzzz.dylib", NSADDIMAGE_OPTION_WITH_SEARCHING);
        // test that NSAddImage() uses fallback path when given a leaf name
        const struct mach_header * mh = NSAddImage("libzzz.dylib", NSADDIMAGE_OPTION_WITH_SEARCHING);
-       if ( mh != NULL )
-               PASS("NSAddImage-leafname");
-       else
+       if ( mh == NULL )
                FAIL("NSAddImage-leafname");
                FAIL("NSAddImage-leafname");
+       else
+#endif
+               PASS("NSAddImage-leafname");
        return EXIT_SUCCESS;
 }
        return EXIT_SUCCESS;
 }
index 9ac5211262d822841362f936c6566d8332d9de9f..09fea733572622092e6eb2a4fc9e6baccde52ff3 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2008-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -23,6 +23,7 @@
 #include <stdio.h>  // fprintf(), NULL
 #include <stdlib.h> // exit(), EXIT_SUCCESS
 #include <string.h>
 #include <stdio.h>  // fprintf(), NULL
 #include <stdlib.h> // exit(), EXIT_SUCCESS
 #include <string.h>
+#include <Availability.h>
 
 #include <mach-o/dyld.h>
 
 
 #include <mach-o/dyld.h>
 
 
 int main()
 {
 
 int main()
 {
+// NSAddressOfSymbol is only available on Mac OS X - not iPhone OS
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        NSAddressOfSymbol(NULL);
        NSAddressOfSymbol(NULL);
+#endif
        
        PASS("NSAddressOfSymbol-NULL");
        return 0;
        
        PASS("NSAddressOfSymbol-NULL");
        return 0;
index fd8099beb933776e02879a425284eab8bb0d9273..006adaa4e6fd94610d157bb4317dd643028dae6f 100644 (file)
@@ -57,4 +57,5 @@ int main()
        }
        
        PASS("addend");
        }
        
        PASS("addend");
+       return 0;
 }
 }
diff --git a/unit-tests/test-cases/all_image_infos-cache-slide/Makefile b/unit-tests/test-cases/all_image_infos-cache-slide/Makefile
new file mode 100644 (file)
index 0000000..0babb7e
--- /dev/null
@@ -0,0 +1,37 @@
+##
+# 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
+
+all-check: all check
+
+check:
+       ./main 
+
+all: 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main 
+
diff --git a/unit-tests/test-cases/all_image_infos-cache-slide/main.c b/unit-tests/test-cases/all_image_infos-cache-slide/main.c
new file mode 100644 (file)
index 0000000..0a550e4
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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 <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <dlfcn.h>
+#include <mach-o/dyld.h>
+#include <mach-o/dyld_images.h>
+#include <mach/mach.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+static uintptr_t libSystemSlide()
+{
+       Dl_info info;
+       if ( dladdr(&malloc, &info) == 0 ) {
+               FAIL("all_image_infos-cache-slide: dladdr(&malloc, xx) failed");
+               exit(0);
+       }
+       
+       const struct mach_header* mallocMh = (struct mach_header*)info.dli_fbase;
+       if ( (mallocMh->flags & 0x80000000) == 0 ) {
+               FAIL("all_image_infos-cache-slide: image containing _malloc not in shared cache");
+               exit(0);
+       }
+       
+       int count = _dyld_image_count();
+       for(int i=0; i < count; ++i) {
+               if ( mallocMh == _dyld_get_image_header(i) ) {
+                       return _dyld_get_image_vmaddr_slide(i);
+               }
+       }
+
+       FAIL("all_image_infos-cache-slide: slide of image containing _malloc not found");
+       exit(0);
+}
+
+
+int main(int argc, const char* argv[])
+{
+       task_dyld_info_data_t task_dyld_info;
+       mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
+    
+    if ( task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&task_dyld_info, &count) ) {
+               FAIL("all_image_infos-cache-slide: task_info() failed");
+               return 0;
+       }
+       struct dyld_all_image_infos* infos = (struct dyld_all_image_infos*)(uintptr_t)task_dyld_info.all_image_info_addr;
+       
+       if ( infos->version < 12 ) {
+               FAIL("all_image_infos-cache-slide: version < 12");
+               return 0;
+       }
+
+       if ( libSystemSlide() != infos->sharedCacheSlide ) {
+               FAIL("all_image_infos-cache-slide: dyld infos sharedCacheSlide (0x%08X) does not match computed slide (0x%08X)",
+                               infos->sharedCacheSlide, libSystemSlide());
+               return 0;
+       }
+
+       PASS("all_image_infos-cache-slide");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/all_image_infos-duplicate/Makefile b/unit-tests/test-cases/all_image_infos-duplicate/Makefile
new file mode 100644 (file)
index 0000000..b0f89b7
--- /dev/null
@@ -0,0 +1,38 @@
+##
+# 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
+
+all-check: all check
+
+check:
+       ./main 
+
+all: 
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -install_name /usr/local/lib/libfoo.dylib
+       cp libfoo.dylib libfoodup.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c 
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libfoo.dylib libfoodup.dylib
diff --git a/unit-tests/test-cases/all_image_infos-duplicate/foo.c b/unit-tests/test-cases/all_image_infos-duplicate/foo.c
new file mode 100644 (file)
index 0000000..81f7dcf
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+int foo()
+{
+       return 10;
+}
diff --git a/unit-tests/test-cases/all_image_infos-duplicate/main.c b/unit-tests/test-cases/all_image_infos-duplicate/main.c
new file mode 100644 (file)
index 0000000..b70ac9c
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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 <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <dlfcn.h>
+#include <mach-o/dyld.h>
+#include <mach-o/dyld_images.h>
+#include <mach/mach.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+struct dyld_all_image_infos* getImageInfosFromKernel()
+{
+       task_dyld_info_data_t task_dyld_info;
+       mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
+    
+    if ( task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&task_dyld_info, &count) ) {
+               FAIL("all_image_infos: task_info() failed");
+               exit(0);
+       }
+       return (struct dyld_all_image_infos*)(uintptr_t)task_dyld_info.all_image_info_addr;
+}
+
+
+int main(int argc, const char* argv[])
+{
+       void* handle = dlopen("libfoo.dylib", RTLD_LAZY);
+       if ( handle == NULL ) {
+               FAIL("dlopen(\"%s\") failed with: %s", "libfoo.dylib", dlerror());
+               exit(0);
+       }
+       
+       void* handle2 = dlopen("libfoodup.dylib", RTLD_LAZY);
+       if ( handle2 == NULL ) {
+               FAIL("dlopen(\"%s\") failed with: %s", "libfoodup.dylib", dlerror());
+               exit(0);
+       }
+       
+       struct dyld_all_image_infos* infos = getImageInfosFromKernel();
+       for( int i=0; i < infos->infoArrayCount; ++i) {
+               //fprintf(stderr, "[%d] %s\n", i , infos->infoArray[i].imageFilePath);
+               if ( strlen(infos->infoArray[i].imageFilePath) < 5 ) {
+                       FAIL("all_image_infos-duplicates: bad entry for address 0x%08X", infos->infoArray[i].imageLoadAddress);
+                       return EXIT_SUCCESS;
+               }
+       }
+
+       PASS("all_image_infos-duplicates");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/all_image_infos-paths/Makefile b/unit-tests/test-cases/all_image_infos-paths/Makefile
new file mode 100644 (file)
index 0000000..e384ae6
--- /dev/null
@@ -0,0 +1,40 @@
+##
+# 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
+
+all-check: all check
+
+check:
+       ./main `pwd`/test.bundle
+       ./main `pwd`/test.dylib
+
+all: 
+       ${CC} ${CCFLAGS} -bundle foo.c -o test.bundle
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o test.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main test.bundle test.dylib
+
diff --git a/unit-tests/test-cases/all_image_infos-paths/foo.c b/unit-tests/test-cases/all_image_infos-paths/foo.c
new file mode 100644 (file)
index 0000000..81f7dcf
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+int foo()
+{
+       return 10;
+}
diff --git a/unit-tests/test-cases/all_image_infos-paths/main.c b/unit-tests/test-cases/all_image_infos-paths/main.c
new file mode 100644 (file)
index 0000000..7e38b8c
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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 <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <dlfcn.h>
+#include <mach-o/dyld.h>
+#include <mach-o/dyld_images.h>
+#include <mach/mach.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+struct dyld_all_image_infos* getImageInfosFromKernel()
+{
+       task_dyld_info_data_t task_dyld_info;
+       mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
+    
+    if ( task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&task_dyld_info, &count) ) {
+               FAIL("all_image_infos: task_info() failed");
+               exit(0);
+       }
+       return (struct dyld_all_image_infos*)(uintptr_t)task_dyld_info.all_image_info_addr;
+}
+
+
+int main(int argc, const char* argv[])
+{
+       char path[1024];
+       strcpy(path, argv[1]);
+       
+       void* handle = dlopen(path, RTLD_LAZY);
+       if ( handle == NULL ) {
+               FAIL("dlopen(\"%s\") failed with: %s", path, dlerror());
+               exit(0);
+       }
+       strcpy(path, "bad");
+       
+       struct dyld_all_image_infos* infos = getImageInfosFromKernel();
+       for( int i=0; i < infos->infoArrayCount; ++i) {
+               //fprintf(stderr, "[%d] %s\n", i , infos->infoArray[i].imageFilePath);
+               if ( strcmp(infos->infoArray[i].imageFilePath, argv[1]) == 0 ) {
+                       PASS("all_image_infos-path");
+                       return EXIT_SUCCESS;
+               }
+       }
+
+       FAIL("all_image_infos-path");
+       return EXIT_SUCCESS;
+}
index 30a84275bcfbe9274f1d5c2ae339fd1b6dabec32..efff2b8930e88053fc5d88a5fedaedd7ea768526 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2008-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <mach-o/dyld.h>
 #include <mach-o/dyld_images.h>
 #include <mach/mach.h>
 #include <mach-o/dyld.h>
 #include <mach-o/dyld_images.h>
 #include <mach/mach.h>
+#include <Availability.h>
 
 #include "test.h"
 
 extern struct mach_header __dso_handle;
 
 
 #include "test.h"
 
 extern struct mach_header __dso_handle;
 
-#ifndef DYLD_ALL_IMAGE_INFOS_OFFSET_OFFSET
-       #define DYLD_ALL_IMAGE_INFOS_OFFSET_OFFSET 0x1010
-#endif
-
-
-#if __i386__ || __ppc__
-       #define DYLD_BASE_ADDRESS 0x8fe00000
-#elif __x86_64__ || __ppc64__
-       #define DYLD_BASE_ADDRESS 0x7fff5fc00000
-#elif __arm__
-       #define DYLD_BASE_ADDRESS 0x2fe00000
-#endif
-
-struct dyld_all_image_infos* getImageInfos()
-{
-       uint32_t offset = *((uint32_t*)(DYLD_BASE_ADDRESS+DYLD_ALL_IMAGE_INFOS_OFFSET_OFFSET));
-       if ( offset > 300000 ) {
-               FAIL("all_image_infos: offset appears to be outside dyld");
-               exit(0);
-       }
-       uintptr_t addr = DYLD_BASE_ADDRESS + offset;
-       return (struct dyld_all_image_infos*)addr;
-}
-
 
 struct dyld_all_image_infos* getImageInfosFromKernel()
 {
 
 struct dyld_all_image_infos* getImageInfosFromKernel()
 {
@@ -71,9 +48,9 @@ struct dyld_all_image_infos* getImageInfosFromKernel()
 int
 main()
 {
 int
 main()
 {
-       struct dyld_all_image_infos* infos = getImageInfos();
-       if ( infos->version != 7 ) {
-               FAIL("all_image_infos: dyld_all_image_infos is not version 7");
+       struct dyld_all_image_infos* infos = getImageInfosFromKernel();
+       if ( infos->version < 9 ) {
+               FAIL("all_image_infos: dyld_all_image_infos is not version >= 9, is  %d", infos->version);
                exit(0);
        }
 
                exit(0);
        }
 
@@ -82,15 +59,25 @@ main()
                exit(0);
        }
 
                exit(0);
        }
 
+       //for( int i=0; i < infos->infoArrayCount; ++i) {
+       //      fprintf(stderr, "infos->infoArray[%d].imageLoadAddress=%p %s\n", i, infos->infoArray[i].imageLoadAddress, infos->infoArray[i].imageFilePath);
+       //}
+       
        if ( infos->infoArray[0].imageLoadAddress != &__dso_handle ) {
        if ( infos->infoArray[0].imageLoadAddress != &__dso_handle ) {
-               FAIL("all_image_infos: dyld_all_image_infos.infoArray for main executable is wrong");
+               FAIL("all_image_infos: dyld_all_image_infos.infoArray for main executable is wrong, infos->infoArray[0].imageLoadAddress=0x%08lX vs 0x%08X", 
+                                       infos->infoArray[0].imageLoadAddress, &__dso_handle);
                exit(0);
        }
 
                exit(0);
        }
 
-       if ( getImageInfosFromKernel() != infos ) {
-               FAIL("all_image_infos: task_info and dyld disagree");
-               exit(0);
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
+       for (const struct dyld_image_info* p = infos->infoArray; p < &infos->infoArray[infos->infoArrayCount]; ++p) {
+               //fprintf(stderr, "addr=0x%p, mTime=0x%lX, path=%s\n", p->imageLoadAddress, p->imageFileModDate, p->imageFilePath);
+               if ( (strncmp(p->imageFilePath, "/usr/lib", 8) == 0) && (p->imageFileModDate != 0) ) {
+                       FAIL("all_image_infos, mTime not zero for cache image %s", p->imageFilePath);
+                       exit(0);
+               }
        }
        }
+#endif
 
        PASS("all_image_infos");
        return EXIT_SUCCESS;
 
        PASS("all_image_infos");
        return EXIT_SUCCESS;
index 80ee13793aa2abb3d3b4dc0600897853b6a2f6a8..287a47b5815c519280d0386fb0d2f9b19c5366e1 100644 (file)
@@ -27,13 +27,16 @@ all-check: all check
 
 check:
        ./main
 
 check:
        ./main
+ifneq "$(OS_NAME)" "iPhoneOS"
+       # "avoid" does not work on iPhoneOS because the original dylibs don't exist
        export DYLD_SHARED_REGION=avoid && ./main
        export DYLD_SHARED_REGION=avoid && ./main
+endif
 
 all: main
 
 
 main: main.c 
 
 all: main
 
 
 main: main.c 
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c -mmacosx-version-min=10.5
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c 
 
 
 
 
 
 
index b6f9489a6cf9346e3d9c9db7a80857106fc3c4d4..4f8264a449a6cb0d963c02cc095503b05072aaa9 100644 (file)
@@ -33,7 +33,7 @@ ifeq "ppc" "$(ARCH)"
 endif
 
 
 endif
 
 
-ifeq "armv6" "$(ARCH)"
+ifeq "iPhoneOS" "$(OS_NAME)"
        STACK_SIZE = 0x20000000
 endif
 
        STACK_SIZE = 0x20000000
 endif
 
diff --git a/unit-tests/test-cases/branch-islands/Makefile b/unit-tests/test-cases/branch-islands/Makefile
new file mode 100644 (file)
index 0000000..7b746fd
--- /dev/null
@@ -0,0 +1,40 @@
+##
+# Copyright (c) 2008-2009 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: main 
+
+main : main.c space.s extra.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c space.s extra.c 
+
+
+
+clean:
+       rm ${RMFLAGS} main
diff --git a/unit-tests/test-cases/branch-islands/extra.c b/unit-tests/test-cases/branch-islands/extra.c
new file mode 100644 (file)
index 0000000..c90affa
--- /dev/null
@@ -0,0 +1,8 @@
+#include <stdbool.h>
+
+
+bool test1()
+{
+       return false;
+}
+
diff --git a/unit-tests/test-cases/branch-islands/main.c b/unit-tests/test-cases/branch-islands/main.c
new file mode 100644 (file)
index 0000000..9a265a0
--- /dev/null
@@ -0,0 +1,26 @@
+#include <stdio.h>
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <stdbool.h>
+#include <string.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+// returns false on success
+extern bool test1();
+
+const char* str = "hello";
+
+
+int main()
+{
+       if ( test1() )
+               FAIL("branch-islands: test1");
+       
+       if ( strncmp(str, "he", 2) != 0 )
+               FAIL("branch-islands: strncmp stub");
+
+       
+       PASS("branch-islands");
+       return EXIT_SUCCESS;
+}
+
diff --git a/unit-tests/test-cases/branch-islands/space.s b/unit-tests/test-cases/branch-islands/space.s
new file mode 100644 (file)
index 0000000..4fdd630
--- /dev/null
@@ -0,0 +1,77 @@
+
+#if __ppc__ 
+
+    .text
+
+_prejunk:
+    mr  r3,r5
+    mr  r3,r4
+    blr
+
+
+_space1:
+    .space 15*1024*1024 + 2
+    
+    .align 5
+_junk:
+    mr  r3,r5
+    mr  r3,r4
+    blr
+    
+    
+_space2:
+    .space 2*1024*1024
+#endif
+
+
+#if __arm__
+
+    .text
+_prejunk:
+    mov        r0, #1
+    nop
+
+#if __thumb2__
+       // thumb2 branches are +/- 16MB
+_space1:
+    .space 12*1024*1024
+_space2:
+    .space 12*1024*1024
+_space3:
+    .space 12*1024*1024
+
+
+#elif __thumb__
+       // thumb1 branches are +/- 4MB
+_space1:
+    .space 3*1024*1024
+_space2:
+    .space 3*1024*1024
+_space3:
+    .space 3*1024*1024
+    
+#else
+
+       // ARM branches are +/- 32MB
+_space1:
+    .space 24*1024*1024
+_space2:
+    .space 24*1024*1024
+_space3:
+    .space 24*1024*1024
+
+#endif
+
+    .align 5
+_junk:
+    mov        r0, #1
+    nop
+    
+    
+_space4:
+    .space 2*1024*1024
+#endif
+
+    .subsections_via_symbols
+    
\ No newline at end of file
index 27f76358e1310d172476d765f16ea9bd86336695..49d30c37dc264bb8424fd5037a67c51281746c70 100644 (file)
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <stdbool.h>
 #include <mach-o/dyld.h>
 #include <stdio.h>
 #include <stdbool.h>
 #include <mach-o/dyld.h>
+#include <Availability.h>
 
 #include "test.h" // PASS(), FAIL()
 
 
 #include "test.h" // PASS(), FAIL()
 
@@ -30,6 +31,8 @@ typedef bool (*CheckFunc)();
 
 int main()
 {
 
 int main()
 {
+// these APIs are 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");
        NSObjectFileImage ofi;
        if ( NSCreateObjectFileImageFromFile("test.bundle", &ofi) != NSObjectFileImageSuccess ) {
                FAIL("NSCreateObjectFileImageFromFile failed");
@@ -63,7 +66,7 @@ int main()
                FAIL("NSDestroyObjectFileImage failed");
                return 1;
        }
                FAIL("NSDestroyObjectFileImage failed");
                return 1;
        }
-
+#endif
        PASS("bundle-basic");
        return 0;
 }
\ No newline at end of file
        PASS("bundle-basic");
        return 0;
 }
\ No newline at end of file
index 69e2f2cd54ac3fe978b6446c7e661c4a21e88b66..c79afe0fb9976db9dad2d3a3de4efe8be0552c86 100644 (file)
@@ -34,6 +34,8 @@
 
 int main(int argc, const char* argv[])
 {
 
 int main(int argc, const char* argv[])
 {
+// NSObjectFile* APIs are only available on Mac OS X - not iPhone OS
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        // load foo.bundle with old API
        NSObjectFileImage ofi;
        if ( NSCreateObjectFileImageFromFile("foo.bundle", &ofi) != NSObjectFileImageSuccess ) {
        // load foo.bundle with old API
        NSObjectFileImage ofi;
        if ( NSCreateObjectFileImageFromFile("foo.bundle", &ofi) != NSObjectFileImageSuccess ) {
@@ -84,8 +86,8 @@ int main(int argc, const char* argv[])
                FAIL("NSUnLinkModule failed");
                return 1;
        }
                FAIL("NSUnLinkModule failed");
                return 1;
        }
-               
-       
+#endif 
+
        PASS("bundle-dont-gc");
        return EXIT_SUCCESS;
 }
        PASS("bundle-dont-gc");
        return EXIT_SUCCESS;
 }
diff --git a/unit-tests/test-cases/bundle-memory-load-all-infos/Makefile b/unit-tests/test-cases/bundle-memory-load-all-infos/Makefile
new file mode 100644 (file)
index 0000000..0a4e679
--- /dev/null
@@ -0,0 +1,41 @@
+##
+# 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: main test.bundle
+
+main : main.c
+       ${CC} ${CCFLAGS}  -Wno-deprecated-declarations -I${TESTROOT}/include -o main main.c
+
+test.bundle : bundle.c
+       ${CC} ${CCFLAGS} -bundle -o test.bundle bundle.c
+
+clean:
+       ${RM} ${RMFLAGS} *~ main test.bundle
+
diff --git a/unit-tests/test-cases/bundle-memory-load-all-infos/bundle.c b/unit-tests/test-cases/bundle-memory-load-all-infos/bundle.c
new file mode 100644 (file)
index 0000000..64232df
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdbool.h>
+
+// test to see if bss section is properly expanded 
+
+static int mydata[1000000];
+
+bool checkdata()
+{
+       return ( mydata[500000] == 0 );
+}
diff --git a/unit-tests/test-cases/bundle-memory-load-all-infos/main.c b/unit-tests/test-cases/bundle-memory-load-all-infos/main.c
new file mode 100644 (file)
index 0000000..87eacca
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h> 
+#include <stdbool.h>
+#include <mach-o/dyld.h>
+#include <mach-o/dyld_images.h>
+#include <sys/types.h>
+#include <sys/stat.h> 
+#include <sys/mman.h> 
+#include <unistd.h>
+#include <fcntl.h>
+#include <Availability.h>
+
+#include "test.h" // PASS(), FAIL()
+
+
+struct dyld_all_image_infos* getImageInfosFromKernel()
+{
+       task_dyld_info_data_t task_dyld_info;
+       mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
+    
+    if ( task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&task_dyld_info, &count) ) {
+               FAIL("all_image_infos: task_info() failed");
+               exit(0);
+       }
+       return (struct dyld_all_image_infos*)(uintptr_t)task_dyld_info.all_image_info_addr;
+}
+
+
+int main()
+{
+// NSObjectFileImage APIs are only available on Mac OS X - not iPhone OS
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+       int fd = open("test.bundle", O_RDONLY, 0);
+       if ( fd == -1 ) {
+               FAIL("open() failed");
+               return 1;
+       }
+
+       struct stat stat_buf;
+       if ( fstat(fd, &stat_buf) == -1) {
+               FAIL("fstat() failed");
+               return 0;
+       }
+
+       void* loadAddress = mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
+       if ( loadAddress == ((void*)(-1)) ) {
+               FAIL("mmap() failed");
+               return 0;
+       }
+
+       close(fd);
+
+       NSObjectFileImage ofi;
+       if ( NSCreateObjectFileImageFromMemory(loadAddress, stat_buf.st_size, &ofi) != NSObjectFileImageSuccess ) {
+               FAIL("NSCreateObjectFileImageFromMemory failed");
+               return 0;
+       }
+       
+       NSModule mod = NSLinkModule(ofi, "he_he", NSLINKMODULE_OPTION_NONE);
+       if ( mod == NULL ) {
+               FAIL("NSLinkModule failed");
+               return 0;
+       }
+       
+       // look for he_he string in list of images loaded
+       struct dyld_all_image_infos* infos = getImageInfosFromKernel();
+
+       if ( infos->infoArrayCount < 2 ) {
+               FAIL("bundle-memory-load-all-images: dyld_all_image_infos.infoArrayCount is  < 2");
+               return 0;
+       }
+
+       bool found = false;
+       for( int i=0; i < infos->infoArrayCount; ++i) {
+               //fprintf(stderr, "infos->infoArray[%d].imageLoadAddress=%p %s\n", i, infos->infoArray[i].imageLoadAddress, infos->infoArray[i].imageFilePath);
+               if ( infos->infoArray[i].imageFilePath == NULL ) {
+                       FAIL("bundle-memory-load-all-images: NULL image path found");
+                       exit(0);
+               }
+               if ( strcmp(infos->infoArray[i].imageFilePath, "he_he") == 0 )
+                       found = true;
+       }
+       
+       if ( !found ) {
+               FAIL("bundle-memory-load-all-images: loaded memory bundle 'he_he' nout found");
+               return 0;
+       }
+
+       if ( !NSUnLinkModule(mod, NSUNLINKMODULE_OPTION_NONE) ) {
+               FAIL("NSUnLinkModule failed");
+               return 0;
+       }
+
+       if ( !NSDestroyObjectFileImage(ofi) ) {
+               FAIL("NSDestroyObjectFileImage failed");
+               return 0;
+       }
+       
+       // Should check that loadAddress is unmmaped now (by call to NSDestroyObjectFileImage)
+#endif
+
+       PASS("bundle-memory-load-all-images");
+       return 0;
+}
\ No newline at end of file
index fe100daf1d8d820bf2951e39bf7867575a93efaf..7e8c93c848ad3411cc005ac0706801f56d1c450c 100644 (file)
 #include <sys/mman.h> 
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/mman.h> 
 #include <unistd.h>
 #include <fcntl.h>
+#include <Availability.h>
 
 #include "test.h" // PASS(), FAIL()
 
 int main()
 {
 
 #include "test.h" // PASS(), FAIL()
 
 int main()
 {
+// NSAddImage is only available on Mac OS X - not iPhone OS
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        int fd = open("test.bundle", O_RDONLY, 0);
        if ( fd == -1 ) {
                FAIL("open() failed");
        int fd = open("test.bundle", O_RDONLY, 0);
        if ( fd == -1 ) {
                FAIL("open() failed");
@@ -55,10 +58,11 @@ int main()
 
        // we are using a file not of type MH_BUNDLE, so NSCreateObjectFileImageFromMemory should fail
        NSObjectFileImage ofi;
 
        // we are using a file not of type MH_BUNDLE, so NSCreateObjectFileImageFromMemory should fail
        NSObjectFileImage ofi;
-       if ( NSCreateObjectFileImageFromMemory(loadAddress, stat_buf.st_size, &ofi) != NSObjectFileImageSuccess ) 
-               PASS("bundle-memory-load-bad");
-       else
+       if ( NSCreateObjectFileImageFromMemory(loadAddress, stat_buf.st_size, &ofi) == NSObjectFileImageSuccess ) 
                FAIL("bundle-memory-load-bad");
                FAIL("bundle-memory-load-bad");
+       else
+#endif
+               PASS("bundle-memory-load-bad");
        
        return 0;
 }
\ No newline at end of file
        
        return 0;
 }
\ No newline at end of file
index 7169e32a1e87608406485e37659a2a99d19f24b0..05ef670e2674adbb4adba28874d77520cff4bf35 100644 (file)
@@ -28,6 +28,7 @@
 #include <sys/mman.h> 
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/mman.h> 
 #include <unistd.h>
 #include <fcntl.h>
+#include <Availability.h>
 
 #include "test.h" // PASS(), FAIL()
 
 
 #include "test.h" // PASS(), FAIL()
 
@@ -35,6 +36,8 @@ typedef bool (*CheckFunc)();
 
 int main()
 {
 
 int main()
 {
+// NSObjectFileImage APIs only available on Mac OS X - not iPhone OS
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        int fd = open("test.bundle", O_RDONLY, 0);
        if ( fd == -1 ) {
                FAIL("open() failed");
        int fd = open("test.bundle", O_RDONLY, 0);
        if ( fd == -1 ) {
                FAIL("open() failed");
@@ -90,6 +93,7 @@ int main()
        }
        
        // Should check that loadAddress is unmmaped now (by call to NSDestroyObjectFileImage)
        }
        
        // Should check that loadAddress is unmmaped now (by call to NSDestroyObjectFileImage)
+#endif
 
        PASS("bundle-memory-load-fat");
        return 0;
 
        PASS("bundle-memory-load-fat");
        return 0;
index d00fbdeaef6e942796a1f9b6b651dd626ef40ac9..47e87924e49508f60aa29ad6cda55cf0a8af1bc1 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -30,6 +30,7 @@
 #include <fcntl.h>
 #include <malloc/malloc.h>
 #include <stdlib.h>
 #include <fcntl.h>
 #include <malloc/malloc.h>
 #include <stdlib.h>
+#include <Availability.h>
 
 
 #include "test.h" // PASS(), FAIL()
 
 
 #include "test.h" // PASS(), FAIL()
@@ -38,6 +39,8 @@ typedef bool (*CheckFunc)();
 
 int main()
 {
 
 int main()
 {
+// NSCreateObjectFileImageFromMemory is only available on Mac OS X - not iPhone OS
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        int fd = open("test.bundle", O_RDONLY, 0);
        if ( fd == -1 ) {
                FAIL("open() failed");
        int fd = open("test.bundle", O_RDONLY, 0);
        if ( fd == -1 ) {
                FAIL("open() failed");
@@ -111,9 +114,8 @@ int main()
                return 1;
        }
        
                return 1;
        }
        
-       
-       
        // Should check that loadAddress is unmmaped now (by call to NSDestroyObjectFileImage)
        // Should check that loadAddress is unmmaped now (by call to NSDestroyObjectFileImage)
+#endif
 
        PASS("bundle-memory-load-malloc");
        return 0;
 
        PASS("bundle-memory-load-malloc");
        return 0;
index 8f212f1ced080353f1f53e1b84eaeb22706338a6..7af9854f484a812727e9b61bc36874741c982de9 100644 (file)
@@ -28,6 +28,7 @@
 #include <sys/mman.h> 
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/mman.h> 
 #include <unistd.h>
 #include <fcntl.h>
+#include <Availability.h>
 
 #include "test.h" // PASS(), FAIL()
 
 
 #include "test.h" // PASS(), FAIL()
 
@@ -35,6 +36,8 @@ typedef bool (*CheckFunc)();
 
 int main()
 {
 
 int main()
 {
+// NSObjectFileImage APIs are only available on Mac OS X - not iPhone OS
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        int fd = open("test.bundle", O_RDONLY, 0);
        if ( fd == -1 ) {
                FAIL("open() failed");
        int fd = open("test.bundle", O_RDONLY, 0);
        if ( fd == -1 ) {
                FAIL("open() failed");
@@ -90,6 +93,7 @@ int main()
        }
        
        // Should check that loadAddress is unmmaped now (by call to NSDestroyObjectFileImage)
        }
        
        // Should check that loadAddress is unmmaped now (by call to NSDestroyObjectFileImage)
+#endif
 
        PASS("bundle-memory-load");
        return 0;
 
        PASS("bundle-memory-load");
        return 0;
index 10d9fce9b737f466dda7693aa797f502ca50466b..c15bd031afe8a86c3cacfa0d3375f336352654e0 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -22,6 +22,7 @@
  */
 #include <stdio.h>
 #include <mach-o/dyld.h>
  */
 #include <stdio.h>
 #include <mach-o/dyld.h>
+#include <Availability.h>
 
 #include "test.h" // PASS(), FAIL()
 
 
 #include "test.h" // PASS(), FAIL()
 
@@ -37,6 +38,8 @@ typedef int (*getter)(void);
 
 int main()
 {
 
 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");
        NSObjectFileImage ofi;
        if ( NSCreateObjectFileImageFromFile("test.bundle", &ofi) != NSObjectFileImageSuccess ) {
                FAIL("NSCreateObjectFileImageFromFile failed");
@@ -173,7 +176,8 @@ int main()
                FAIL("NSDestroyObjectFileImage failed");
                return 0;
        }
                FAIL("NSDestroyObjectFileImage failed");
                return 0;
        }
-       
+#endif
+
        PASS("bundle-multi-link");
        return 0;
 }
        PASS("bundle-multi-link");
        return 0;
 }
index b9eb8b3867426051b4eb8b6ae832b57315b15af9..ab0382a40045d7b65c8266be1997510a42feb7aa 100644 (file)
@@ -22,6 +22,7 @@
  */
 #include <stdio.h>
 #include <mach-o/dyld.h>
  */
 #include <stdio.h>
 #include <mach-o/dyld.h>
+#include <Availability.h>
 
 #include "test.h" // PASS(), FAIL()
 
 
 #include "test.h" // PASS(), FAIL()
 
@@ -32,6 +33,8 @@
 
 int main()
 {
 
 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");
        NSObjectFileImage ofi;
        if ( NSCreateObjectFileImageFromFile("test.bundle", &ofi) != NSObjectFileImageSuccess ) {
                FAIL("NSCreateObjectFileImageFromFile failed");
@@ -147,7 +150,7 @@ int main()
                FAIL("3rd NSDestroyObjectFileImage failed");
                return 0;
        }
                FAIL("3rd NSDestroyObjectFileImage failed");
                return 0;
        }
-       
+#endif 
        PASS("bundle-multi-load");
        return 0;
 }
        PASS("bundle-multi-load");
        return 0;
 }
index 4244489e863cd1b7bbb00435a2d2305442751945..15c556351bcf70f9a44a44c8c4d48f5246d28a62 100644 (file)
@@ -31,6 +31,8 @@ typedef bool (*CheckFunc)();
 
 int main()
 {
 
 int main()
 {
+// NSCreateObjectFileImageFromMemory is only available on Mac OS X - not iPhone OS
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        const char* path = "test.bundle";
 
        NSObjectFileImage ofi;
        const char* path = "test.bundle";
 
        NSObjectFileImage ofi;
@@ -77,7 +79,7 @@ int main()
                FAIL("NSDestroyObjectFileImage failed");
                return 0;
        }
                FAIL("NSDestroyObjectFileImage failed");
                return 0;
        }
-
+#endif
        PASS("bundle-name-ownership");
        return 0;
 }
\ No newline at end of file
        PASS("bundle-name-ownership");
        return 0;
 }
\ No newline at end of file
index 86eac29799cee210c9ed3707f0f8d1ff24402844..2a35990c216d8226d81ac8f8420dcc2a3fa13fbe 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <stdbool.h>
 #include <mach-o/dyld.h>
 #include <stdio.h>
 #include <stdbool.h>
 #include <mach-o/dyld.h>
+#include <Availability.h>
 
 #include "test.h" // PASS(), FAIL()
 
 
 #include "test.h" // PASS(), FAIL()
 
@@ -30,6 +31,8 @@ typedef bool (*CheckFunc)();
 
 int main()
 {
 
 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");
        NSObjectFileImage ofi;
        if ( NSCreateObjectFileImageFromFile("test.bundle", &ofi) != NSObjectFileImageSuccess ) {
                FAIL("NSCreateObjectFileImageFromFile failed");
@@ -89,7 +92,7 @@ int main()
                FAIL("NSDestroyObjectFileImage failed");
                return 1;
        }
                FAIL("NSDestroyObjectFileImage failed");
                return 1;
        }
-
+#endif
        PASS("bundle-private");
        return 0;
 }
\ No newline at end of file
        PASS("bundle-private");
        return 0;
 }
\ No newline at end of file
index 1f9c3d7d279ad1f86b4488f95d59591100eb66fb..9f0f0c1244f8b9401b6b270ba75dd7691ca3b617 100644 (file)
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <mach-o/dyld.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <mach-o/dyld.h>
+#include <Availability.h>
 
 #include "test.h" // PASS(), FAIL()
 
 
 #include "test.h" // PASS(), FAIL()
 
@@ -36,6 +37,8 @@ typedef void (*fooProc)();
 // test.bundle
 void doit()
 {
 // test.bundle
 void doit()
 {
+// 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");
        NSObjectFileImage ofi;
        if ( NSCreateObjectFileImageFromFile("test.bundle", &ofi) != NSObjectFileImageSuccess ) {
                FAIL("NSCreateObjectFileImageFromFile failed");
@@ -66,14 +69,17 @@ void doit()
                FAIL("NSDestroyObjectFileImage failed");
                exit(0);
        }
                FAIL("NSDestroyObjectFileImage failed");
                exit(0);
        }
+#endif
 }
 
 
 static void myRemoveImage(const struct mach_header *mh, intptr_t vmaddr_slide)
 {
 }
 
 
 static void myRemoveImage(const struct mach_header *mh, intptr_t vmaddr_slide)
 {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        // calling _dyld_get_image_header_containing_address() during the remove image hook 
        // could cause dyld to not flush the address->image cache
        _dyld_get_image_header_containing_address(mh);
        // calling _dyld_get_image_header_containing_address() during the remove image hook 
        // could cause dyld to not flush the address->image cache
        _dyld_get_image_header_containing_address(mh);
+#endif
 }
 
 
 }
 
 
index 93af2686ace2982a153f0d77747fa53fc3ce9d7d..bccdf8d6a2f0fed586a114d0c94924e11d7cefef 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <mach-o/dyld.h>
 #include <stdio.h>
 #include <string.h>
 #include <mach-o/dyld.h>
+#include <Availability.h>
 
 #include "test.h" // PASS(), FAIL()
 
 
 #include "test.h" // PASS(), FAIL()
 
@@ -30,6 +31,8 @@ typedef bool (*CheckFunc)();
 
 int main()
 {
 
 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");
        NSObjectFileImage ofi;
        if ( NSCreateObjectFileImageFromFile("test.bundle", &ofi) != NSObjectFileImageSuccess ) {
                FAIL("NSCreateObjectFileImageFromFile failed");
@@ -61,7 +64,7 @@ int main()
                        return 1;
                }
        }
                        return 1;
                }
        }
-
+#endif
        PASS("bundle-unlinkable");
        return 0;
 }
\ No newline at end of file
        PASS("bundle-unlinkable");
        return 0;
 }
\ No newline at end of file
index c79b0fd107f727b9ecd7ab188e263f85b6123d09..018ee9e7e94c4525ea0014086d783fe36c3b684d 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <stdbool.h>
 #include <mach-o/dyld.h>
 #include <stdio.h>
 #include <stdbool.h>
 #include <mach-o/dyld.h>
+#include <Availability.h>
 
 #include "test.h" // PASS(), FAIL()
 
 
 #include "test.h" // PASS(), FAIL()
 
@@ -30,6 +31,8 @@ typedef bool (*CheckFunc)();
 
 int main()
 {
 
 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");
        NSObjectFileImage ofi;
        if ( NSCreateObjectFileImageFromFile("test.bundle", &ofi) != NSObjectFileImageSuccess ) {
                FAIL("NSCreateObjectFileImageFromFile failed");
@@ -66,7 +69,7 @@ int main()
 
        // call function again, even though bundle is unloaded
        func();
 
        // call function again, even though bundle is unloaded
        func();
-       
+#endif 
 
        PASS("bundle-basic");
        return 0;
 
        PASS("bundle-basic");
        return 0;
index 8caba38d6269e2f5ce70a09d6f90e0ff631f0da7..aea5c6f6ca6462b4fe2aaef22b4859a5e02dfbd6 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <sys/mman.h> 
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/mman.h> 
 #include <unistd.h>
 #include <fcntl.h>
+#include <Availability.h>
 
 #include "test.h" // PASS(), FAIL()
 
 
 #include "test.h" // PASS(), FAIL()
 
+extern void bar();
+
+
+// NSCreateObjectFileImageFromMemory is only available on Mac OS X - not iPhone OS
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
 
 void loadAsBundleFromMemory(const char* path)
 {
 
 void loadAsBundleFromMemory(const char* path)
 {
@@ -79,10 +85,11 @@ void loadAsDylib(const char* path)
        }
 }
 
        }
 }
 
-extern void bar();
+#endif
 
 int main()
 {
 
 int main()
 {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        int dummy; 
        
        // verify that NSAddImage fails to load MH_BUNDLE
        int dummy; 
        
        // verify that NSAddImage fails to load MH_BUNDLE
@@ -102,7 +109,7 @@ int main()
        
        // verify that dyld data structures are not wanked by scanning all images
        _dyld_get_image_header_containing_address(&dummy);
        
        // verify that dyld data structures are not wanked by scanning all images
        _dyld_get_image_header_containing_address(&dummy);
-
+#endif
        PASS("bundle-v-dylib");
        return 0;
 }
\ No newline at end of file
        PASS("bundle-v-dylib");
        return 0;
 }
\ No newline at end of file
diff --git a/unit-tests/test-cases/coreSymbolication-notify/Makefile b/unit-tests/test-cases/coreSymbolication-notify/Makefile
new file mode 100644 (file)
index 0000000..60cedcd
--- /dev/null
@@ -0,0 +1,52 @@
+##
+# Copyright (c) 2009 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
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+all-check: all check
+
+check:
+       export DYLD_PRINT_CS_NOTIFICATIONS=1 && ./main  2> notifications.log
+       grep " load" notifications.log | grep foo.bundle | wc -l | grep 1  >/dev/null
+       grep " load" notifications.log | grep bar.dylib | wc -l | grep 1 >/dev/null
+       grep " unload" notifications.log | grep foo.bundle | wc -l | grep 1  >/dev/null
+       grep " unload" notifications.log | grep bar.dylib | wc -l | grep 1 >/dev/null
+       echo "PASS coreSymbolication-notify"
+
+all: main foo.bundle 
+
+main: main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c 
+
+foo.bundle: foo.c libbar.dylib 
+       ${CC} ${CCFLAGS} -bundle -I${TESTROOT}/include -o foo.bundle foo.c libbar.dylib  
+
+libbar.dylib : bar.c
+       ${CC} ${CCFLAGS} -dynamiclib -I${TESTROOT}/include -o libbar.dylib  bar.c 
+       
+
+clean:
+       ${RM} ${RMFLAGS} *~ main foo.bundle libbar.dylib notifications.log
+
diff --git a/unit-tests/test-cases/coreSymbolication-notify/bar.c b/unit-tests/test-cases/coreSymbolication-notify/bar.c
new file mode 100644 (file)
index 0000000..63c34e0
--- /dev/null
@@ -0,0 +1,2 @@
+
+int bar = 10;
diff --git a/unit-tests/test-cases/coreSymbolication-notify/foo.c b/unit-tests/test-cases/coreSymbolication-notify/foo.c
new file mode 100644 (file)
index 0000000..6924ac6
--- /dev/null
@@ -0,0 +1,3 @@
+
+void foo() {}
+
diff --git a/unit-tests/test-cases/coreSymbolication-notify/main.c b/unit-tests/test-cases/coreSymbolication-notify/main.c
new file mode 100644 (file)
index 0000000..56ca5f4
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdbool.h>  // fprintf(), NULL
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <stdbool.h>
+#include <string.h>
+#include <mach-o/dyld.h>  
+#include <mach-o/dyld_priv.h>  
+#include <dlfcn.h>  
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+int main(int argc, const char* argv[])
+{
+
+       if ( ! dlopen_preflight("foo.bundle") ) {
+               FAIL("coreSymbolication-notify foo.bundle should not be loadable");
+               exit(0);
+       }
+
+       void* h = dlopen("foo.bundle", RTLD_LAZY);
+       if ( h == NULL ) {
+               FAIL("coreSymbolication-notify foo.bundle failed: %s", dlerror());
+               exit(0);
+       }
+
+       dlclose(h);
+       
+                       
+       return EXIT_SUCCESS;
+}
index 893e25bca74b9a946acb88bbd3586d3a4e3af8d2..78e43d593663fc35b4fde857c2818ec099639454 100644 (file)
@@ -1,5 +1,5 @@
 ##
 ##
-# Copyright (c) 2007 Apple Inc. All rights reserved.
+# Copyright (c) 2007-2010 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -30,30 +30,27 @@ include ${TESTROOT}/include/common.makefile
 all-check: all check
 
 check:
 all-check: all check
 
 check:
-       ./main-10.4 ./main-10.4
-       ./main-10.5 ./main-10.5
-       ./main-10.4.stripped ./main-10.4.stripped
-       ./main-10.5.stripped ./main-10.5.stripped
-       `pwd`/main-10.4 `pwd`/main-10.4
-       `pwd`/main-10.5 `pwd`/main-10.5
-       `pwd`/main-10.4.stripped `pwd`/main-10.4.stripped
-       `pwd`/main-10.5.stripped `pwd`/main-10.5.stripped
+       ./main ./main
+       ./main.stripped ./main.stripped
+       `pwd`/main `pwd`/main
+       `pwd`/main.stripped `pwd`/main.stripped
+       export DYLD_LIBRARY_PATH=. && export DYLD_FRAMEWORK_PATH=. && ./main-setuid ./main-setuid
 
 
-all: main-10.4 main-10.5 main-10.4.stripped main-10.5.stripped
+all: main  main.stripped main-setuid
 
 
-main-10.4: main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main-10.4 main.c -mmacosx-version-min=10.4 -w
+main: main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c -w
 
 
-main-10.4.stripped: main-10.4
-       strip main-10.4 -o main-10.4.stripped
-       
-main-10.5: main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main-10.5 main.c -mmacosx-version-min=10.5 -w
+main.stripped: main
+       strip main -o main.stripped
+
+main-setuid: main
+       cp main main-setuid
+       sudo chown root main-setuid
+       sudo chmod 4755 main-setuid
 
 
-main-10.5.stripped: main-10.5
-       strip main-10.5 -o main-10.5.stripped
 
 clean:
 
 clean:
-       ${RM} ${RMFLAGS} *~ main-10.4 main-10.5 main-10.4.stripped main-10.5.stripped
+       ${RM} ${RMFLAGS} *~ main main.stripped main-setuid
  
 
  
 
index 05959bb763717b40d6178352ef90f6ea22a58fcb..0d888ad0dda43e3a636d75a6398c8998f326c9d2 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 
 
 ///
 
 
 ///
+/// verify parameters passed to initializer are same as passed to main()
 /// verify that apple[0] parameter is correct by comparing to argv[1]
 ///
 
 /// verify that apple[0] parameter is correct by comparing to argv[1]
 ///
 
+static int                     initializer_argc = 0;
+static const char**    initializer_argv = NULL;
+static const char**    initializer_env = NULL;
+static const char**    initializer_apple = NULL;
+
+
+__attribute__((constructor))
+void init(int argc, const char* argv[], const char* env[], const char* apple[])
+{
+       initializer_argc = argc;
+       initializer_argv = argv;
+       initializer_env = env;
+       initializer_apple = apple;
+}
+
 int
 main(int argc, const char* argv[], const char* env[], const char* apple[])
 {
 int
 main(int argc, const char* argv[], const char* env[], const char* apple[])
 {
+       if ( argc != initializer_argc ) {
+               FAIL("crt-apple argc changed");
+               exit(EXIT_SUCCESS);
+       }
+       
+       if ( argv != initializer_argv ) {
+               FAIL("crt-apple argv changed");
+               exit(EXIT_SUCCESS);
+       }
+               
+       if ( env != initializer_env ) {
+               FAIL("crt-apple envp changed");
+               exit(EXIT_SUCCESS);
+       }
+               
+       if ( apple != initializer_apple ) {
+               FAIL("crt-apple apple changed");
+               exit(EXIT_SUCCESS);
+       }
+               
        if ( strcmp(apple[0], argv[1]) == 0 )
                PASS("crt-apple %s", argv[0]);
        else
        if ( strcmp(apple[0], argv[1]) == 0 )
                PASS("crt-apple %s", argv[0]);
        else
index 9d8dd599fa30983017aac9bf7f44c19a503df72a..f1865bb19f385bf4e6386455bd3029e88bc9c90c 100644 (file)
@@ -1,5 +1,5 @@
 ##
 ##
-# Copyright (c) 2007 Apple Inc. All rights reserved.
+# Copyright (c) 2007-2009 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -30,19 +30,16 @@ include ${TESTROOT}/include/common.makefile
 all-check: all check
 
 check:
 all-check: all check
 
 check:
-       ${TESTROOT}/bin/exit-zero-pass.pl "crt-argv-NULL main-10.4" "crt-argv-NULL main-10.4"    ./main-10.4
-       ${TESTROOT}/bin/exit-zero-pass.pl "crt-argv-NULL main-10.5" "crt-argv-NULL main-10.5"    ./main-10.5
+       ${TESTROOT}/bin/exit-zero-pass.pl "crt-argv-NULL main" "crt-argv-NULL main"    ./main
 
 
 
 
-all:  main-10.4  main-10.5
+all:  main
 
 
-main-10.4: main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main-10.4 main.c -mmacosx-version-min=10.4
 
 
-main-10.5: main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main-10.5 main.c -mmacosx-version-min=10.5
+main: main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
 
 clean:
 
 clean:
-       ${RM} ${RMFLAGS} *~ main-10.4  main-10.5
+       ${RM} ${RMFLAGS} *~ main
  
 
  
 
index 491d480726183b277c9295f5a4d8c1b9d2347af0..ee12f105146b48667b67772d81ed3b223d8e75bf 100644 (file)
@@ -1,5 +1,5 @@
 ##
 ##
-# Copyright (c) 2007 Apple Inc. All rights reserved.
+# Copyright (c) 2007-2009 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -31,20 +31,16 @@ include ${TESTROOT}/include/common.makefile
 all-check: all check
 
 check:
 all-check: all check
 
 check:
-       ./main-10.4
-       ./main-10.5
+       ./main
 
 
 
 
-all: main-10.4 main-10.5
+all: main
 
 
-main-10.4: main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main-10.4 mystart.s main.c -mmacosx-version-min=10.4 -e _mystart
-
-main-10.5: main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main-10.5 mystart.s main.c -mmacosx-version-min=10.5 -e _mystart
+main: main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main mystart.s main.c -e _mystart
 
 
 clean:
 
 
 clean:
-       ${RM} ${RMFLAGS} *~ main-10.4 main-10.5
+       ${RM} ${RMFLAGS} *~  main
  
 
  
 
index 0986fd082648611c77b8e6489361a61f0d766d84..29c79cf8cd6e5ce81b96b79d7c787dd7ec804a25 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -23,6 +23,7 @@
 #include <stdio.h>  // fprintf(), NULL
 #include <stdlib.h> // exit(), EXIT_SUCCESS
 #include <dlfcn.h>
 #include <stdio.h>  // fprintf(), NULL
 #include <stdlib.h> // exit(), EXIT_SUCCESS
 #include <dlfcn.h>
+#include <Availability.h>
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
@@ -34,10 +35,15 @@ int flag = 0;
        // for 64-bit binaries initializers are always called before entry point
        #define ENTRY_BEFORE_INIT 0
 #else
        // for 64-bit binaries initializers are always called before entry point
        #define ENTRY_BEFORE_INIT 0
 #else
-       // for pre 10.5, 32-bit binaries, entry point is called which then calls initializers
-       #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
-               #define ENTRY_BEFORE_INIT 1
+       #if __MAC_OS_X_VERSION_MIN_REQUIRED
+               // for pre 10.5, 32-bit binaries, entry point is called which then calls initializers
+               #if __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_5
+                       #define ENTRY_BEFORE_INIT 1
+               #else
+                       #define ENTRY_BEFORE_INIT 0
+               #endif
        #else
        #else
+               // for iPhoneOS, initializers are always called before entry point
                #define ENTRY_BEFORE_INIT 0
        #endif
 #endif
                #define ENTRY_BEFORE_INIT 0
        #endif
 #endif
index b4cb9be56b23df32765e17d8d6eb2fe0eb1af5fe..a95e0b511824da84125229e77e559f1634e8419f 100644 (file)
@@ -1,3 +1,7 @@
+# Built output for (null)
+# Generated at (null)
+# Using (null) configuration, (null) architecture for (null) target of (null) project
+
 
 
 
 
 
 
@@ -5,7 +9,10 @@
        .globl _mystart
 _mystart:
 #if __i386__ 
        .globl _mystart
 _mystart:
 #if __i386__ 
-       movl    $2, _flag
+       call    L1
+L1: popl       %eax
+       movl    L_flag$non_lazy_ptr-L1(%eax), %eax
+       movl    $2, (%eax)
        jmp             start
 #elif __x86_64__
        movl    $2, _flag(%rip)
        jmp             start
 #elif __x86_64__
        movl    $2, _flag(%rip)
@@ -15,6 +22,22 @@ _mystart:
        lis r2,ha16(_flag)
        stw r0,lo16(_flag)(r2)
        b               start
        lis r2,ha16(_flag)
        stw r0,lo16(_flag)(r2)
        b               start
+#elif __arm__
+       ldr     r3, L4
+       mov     r2, #2
+       add     r3, pc
+       ldr     r3, [r3]
+       str     r2, [r3, #0]
+       b       start
+L4:    .long   L_flag$non_lazy_ptr-(L4-8)
+#endif
+
+#if __i386__ || __arm__
+       .section        __DATA,__nl_symbol_ptr,non_lazy_symbol_pointers
+       .align  2
+L_flag$non_lazy_ptr:
+.indirect_symbol _flag
+       .long   0
 #endif
 
 
 #endif
 
 
index 6f30df5137be587b2633e322ba6e07db66ffca7b..aab6ce682e8b4b65fb0bf861c6a5ba71839905cf 100644 (file)
@@ -1,5 +1,5 @@
 ##
 ##
-# Copyright (c) 2007 Apple Inc. All rights reserved.
+# Copyright (c) 2007-2009 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -28,37 +28,23 @@ include ${TESTROOT}/include/common.makefile
 # the mechanism for 10.4 and 10.5 is different 
 #
 
 # the mechanism for 10.4 and 10.5 is different 
 #
 
+
 all-check: all check
 
 check:
 all-check: all check
 
 check:
-       ./main-10.4
-       ./main-10.5
-       ./main-10.6
-       ./main-10.4.stripped
-       ./main-10.5.stripped
-       ./main-10.6.stripped
-
-all: main-10.4 main-10.5 main-10.6 main-10.4.stripped main-10.5.stripped main-10.6.stripped
-
-main-10.4: main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main-10.4 main.c -mmacosx-version-min=10.4
+       ./main
+       ./main.stripped
 
 
-main-10.4.stripped: main-10.4
-       strip main-10.4 -o main-10.4.stripped
-       
-main-10.5: main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main-10.5 main.c -mmacosx-version-min=10.5
+all: main  main.stripped
 
 
-main-10.5.stripped: main-10.5
-       strip main-10.5 -o main-10.5.stripped
 
 
-main-10.6: main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main-10.6 main.c -mmacosx-version-min=10.6  -nostdlib -lcrt1.10.6.o -lSystem
+main: main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include $(CRTLIB) -o main main.c
 
 
-main-10.6.stripped: main-10.6
-       strip main-10.6 -o main-10.6.stripped
+main.stripped: main
+       strip main -o main.stripped
 
 clean:
 
 clean:
-       ${RM} ${RMFLAGS} *~ main-10.4 main-10.5 main-10.6 main-10.4.stripped main-10.5.stripped main-10.6.stripped
+       ${RM} ${RMFLAGS} *~ main main.stripped
  
 
  
 
index 0e4bd7b46628703c8da7fe1b8f4042dfdecbb115..a0cf8eda938cab9bdac2e27a05d2a19e78d4ebaf 100644 (file)
@@ -1,5 +1,5 @@
 ##
 ##
-# Copyright (c) 2007 Apple Inc. All rights reserved.
+# Copyright (c) 2007-2009 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -31,27 +31,20 @@ include ${TESTROOT}/include/common.makefile
 all-check: all check
 
 check:
 all-check: all check
 
 check:
-       ${TESTROOT}/bin/exit-zero-pass.pl "crt-result good-10.4" "crt-result good-10.4"    ./good-10.4
-       ${TESTROOT}/bin/exit-zero-pass.pl "crt-result good-10.5" "crt-result good-10.5"    ./good-10.5
-       ${TESTROOT}/bin/exit-non-zero-pass.pl "crt-result bad-10.4" "crt-result bad-10.4"  ./bad-10.4
-       ${TESTROOT}/bin/exit-non-zero-pass.pl "crt-result bad-10.5" "crt-result bad-10.5"  ./bad-10.5
+       ${TESTROOT}/bin/exit-zero-pass.pl "crt-result good" "crt-result good"    ./good
+       ${TESTROOT}/bin/exit-non-zero-pass.pl "crt-result bad" "crt-result bad"  ./bad
 
 
 
 
-all: good-10.4 good-10.5  bad-10.4 bad-10.5 
+all: good bad 
 
 
-good-10.4: good.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o good-10.4 good.c -mmacosx-version-min=10.4
 
 
-good-10.5: good.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o good-10.5 good.c -mmacosx-version-min=10.5
+good: good.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o good good.c 
 
 
-bad-10.4: bad.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o bad-10.4 bad.c -mmacosx-version-min=10.4
-
-bad-10.5: bad.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o bad-10.5 bad.c -mmacosx-version-min=10.5
+bad: bad.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o bad bad.c
 
 clean:
 
 clean:
-       ${RM} ${RMFLAGS} *~ good-10.4 good-10.5  bad-10.4 bad-10.5 
+       ${RM} ${RMFLAGS} *~  good  bad 
  
 
  
 
index 0399be1b82cbbb0fee1b5a08a2dd86183c75ca00..e0731709e7423a71dfd10fc1bd316717f2e62ab8 100644 (file)
  * @APPLE_LICENSE_HEADER_END@
  */
 
  * @APPLE_LICENSE_HEADER_END@
  */
 
+#include <stdlib.h>
 
 class A
 {
 public:
        A() { f = 10; }
 
 class A
 {
 public:
        A() { f = 10; }
-       ~A() { f = 0; }
+       ~A() { if ( f == 0 ) abort(); f = 0; }
        int get() { return f; }
 private:
        int f;  
        int get() { return f; }
 private:
        int f;  
index 9727ccb66ef05e205c7d8bf63bf6e6c37d23e32e..21e64462c030b33649c045d8d7e8563d4aad302a 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -25,6 +25,7 @@
 #include <mach-o/dyld.h>
 #include <pthread.h>
 #include <unistd.h>
 #include <mach-o/dyld.h>
 #include <pthread.h>
 #include <unistd.h>
+#include <Availability.h>
 
 #include "test.h"
 
 
 #include "test.h"
 
@@ -40,6 +41,7 @@
 
 extern void foo();
 
 
 extern void foo();
 
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
 
 static volatile int            sBarrier = 0;
 static pthread_mutex_t sBarrierMutex;
 
 static volatile int            sBarrier = 0;
 static pthread_mutex_t sBarrierMutex;
@@ -90,9 +92,11 @@ static void myImageHandler(const struct mach_header *mh, intptr_t vmaddr_slide)
                pthread_mutex_unlock(&sMyLock);
        }
 }
                pthread_mutex_unlock(&sMyLock);
        }
 }
+#endif
 
 int main()
 {
 
 int main()
 {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        pthread_mutex_init(&sBarrierMutex, NULL);
        pthread_cond_init(&sBarrierFree, NULL);
        pthread_mutex_init(&sMyLock, NULL);
        pthread_mutex_init(&sBarrierMutex, NULL);
        pthread_cond_init(&sBarrierFree, NULL);
        pthread_mutex_init(&sMyLock, NULL);
@@ -111,6 +115,8 @@ int main()
        // thread 1
        _dyld_register_func_for_add_image(&myImageHandler);
        NSAddImage("bar.dylib", 0);
        // thread 1
        _dyld_register_func_for_add_image(&myImageHandler);
        NSAddImage("bar.dylib", 0);
+#endif
        
        PASS("deadlock");
        
        PASS("deadlock");
+       return 0;
 }
 }
index 3a6122055579a269893161b6ec0d669e243bfaed..fb05db114b578b1f0f58c1dcf8c84a25ad806070 100644 (file)
@@ -1,5 +1,5 @@
 ##
 ##
-# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2005-2009 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -29,7 +29,7 @@ check:
        ./main
 
 all:
        ./main
 
 all:
-       ${CC} ${CCFLAGS} -Wno-deprecated-declarations -g -I${TESTROOT}/include -o main main.c -mmacosx-version-min=10.5
+       ${CC} ${CCFLAGS} -Wno-deprecated-declarations -g -I${TESTROOT}/include -o main main.c
        
 
 clean:
        
 
 clean:
index ab88475bafe8c684b9f605447580970c37c67209..c75c621a1a175652a65293ecaf73820abc0b7f12 100644 (file)
@@ -25,6 +25,7 @@
 #include <string.h> 
 #include <dlfcn.h> 
 #include <mach-o/dyld.h> 
 #include <string.h> 
 #include <dlfcn.h> 
 #include <mach-o/dyld.h> 
+#include <Availability.h> 
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
@@ -66,10 +67,12 @@ static void verifybar()
                FAIL("dladdr()->dli_saddr is not &bar");
                exit(0);
        }
                FAIL("dladdr()->dli_saddr is not &bar");
                exit(0);
        }
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        if ( info.dli_fbase != _dyld_get_image_header_containing_address(&bar) ) {
                FAIL("dladdr()->dli_fbase is not image that contains &bar");
                exit(0);
        }
        if ( info.dli_fbase != _dyld_get_image_header_containing_address(&bar) ) {
                FAIL("dladdr()->dli_fbase is not image that contains &bar");
                exit(0);
        }
+#endif
 }
 
 // checks local symbol 
 }
 
 // checks local symbol 
@@ -88,10 +91,12 @@ static void verifyfoo()
                FAIL("dladdr()->dli_saddr is not &foo");
                exit(0);
        }
                FAIL("dladdr()->dli_saddr is not &foo");
                exit(0);
        }
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        if ( info.dli_fbase != _dyld_get_image_header_containing_address(&foo) ) {
                FAIL("dladdr()->dli_fbase is not image that contains &foo");
                exit(0);
        }
        if ( info.dli_fbase != _dyld_get_image_header_containing_address(&foo) ) {
                FAIL("dladdr()->dli_fbase is not image that contains &foo");
                exit(0);
        }
+#endif
 }
 
 // checks hidden symbol 
 }
 
 // checks hidden symbol 
@@ -110,10 +115,12 @@ static void verifyhide()
                FAIL("dladdr()->dli_saddr is not &hide");
                exit(0);
        }
                FAIL("dladdr()->dli_saddr is not &hide");
                exit(0);
        }
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        if ( info.dli_fbase != _dyld_get_image_header_containing_address(&hide) ) {
                FAIL("dladdr()->dli_fbase is not image that contains &hide");
                exit(0);
        }
        if ( info.dli_fbase != _dyld_get_image_header_containing_address(&hide) ) {
                FAIL("dladdr()->dli_fbase is not image that contains &hide");
                exit(0);
        }
+#endif
 }
 
 
 }
 
 
index 797e0c4a95591bd0196ab2af8f3acbe70c28a959..6515da42625ceaa3447d71cb4ddfa2a17f6d1be7 100644 (file)
@@ -1,5 +1,5 @@
 ##
 ##
-# Copyright (c) 2008 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2008-2009 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
+ifeq "$(OS_NAME)" "iPhoneOS"
+       RUN_AS_USER = login -f -l mobile
+else
+       RUN_AS_USER = 
+endif
+
 all-check: all check
 
 check:
 all-check: all check
 
 check:
-       ./main
+       chmod -r libnoread.dylib
+       ${RUN_AS_USER} ./main
 
 all:  
        ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
        ${CC} ${CCFLAGS} foo.c -dynamiclib -o libnoread.dylib
 
 all:  
        ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
        ${CC} ${CCFLAGS} foo.c -dynamiclib -o libnoread.dylib
-       chmod -r libnoread.dylib
 
 clean:
        ${RM} ${RMFLAGS} *~ main libnoread.dylib
 
 clean:
        ${RM} ${RMFLAGS} *~ main libnoread.dylib
index a3afc96e62a43341b0089aabf94e9882dfac808e..2fc2da1c7f7d1c8beeefa6a57df9ea79e45c4a25 100644 (file)
@@ -35,7 +35,7 @@ main : main.c
 
 
 foo.exe : foo.c
 
 
 foo.exe : foo.c
-       ${CC} ${CCFLAGS} foo.c -o foo.exe
+       ${CC} ${CCFLAGS} foo.c -o foo.exe -Wl,-no_pie
 
 foo.pie : foo.c
        ${CC} ${CCFLAGS} foo.c -o foo.pie -Wl,-pie
 
 foo.pie : foo.c
        ${CC} ${CCFLAGS} foo.c -o foo.pie -Wl,-pie
index 8dfe72f77d8ce3240469bde46a3a311fa551d64a..e208e146448805b9b2f3a29a488ed5576791f80d 100644 (file)
@@ -26,6 +26,7 @@
 #include <dlfcn.h>
 #include <libkern/OSCacheControl.h> // sys_icache_invalidate
 #include <sys/mman.h> // for mprotext
 #include <dlfcn.h>
 #include <libkern/OSCacheControl.h> // sys_icache_invalidate
 #include <sys/mman.h> // for mprotext
+#include <mach/mach.h>
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
@@ -36,18 +37,33 @@ void* calldlopen(const char* path, int mode, void* (*dlopen_proc)(const char* pa
        return (*dlopen_proc)(path, mode);
 }
 
        return (*dlopen_proc)(path, mode);
 }
 
+#if __thumb__
+       #define START_OF_FUNC(x) ((void*)((long)x & (-2)))
+       #define ADDR_FROM_BLOCK(x) ((void*)((long)x | 1))
+#else
+       #define START_OF_FUNC(x) (x)
+       #define ADDR_FROM_BLOCK(x) (x)
+#endif
+
 //
 // try calling dlopen() from code not owned by dyld
 //
 int main()
 {
 //
 // try calling dlopen() from code not owned by dyld
 //
 int main()
 {
-       void* codeBlock = malloc(4096);
-       memcpy(codeBlock, &calldlopen, 4096);
+       // now try to create a page where foo() was
+       vm_address_t addr = 0;
+       kern_return_t r = vm_allocate(mach_task_self(), &addr, 4096, VM_FLAGS_ANYWHERE);
+       if ( r != KERN_SUCCESS )  {
+               FAIL("vm_allocate returned %d", r);
+               return 0;
+       }
+       void* codeBlock = (void*)(addr);
+       memcpy(codeBlock, START_OF_FUNC(calldlopen), 4096);
        sys_icache_invalidate(codeBlock, 4096);
        mprotect(codeBlock, 4096, PROT_READ | PROT_EXEC);
        //fprintf(stderr, "codeBlock=%p\n", codeBlock);
        
        sys_icache_invalidate(codeBlock, 4096);
        mprotect(codeBlock, 4096, PROT_READ | PROT_EXEC);
        //fprintf(stderr, "codeBlock=%p\n", codeBlock);
        
-       void* (*caller)(const char* path, int mode, void* (*dlopen_proc)(const char* path, int mode)) = codeBlock;
+       void* (*caller)(const char* path, int mode, void* (*dlopen_proc)(const char* path, int mode)) = ADDR_FROM_BLOCK(codeBlock);
        
        void* handle = (*caller)("foo.bundle", RTLD_LAZY, &dlopen);
        if ( handle == NULL ) {
        
        void* handle = (*caller)("foo.bundle", RTLD_LAZY, &dlopen);
        if ( handle == NULL ) {
index b72a1a51675ec5c2a5697df7c72e15a897c8dadd..a48d74f22656e17f5f26bbd89c7d88af7114a07f 100644 (file)
@@ -1,3 +1,6 @@
+#include <string.h>
+
 void bar()
 {
 void bar()
 {
+       strcpy(NULL, NULL);
 }
 }
diff --git a/unit-tests/test-cases/dlopen-non-canonical-path/Makefile b/unit-tests/test-cases/dlopen-non-canonical-path/Makefile
new file mode 100644 (file)
index 0000000..e933867
--- /dev/null
@@ -0,0 +1,37 @@
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+
+all-check: all check
+
+check:
+       ./main
+
+all:
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c 
+
+clean:
+       ${RM} ${RMFLAGS} main 
diff --git a/unit-tests/test-cases/dlopen-non-canonical-path/main.c b/unit-tests/test-cases/dlopen-non-canonical-path/main.c
new file mode 100644 (file)
index 0000000..023c370
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2009 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> // EXIT_SUCCESS
+#include <stdio.h> 
+#include <dlfcn.h>
+#include <Availability.h>
+
+#include "test.h"
+
+static void tryPath(const char* path)
+{
+       if ( dlopen_preflight(path) ) {
+               void* handle = dlopen(path, RTLD_LAZY);
+               if ( handle == NULL ) {
+                       FAIL("dlopen-non-canonical-path: dlopen(%s)", path);
+                       exit(0);
+               }
+       }
+       else {
+               FAIL("dlopen-non-canonical-path: dlopen_preflight(%s)", path);
+               exit(0);
+       }
+}
+
+//
+//  <rdar://problem/7017050> dlopen() not opening frameworks with non-canonical paths
+//
+
+int main()
+{
+       tryPath("//usr/lib/libSystem.B.dylib");
+       tryPath("/usr/bin/../lib/libSystem.B.dylib");
+       tryPath("/usr/lib/./libSystem.B.dylib");
+       tryPath("/usr/lib//libSystem.B.dylib");
+
+       PASS("dlopen-non-canonical-path");
+       return EXIT_SUCCESS;
+}
+
+
index 5844be249342890510695b0a718d60a92ece0752..484ef57dbae54dc4237d61bd304c5c088ebc757d 100644 (file)
@@ -39,7 +39,7 @@ check:
 all: main 
 
 main : main.c  libfoo.dylib 
 all: main 
 
 main : main.c  libfoo.dylib 
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c -mmacosx-version-min=10.4
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -Wno-deprecated-declarations  -o main main.c 
 
 
 libfoo.dylib : foo.c
 
 
 libfoo.dylib : foo.c
index d99436ac253f6f9b18a3bb621b0fee5e6537e81a..630ba970f5676872ef64d062ae3f0a2e9e392180 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -24,6 +24,7 @@
 #include <stdlib.h> // exit(), EXIT_SUCCESS
 #include <dlfcn.h>
 #include <mach-o/dyld.h>
 #include <stdlib.h> // exit(), EXIT_SUCCESS
 #include <dlfcn.h>
 #include <mach-o/dyld.h>
+#include <Availability.h>
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
@@ -33,8 +34,11 @@ typedef void* (*fooProc)();
 
 static void notify(const struct mach_header *mh, intptr_t vmaddr_slide) 
 {
 
 static void notify(const struct mach_header *mh, intptr_t vmaddr_slide) 
 {
+// NSLookupSymbolInImage is only available on Mac OS X - not iPhone OS
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        //fprintf(stderr, "mh=%p\n", mh);
        NSLookupSymbolInImage(mh, "_bar", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
        //fprintf(stderr, "mh=%p\n", mh);
        NSLookupSymbolInImage(mh, "_bar", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
+#endif
 }
 
 
 }
 
 
diff --git a/unit-tests/test-cases/dlopen-search-leak/Makefile b/unit-tests/test-cases/dlopen-search-leak/Makefile
new file mode 100644 (file)
index 0000000..2a361da
--- /dev/null
@@ -0,0 +1,71 @@
+##
+# Copyright (c) 2007-2009 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 there are no leaks with dlopen/close on success and failure
+#
+
+# leaks does not work on rosetta processes
+CHECK = check-real
+ifeq "ppc" "$(ARCH)"
+       MACHINE =  $(shell arch)
+       ifeq "i386" "$(MACHINE)"
+               CHECK = check-xfail
+       endif
+endif
+
+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"
+
+check-xfail:
+       echo "XFAIL dlopen-leak"; 
+       
+       
+all: main
+
+
+libfoo.dylib : foo.c 
+       ${CC} foo.c -dynamiclib -o libfoo.dylib 
+
+hide/libfoo.dylib :
+       mkdir hide
+       touch hide/libfoo.dylib
+       
+other/libfoo.dylib :
+       mkdir other
+       touch other/libfoo.dylib
+
+main : main.c libfoo.dylib hide/libfoo.dylib other/libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c -o main 
+
+
+
+clean:
+       ${RM} ${RMFLAGS} *~  main libfoo.dylib hide other
diff --git a/unit-tests/test-cases/dlopen-search-leak/foo.c b/unit-tests/test-cases/dlopen-search-leak/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-search-leak/main.c b/unit-tests/test-cases/dlopen-search-leak/main.c
new file mode 100644 (file)
index 0000000..7a4f090
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007-2009 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 <stdlib.h>
+#include <dlfcn.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+  
+#include "test.h"
+
+
+int main()
+{
+       for (int i=0; i < 100; ++i) {
+               void* handle = dlopen("libfoo.dylib", RTLD_LAZY);
+               if ( handle != NULL ) 
+                       dlclose(handle);
+       }
+       
+       // execute leaks command on myself
+       char cmd[512];
+       sprintf(cmd, "leaks %u\n", getpid());
+       system(cmd);
+               
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/dlopen_preflight-shared-cache/Makefile b/unit-tests/test-cases/dlopen_preflight-shared-cache/Makefile
deleted file mode 100644 (file)
index 8a5e93a..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-##
-# Copyright (c) 2009 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: main 
-
-main: main.c libbar.dylib
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c 
-
-libbar.dylib : bar.c
-       ${CC} ${CCFLAGS} -dynamiclib -I${TESTROOT}/include -o libbar.dylib -lz
-
-
-clean:
-       ${RM} ${RMFLAGS} *~ main libbar.dylib
-
diff --git a/unit-tests/test-cases/dlopen_preflight-shared-cache/bar.c b/unit-tests/test-cases/dlopen_preflight-shared-cache/bar.c
deleted file mode 100644 (file)
index 8b13789..0000000
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/unit-tests/test-cases/dlopen_preflight-shared-cache/main.c b/unit-tests/test-cases/dlopen_preflight-shared-cache/main.c
deleted file mode 100644 (file)
index 6c69905..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2009 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-#include <stdbool.h>  // fprintf(), NULL
-#include <stdio.h>  // fprintf(), NULL
-#include <stdlib.h> // exit(), EXIT_SUCCESS
-#include <stdbool.h>
-#include <string.h>
-#include <mach-o/dyld.h>  
-#include <mach-o/dyld_priv.h>  
-#include <dlfcn.h>  
-
-#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
-
-
-
-int main(int argc, const char* argv[])
-{
-       // test that libbar which links with libz.dylib preflights
-       if ( ! dlopen_preflight("./libbar.dylib") ) {
-               FAIL("dlopen_preflight-basic libbar.dylib should be loadable, but got: %s", dlerror());
-               exit(0);
-       }
-
-       // test that libz.dylib itself preflights
-       if ( ! dlopen_preflight("/usr/lib/libz.dylib") ) {
-               FAIL("dlopen_preflight-basic /usr/lib/libz.dylib should be loadable, but got: %s", dlerror());
-               exit(0);
-       }
-
-       // verify libbar and libz are no longer loaded
-       uint32_t count = _dyld_image_count();
-       for (uint32_t i=0; i < count; ++i) {
-               const char* path = _dyld_get_image_name(i);
-               if ( strstr(path, "libz.") != NULL ) {
-                       FAIL("dlopen_preflight-shared-cache: %s is loaded", path);
-                       exit(0);
-               }
-       }
-
-       
-       PASS("dlopen_preflight-shared-cache");
-               
-       return EXIT_SUCCESS;
-}
index 3c40c6f45a2a22db4730e595a12fa3c7bdc646c5..f800ae4a6df3386e926226ad6bcc83c3e0c9ef42 100644 (file)
@@ -27,10 +27,16 @@ include ${TESTROOT}/include/common.makefile
 # Test that dtrace probes fire 
 #
 
 # Test that dtrace probes fire 
 #
 
+ifeq "$(OS_NAME)" "iPhoneOS"
+       SUDO = 
+else
+       SUDO = sudo
+endif
+
 all-check: all check
 
 check:
 all-check: all check
 
 check:
-       if [ `sudo dtrace -q -n 'Foo$$target:::count { printf("%u\n", arg0); } ' -c ./main | wc -w` == 5 ]; \
+       if [ `${SUDO} /usr/sbin/dtrace -q -n 'Foo$$target:::count { printf("%u\n", arg0); } ' -c ./main | wc -w` == 5 ]; \
        then \
                echo "PASS dtrace-static-probes"; \
        else \
        then \
                echo "PASS dtrace-static-probes"; \
        else \
index 00ad15684b7ac4419ebafac904766d65dacf43b7..c2a8e2e75873c4147800cd803e5ab92d4f803651 100644 (file)
@@ -31,14 +31,14 @@ check:
 all: main test.bundle test.dylib
 
 main : main.c foo.c
 all: main test.bundle test.dylib
 
 main : main.c foo.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c foo.c -mmacosx-version-min=10.5
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c foo.c 
 
 
 test.bundle : foo.c
 
 
 test.bundle : foo.c
-       ${CC} ${CCFLAGS} -bundle foo.c -o test.bundle -mmacosx-version-min=10.5
+       ${CC} ${CCFLAGS} -bundle foo.c -o test.bundle 
 
 test.dylib : foo.c
 
 test.dylib : foo.c
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o test.dylib -mmacosx-version-min=10.5
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o test.dylib 
 
 
 
 
 
 
index 00b5af3ce7ef1be0b6f080035b9d1f4639d5b7fc..bc232a2ec185d299fa782c6fa672ee57d4c5782b 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  */
 
 #include <stdbool.h>
  */
 
 #include <stdbool.h>
+#include <Availability.h>
+
+
+// _dyld_func_lookup is only available in 10.5 and earlier
+#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && (__MAC_OS_X_VERSION_MIN_REQUIRED <= __MAC_10_5)
 
 extern bool _dyld_func_lookup(const char* dyld_func_name, void** address);
 
 
 extern bool _dyld_func_lookup(const char* dyld_func_name, void** address);
 
@@ -42,3 +47,5 @@ bool check_dyld_func_lookup()
        // looks good
        return true;
 }
        // looks good
        return true;
 }
+
+#endif
index 270e34389544748f5c5b1f6de7c708b4a062697e..35bbd9ff525378f93132daa9ff6c8085aeda2361 100644 (file)
 #include <stdlib.h> // exit(), EXIT_SUCCESS
 #include <dlfcn.h>
 #include <stdbool.h>
 #include <stdlib.h> // exit(), EXIT_SUCCESS
 #include <dlfcn.h>
 #include <stdbool.h>
+#include <Availability.h>
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
+
+// _dyld_func_lookup is only available in 10.5 and earlier
+#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && (__MAC_OS_X_VERSION_MIN_REQUIRED <= __MAC_10_5)
 extern bool check_dyld_func_lookup();
 
 typedef bool (*proc)(void);
 extern bool check_dyld_func_lookup();
 
 typedef bool (*proc)(void);
@@ -53,17 +57,20 @@ static void trySO(const char* path)
        
        dlclose(handle);
 }
        
        dlclose(handle);
 }
-
+#endif
 
 
 int main()
 {
 
 
 int main()
 {
+// _dyld_func_lookup is only available in 10.5 and earlier
+#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && (__MAC_OS_X_VERSION_MIN_REQUIRED <= __MAC_10_5)
        if ( ! check_dyld_func_lookup() )
                FAIL("check_dyld_func_lookup failed for main executable");
 
        trySO("test.bundle");
        trySO("test.dylib");
        if ( ! check_dyld_func_lookup() )
                FAIL("check_dyld_func_lookup failed for main executable");
 
        trySO("test.bundle");
        trySO("test.dylib");
-  
+#endif
+
        PASS("dyld-func-lookup");
        return EXIT_SUCCESS;
 }
        PASS("dyld-func-lookup");
        return EXIT_SUCCESS;
 }
index a64d5a26c4517b224f30e67ad1e98d5d9b6b3cf8..aa6ab80e8c156f2253e475ddd974a58805024288 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <stdio.h>  // fprintf(), NULL
 #include <stdlib.h> // exit(), EXIT_SUCCESS
 #include <mach-o/dyld.h>
 #include <stdio.h>  // fprintf(), NULL
 #include <stdlib.h> // exit(), EXIT_SUCCESS
 #include <mach-o/dyld.h>
+#include <Availability.h>
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
 int
 main(int argc, const char* argv[])
 {
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
 int
 main(int argc, const char* argv[])
 {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
   _dyld_launched_prebound();
   _dyld_launched_prebound();
+#endif
   return EXIT_SUCCESS;
 }
   return EXIT_SUCCESS;
 }
index d17bbaa9f8f50121c3cd792d685a456770048ca6..aa3debfe242044c1e94a89f172c75287a74a9c64 100644 (file)
@@ -1,5 +1,5 @@
 ##
 ##
-# Copyright (c) 2005-2007 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2009 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -24,15 +24,23 @@ TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
 STACK_BASE = 0x8fe01000
 include ${TESTROOT}/include/common.makefile
 
 STACK_BASE = 0x8fe01000
+STACK_SIZE = 0x00100000
 
 ifeq "armv6" "$(ARCH)"
        STACK_BASE = 0x2fe01000
 
 ifeq "armv6" "$(ARCH)"
        STACK_BASE = 0x2fe01000
+       STACK_SIZE = 0x00100000
+endif
+ifeq "armv7" "$(ARCH)"
+       STACK_BASE = 0x2fe01000
+       STACK_SIZE = 0x00100000
 endif
 ifeq "ppc64" "$(ARCH)"
 endif
 ifeq "ppc64" "$(ARCH)"
-       STACK_BASE = 0x7fff5fc00000
+       STACK_BASE = 0x7fff5ff00000
+       STACK_SIZE = 0x00400000
 endif
 ifeq "x86_64" "$(ARCH)"
 endif
 ifeq "x86_64" "$(ARCH)"
-       STACK_BASE = 0x7fff5fc00000
+       STACK_BASE = 0x7fff5ff00000
+       STACK_SIZE = 0x00400000
 endif
 
 
 endif
 
 
@@ -43,7 +51,7 @@ check:
        ${TESTROOT}/bin/exit-zero-pass.pl "dyld did slide" "dyld did not slide" ./main
 
 all:
        ${TESTROOT}/bin/exit-zero-pass.pl "dyld did slide" "dyld did not slide" ./main
 
 all:
-       ${CC} ${CCFLAGS} -Wno-deprecated-declarations -I${TESTROOT}/include -o main main.c -Wl,-stack_addr,${STACK_BASE} -Wl,-stack_size,0x00100000
+       ${CC} ${CCFLAGS} -Wno-deprecated-declarations -I${TESTROOT}/include -o main main.c -Wl,-stack_addr,${STACK_BASE} -Wl,-stack_size,${STACK_SIZE}
 
 clean:
        ${RM} ${RMFLAGS} main
 
 clean:
        ${RM} ${RMFLAGS} main
index 2bd67bad01ea25948eb8b7619ad436f3a56da6ab..a689f63105e548ed61bf025238431c967d04f1c2 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2005-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -21,7 +21,8 @@
  * @APPLE_LICENSE_HEADER_END@
  */
 #include <stdlib.h> // EXIT_SUCCESS
  * @APPLE_LICENSE_HEADER_END@
  */
 #include <stdlib.h> // EXIT_SUCCESS
-#include <mach-o/dyld.h>
+#include <dlfcn.h>
+#include <mach-o/dyld_priv.h>
 
 #include "test.h"
 
 
 #include "test.h"
 
@@ -39,9 +40,9 @@
 int
 main()
 {
 int
 main()
 {
-       // call a dyld function that will internally throw an exception to test dyld slide properly
-       NSAddImage("/foo/bar", NSADDIMAGE_OPTION_RETURN_ON_ERROR);
-       
+       // call a dyld function that will execute lots of code and bus error dyld was not slid
+       dlsym(RTLD_DEFAULT, "foobar");
+
        return EXIT_SUCCESS;
 }
 
        return EXIT_SUCCESS;
 }
 
index af3f2b9ea49dd67228d9c357084228032de0bf08..dccb78c566957fc40f9e7217408203aa2d4205e6 100644 (file)
@@ -1,5 +1,5 @@
 ##
 ##
-# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2006-2009 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 # 
 # @APPLE_LICENSE_HEADER_END@
 ##
 # 
 # @APPLE_LICENSE_HEADER_END@
 ##
-TESTROOT = ../..
+PWD = $(shell pwd)
+TESTROOT = $(PWD)/../..
 include ${TESTROOT}/include/common.makefile
 
 include ${TESTROOT}/include/common.makefile
 
+ifeq "$(OS_NAME)" "iPhoneOS"
+       RUN_AS_USER = login -f -l mobile
+else
+       RUN_AS_USER = 
+endif
+
 all-check: all check
 
 check:
 all-check: all check
 
 check:
-       ${TESTROOT}/bin/exit-non-zero-pass.pl "fallback-with-suid" "fallback-with-suid" ./main-suid
+       ${RUN_AS_USER} ${PASS_IFF_FAILURE} "fallback-with-suid" "fallback-with-suid" $(PWD)/main-suid
        
 all: main-suid
 
        
 all: main-suid
 
index caf93e98bdccf66c47f9ed8cc26bae1ca2feb734..6fe230bb826d1cefc1af9959a4c45897ed0d01a7 100644 (file)
@@ -1,5 +1,5 @@
 ##
 ##
-# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2005-2009 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -35,11 +35,11 @@ main : main.c libfoo.dylib
 
 
 libfoo.dylib : foo.c libbar.dylib
 
 
 libfoo.dylib : foo.c libbar.dylib
-       ${CC} ${CCFLAGS} -mmacosx-version-min=10.2 -dynamiclib foo.c -o libfoo.dylib libbar.dylib -flat_namespace -prebind -seg1addr 20000
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib libbar.dylib -flat_namespace -prebind -seg1addr 20000
 
 
 libbar.dylib : bar.c
 
 
 libbar.dylib : bar.c
-       ${CC} ${CCFLAGS} -mmacosx-version-min=10.2 -dynamiclib bar.c -o libbar.dylib -prebind -seg1addr 30000
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -prebind -seg1addr 30000
 
 
 
 
 
 
index 904aeb38438d11a28b68eeb32bdcf8d4e2606ef9..fdaa89366a485749fa7b5525ed3da1876f989f80 100644 (file)
 int
 main(int argc, const char* argv[])
 {
 int
 main(int argc, const char* argv[])
 {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        const struct mach_header *image;
 
        image = NSAddImage("AppKit.framework/AppKit",
                        NSADDIMAGE_OPTION_RETURN_ON_ERROR | NSADDIMAGE_OPTION_WITH_SEARCHING);
        const struct mach_header *image;
 
        image = NSAddImage("AppKit.framework/AppKit",
                        NSADDIMAGE_OPTION_RETURN_ON_ERROR | NSADDIMAGE_OPTION_WITH_SEARCHING);
-       if ( image != NULL )
-               PASS("AppKit loaded");
-       else
+       if ( image == NULL )
                FAIL("Could not load AppKit");
                FAIL("Could not load AppKit");
+       else
+#endif
+               PASS("AppKit loaded");
 
        return 0;
 }
 
        return 0;
 }
diff --git a/unit-tests/test-cases/image-count/Makefile b/unit-tests/test-cases/image-count/Makefile
new file mode 100644 (file)
index 0000000..115f7fe
--- /dev/null
@@ -0,0 +1,17 @@
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+
+all-check: all check
+
+check:
+       ./main
+
+all:
+       ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c -I../../../include
+
+clean:
+       ${RM} ${RMFLAGS} main libfoo.dylib
diff --git a/unit-tests/test-cases/image-count/foo.c b/unit-tests/test-cases/image-count/foo.c
new file mode 100644 (file)
index 0000000..c1f5255
--- /dev/null
@@ -0,0 +1,2 @@
+void foo() {}
+
diff --git a/unit-tests/test-cases/image-count/main.c b/unit-tests/test-cases/image-count/main.c
new file mode 100644 (file)
index 0000000..06740b9
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * 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> // EXIT_SUCCESS
+#include <stdio.h> 
+#include <dlfcn.h> 
+#include <mach-o/dyld.h>
+#include <mach-o/dyld_images.h>
+
+#include "test.h"
+
+extern struct mach_header __dso_handle;
+
+
+struct dyld_all_image_infos* getImageInfosFromKernel()
+{
+       task_dyld_info_data_t task_dyld_info;
+       mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
+    
+    if ( task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&task_dyld_info, &count) ) {
+               FAIL("all_image_infos: task_info() failed");
+               exit(0);
+       }
+       return (struct dyld_all_image_infos*)(uintptr_t)task_dyld_info.all_image_info_addr;
+}
+
+
+int
+main()
+{
+       struct dyld_all_image_infos* info = getImageInfosFromKernel();
+       if ( info->version < 10 ) {
+               FAIL("image-count: dyld_all_image_infos is < 10");
+               exit(0);
+       }
+
+       if ( info->infoArrayCount !=  info->initialImageCount ) {
+               FAIL("image-count: dyld_all_image_infos.infoArrayCount != dyld_all_image_infos.initialImageCount");
+               exit(0);
+       }
+
+       void* h = dlopen("libfoo.dylib", RTLD_LAZY);
+       if ( h == NULL ) {
+               FAIL("image-count: dyld_all_image_infos is < 10");
+               exit(0);
+       }
+
+       if ( info->infoArrayCount != (info->initialImageCount+1) ) {
+               FAIL("image-count: infoArrayCount did not increment when libfoo.dylib was loaded");
+               exit(0);
+       }
+
+       dlclose(h);
+       
+       if ( info->infoArrayCount !=  info->initialImageCount ) {
+               FAIL("image-count: infoArrayCount did not decrement when libfoo.dylib was unloaded");
+               exit(0);
+       }
+
+       PASS("image-count");
+       return EXIT_SUCCESS;
+}
+
+
index 3e1f3419850f6d76235a3a9ca70ccc8da58824ea..37eb8d7a8e5ec64cd1309cdd4fe9590ce09ca185 100644 (file)
@@ -31,6 +31,9 @@
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+
 static bool doneRegistering = false;
 
 //
 static bool doneRegistering = false;
 
 //
@@ -92,10 +95,13 @@ static void load(const char* name)
                }
        }
 }
                }
        }
 }
+#endif
 
 
 int main(int argc, const char* argv[])
 {
 
 
 int main(int argc, const char* argv[])
 {
+// NSCreateObjectFileImageFromMemory is only available on Mac OS X - not iPhone OS
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        // tell dyld we want to know when images successfully loaded
        dyld_register_image_state_change_handler(dyld_image_state_initialized, false, singleInitializedHandler);
        doneRegistering = true;
        // tell dyld we want to know when images successfully loaded
        dyld_register_image_state_change_handler(dyld_image_state_initialized, false, singleInitializedHandler);
        doneRegistering = true;
@@ -125,6 +131,7 @@ int main(int argc, const char* argv[])
        }
 
 //     dlopen("/usr/lib/libz.1.2.3.dylib", RTLD_LAZY);
        }
 
 //     dlopen("/usr/lib/libz.1.2.3.dylib", RTLD_LAZY);
+#endif
        
        PASS("image-state-deny");
                
        
        PASS("image-state-deny");
                
index 79edd75f3d536948945b9145dd93218f8f33dc27..28b4c8e65e192fbfd52272376301090425fa8fa0 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -33,7 +33,7 @@ int main(int argc, const char* argv[])
        }
 
        uint32_t imageCount = _dyld_image_count();
        }
 
        uint32_t imageCount = _dyld_image_count();
-       const struct mach_header* mh = NSAddImage(argv[1], 0);
+       dlopen(argv[1], 0);
        if ( imageCount != _dyld_image_count() ) {
                FAIL("image count changed");
                return EXIT_SUCCESS;
        if ( imageCount != _dyld_image_count() ) {
                FAIL("image count changed");
                return EXIT_SUCCESS;
diff --git a/unit-tests/test-cases/initializer-bounds-check/Makefile b/unit-tests/test-cases/initializer-bounds-check/Makefile
new file mode 100644 (file)
index 0000000..aa35765
--- /dev/null
@@ -0,0 +1,38 @@
+##
+# 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
+
+all-check: all check
+
+check:
+       ./main 
+       
+all:
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include bar.c -dynamiclib -o libbar.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include foo1.c foo2.c libbar.dylib -dynamiclib -o libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c libfoo.dylib libbar.dylib -o main 
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libbar.dylib libfoo.dylib
+
diff --git a/unit-tests/test-cases/initializer-bounds-check/bar.c b/unit-tests/test-cases/initializer-bounds-check/bar.c
new file mode 100644 (file)
index 0000000..12846f3
--- /dev/null
@@ -0,0 +1,7 @@
+
+int bar = 0;
+
+void altSecondInit()
+{
+       bar = 1;
+}
diff --git a/unit-tests/test-cases/initializer-bounds-check/foo1.c b/unit-tests/test-cases/initializer-bounds-check/foo1.c
new file mode 100644 (file)
index 0000000..5333718
--- /dev/null
@@ -0,0 +1,14 @@
+#include <stdio.h>
+
+extern void* initializers[] __asm__("section$start$__DATA$__mod_init_func");
+
+extern void altSecondInit();
+
+
+__attribute__((constructor))
+void firstInit()
+{
+       // slam second initializer to be pointer into another dylib
+       initializers[1] = &altSecondInit;
+}
+
diff --git a/unit-tests/test-cases/initializer-bounds-check/foo2.c b/unit-tests/test-cases/initializer-bounds-check/foo2.c
new file mode 100644 (file)
index 0000000..ea8cf54
--- /dev/null
@@ -0,0 +1,12 @@
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+__attribute__((constructor))
+void secondInit()
+{
+       FAIL("initializer-bounds-check, second init called");
+       exit(0);
+}
+
diff --git a/unit-tests/test-cases/initializer-bounds-check/main.c b/unit-tests/test-cases/initializer-bounds-check/main.c
new file mode 100644 (file)
index 0000000..f466342
--- /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()
+
+extern int bar;
+
+int
+main()
+{
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
+       if ( bar == 1 )
+               FAIL("initializer-bounds-check, out of bounds initializer called");
+       else
+               PASS("initializer-bounds-check");
+#else
+               PASS("initializer-bounds-check");
+#endif
+  return EXIT_SUCCESS;
+}
index 1380ba99c43451bbf5e3effdd0bb813cbdeb1169..b270917c5e946eb36af4dd643dde5050a180f948 100644 (file)
@@ -1,5 +1,5 @@
 ##
 ##
-# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2005-2009 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
+PWD = `pwd`
+
+ifeq "$(OS_NAME)" "iPhoneOS"
+       RUN_AS_USER = login -f -l mobile
+else
+       RUN_AS_USER = 
+endif
+
 all-check: all check
 
 check:
 all-check: all check
 
 check:
-       export DYLD_INSERT_LIBRARIES="/usr/lib/libldap.dylib:/usr/lib/libpcap.dylib" && ./main
+       ${RUN_AS_USER} $(PWD)/main-with-env
 
 all: main
 
 
 all: main
 
@@ -34,7 +42,11 @@ main: main.c
        ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
        sudo chown root main
        sudo chmod 4755 main
        ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
        sudo chown root main
        sudo chmod 4755 main
+       echo "#!/bin/sh" > main-with-env
+       echo "export DYLD_INSERT_LIBRARIES=/usr/lib/libz.dylib" >> main-with-env
+       echo "$(PWD)/main" >> main-with-env
+       chmod +x main-with-env
 
 clean:
 
 clean:
-       ${RM} ${RMFLAGS} *~ main
+       ${RM} ${RMFLAGS} *~ main main-with-env
 
 
index 141931fe13f4c4d8ef66bc03eb6629dd4c48cf1a..f8600b477bbb64fa58ecb5b430b360fb9cad4eb8 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <stdio.h>
 #include <stdlib.h>
 #include <mach-o/dyld.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <mach-o/dyld.h>
+#include <Availability.h>
+#include <dlfcn.h>
 
 #include "test.h"
 
 
 int main()
 {
 
 #include "test.h"
 
 
 int main()
 {
+#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && (__MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_5)
        NSAddImage("@loader_path/hide/libfoo3.dylib", 0);
        NSAddImage("@loader_path/hide/libfoo3.dylib", 0);
-
-       PASS("loader_path");
+#else
+       if ( dlopen("@loader_path/hide/libfoo3.dylib", 0) == NULL )
+               FAIL("loader_path");
+       else
+#endif
+               PASS("loader_path");
        return EXIT_SUCCESS;
 }
        return EXIT_SUCCESS;
 }
index 0c815549cedc6e59f8cd60f209eda8b4f25effef..9993ac408ce4bd86b4f8c8e2e6a0932d67388796 100644 (file)
@@ -29,6 +29,8 @@
 
 int main()
 {
 
 int main()
 {
+// NSCreateObjectFileImageFromMemory is only available on Mac OS X - not iPhone OS
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        // load bundle which indirectly loads libfoo and libbar
        NSObjectFileImage ofi;
        if ( NSCreateObjectFileImageFromFile("test.bundle", &ofi) != NSObjectFileImageSuccess ) {
        // load bundle which indirectly loads libfoo and libbar
        NSObjectFileImage ofi;
        if ( NSCreateObjectFileImageFromFile("test.bundle", &ofi) != NSObjectFileImageSuccess ) {
@@ -48,7 +50,7 @@ int main()
        if ( mh != NULL ) {
                return 1;
        }
        if ( mh != NULL ) {
                return 1;
        }
-       
+#endif
 #if 0  
        // find foo
        NSSymbol sym = NSLookupSymbolInImage(mh, "_foo", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND);
 #if 0  
        // find foo
        NSSymbol sym = NSLookupSymbolInImage(mh, "_foo", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND);
diff --git a/unit-tests/test-cases/pie-DYLD_NO_PIE/Makefile b/unit-tests/test-cases/pie-DYLD_NO_PIE/Makefile
deleted file mode 100644 (file)
index f3fd51e..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-
-TESTROOT = ../..
-include ${TESTROOT}/include/common.makefile
-
-
-#
-# <rdar://problem/5807857> there should be some way to temporarily turn off -pie
-#
-# run a PIE four times and verify its load address was the same every time
-#
-
-all-check: all check
-
-check:
-       export DYLD_NO_PIE=1 && ./main > main.out
-       export DYLD_NO_PIE=1 && ./main >> main.out
-       export DYLD_NO_PIE=1 && ./main >> main.out
-       export DYLD_NO_PIE=1 && ./main >> main.out
-       if [ `sort main.out -u | wc -l` == 1 ]; \
-       then \
-               echo "PASS pie-DYLD_NO_PIE"; \
-       else \
-               echo "FAIL pie-DYLD_NO_PIE"; \
-       fi; \
-        
-all: main
-
-main : main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -Wl,-pie -o main main.c
-
-
-clean:
-       ${RM} ${RMFLAGS} *~ main main.out
-
diff --git a/unit-tests/test-cases/pie-DYLD_NO_PIE/main.c b/unit-tests/test-cases/pie-DYLD_NO_PIE/main.c
deleted file mode 100644 (file)
index 3a6571d..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 2007 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>
-
-int main()
-{
-       //int local;
-       
-       printf("&main=%p\n", &main);
-       //printf("&local=%p\n",&local);
-       return 0;
-}
index 0c6c45520819c8677de47255593bc71c8c37a631..bac7b71bfc620d866f08d48fe58c1988e81e7b9b 100644 (file)
@@ -42,7 +42,7 @@ check:
 all: main
 
 main : main.c
 all: main
 
 main : main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -Wl,-pie -o main main.c -mmacosx-version-min=10.5
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -Wl,-pie -o main main.c 
 
 
 clean:
 
 
 clean:
index b29599453ebe700fd4fbf0dd517fad3bb6b5d7e1..e8a5fd0503ee61d3264d135db80818f2afbb630d 100644 (file)
@@ -42,7 +42,7 @@ check:
 all: main
 
 main : main.c
 all: main
 
 main : main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -Wl,-pie -o main main.c -mmacosx-version-min=10.5
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -Wl,-pie -o main main.c
 
 
 clean:
 
 
 clean:
index f7e3b8812d637fb0136659c15379f0164a5f446d..49d9a882662b90c351969bef3333537f632bca16 100644 (file)
  */
 #include <stdio.h>
 #include <stdbool.h>
  */
 #include <stdio.h>
 #include <stdbool.h>
+#include <Availability.h>
 
 
-char bigarray[1500000000];
-
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
+char bigarray[0x10000000];     // 0.25GB
+#else
+       #if __LP64__
+               char bigarray[0xF0000000];      // 4GB
+       #else
+               char bigarray[0x30000000];      // 0.75GB
+       #endif
+#endif
 
 int main()
 {
 
 int main()
 {
index 7c68dbce08bd9da0606a75c6e7d66b32909b32ae..e795c80d86103eb6adba5dccbe1a821afeb65153 100644 (file)
@@ -42,7 +42,7 @@ check:
 all: main
 
 main : main.c
 all: main
 
 main : main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -Wl,-pie -o main main.c -mmacosx-version-min=10.5 -Wl,-stack_size,0x10000000
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -Wl,-pie -o main main.c -Wl,-stack_size,0x10000000
 
 
 clean:
 
 
 clean:
index 497174e9994d34966cfba09dfd1462e4f57817b7..a83adcd1e9f6bdb4f7f4fac6dfdc901a25c9f8af 100644 (file)
@@ -1,5 +1,5 @@
 ##
 ##
-# Copyright (c) 2007-2008 Apple Inc. All rights reserved.
+# Copyright (c) 2007-2009 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -41,15 +41,15 @@ check:
        ./main >> main.out
        if [ `sort main.out -u | wc -l` == 4 ]; \
        then \
        ./main >> main.out
        if [ `sort main.out -u | wc -l` == 4 ]; \
        then \
-               echo "PASS pie-basic"; \
+               echo "PASS pie-text-reloc"; \
        else \
        else \
-               echo "FAIL pie-basic"; \
+               echo "FAIL pie-text-reloc"; \
        fi; \
         
 all: main
 
 main : main.c
        fi; \
         
 all: main
 
 main : main.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -Wl,-pie  $(EXTRA_OPTIONS) -o main main.c -mmacosx-version-min=10.5
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -Wl,-pie  $(EXTRA_OPTIONS) -o main main.c 
 
 
 clean:
 
 
 clean:
index a3edccc26df4614af2fd2cbe6c8c624bb9c1a02d..ce0d7d94310bbf1e8115823b536db0dde404fadb 100644 (file)
@@ -43,10 +43,10 @@ check:
 all: main 
 
 main: main.c libfoo.dylib
 all: main 
 
 main: main.c libfoo.dylib
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libfoo.dylib -Wl,-no_pie
 
 libfoo.dylib: foo.c
 
 libfoo.dylib: foo.c
-       ${CC} ${CCFLAGS} -dynamiclib -o libfoo.dylib foo.c -seg1addr ${DYLIB_BASES_ADDRESS} -mmacosx-version-min=10.5
+       ${CC} ${CCFLAGS} -dynamiclib -o libfoo.dylib foo.c -seg1addr ${DYLIB_BASES_ADDRESS}
 
 
 clean:
 
 
 clean:
index da9f97a06f66fbffafeae5c094879f7ca2b9dfa1..5cea7a1e98b08f7af43173282f9f09354ff6912c 100644 (file)
@@ -1,5 +1,5 @@
 ##
 ##
-# Copyright (c) 2007 Apple Inc. All rights reserved.
+# Copyright (c) 2007-2009 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -27,38 +27,28 @@ PWD = `pwd`
 
 
 #
 
 
 #
-# Test that the 10.4 and 10.5 ways to re-export a dylib work
+# Test that dylib re-exports work
 #
 
 all-check: all check
 
 check:
 #
 
 all-check: all check
 
 check:
-       ./main4
-       ./main5
+       ./main
 
 
-all: main4 main5
+all: main
 
 
-libbar4.dylib : bar.c
-       ${CC} bar.c -dynamiclib -o $(PWD)/libbar4.dylib -mmacosx-version-min=10.4
 
 
-libfoo4.dylib : foo.c libbar4.dylib
-       ${CC} foo.c -dynamiclib libbar4.dylib -sub_library libbar4 -install_name $(PWD)/libfoo4.dylib -o libfoo4.dylib -mmacosx-version-min=10.4
 
 
-main4 : main.c libfoo4.dylib
-       ${CC} main.c -I${TESTROOT}/include -o main4 libfoo4.dylib -mmacosx-version-min=10.4
+libbar.dylib : bar.c
+       ${CC} bar.c -dynamiclib -o $(PWD)/libbar.dylib 
 
 
+libfoo.dylib : foo.c libbar.dylib
+       ${CC} foo.c -dynamiclib libbar.dylib -sub_library libbar -install_name $(PWD)/libfoo.dylib -o libfoo.dylib 
 
 
-
-libbar5.dylib : bar.c
-       ${CC} bar.c -dynamiclib -o $(PWD)/libbar5.dylib -mmacosx-version-min=10.5
-
-libfoo5.dylib : foo.c libbar5.dylib
-       ${CC} foo.c -dynamiclib libbar5.dylib -sub_library libbar5 -install_name $(PWD)/libfoo5.dylib -o libfoo5.dylib -mmacosx-version-min=10.5
-
-main5 : main.c libfoo5.dylib
-       ${CC} main.c -I${TESTROOT}/include -o main5 libfoo5.dylib -mmacosx-version-min=10.5
+main : main.c libfoo.dylib
+       ${CC} main.c -I${TESTROOT}/include -o main libfoo.dylib 
 
        
 clean:
 
        
 clean:
-       rm -rf main4 main5 libfoo4.dylib libfoo5.dylib libbar4.dylib libbar5.dylib
+       rm -rf main libfoo.dylib libbar.dylib
        
\ No newline at end of file
        
\ No newline at end of file
index 7082b05d6c1ccf7c9fab92f56da779c047773fb3..9e5cea63d9a369e05cb1e344548e981b194f080f 100644 (file)
@@ -1,5 +1,5 @@
 ##
 ##
-# Copyright (c) 2007 Apple Inc. All rights reserved.
+# Copyright (c) 2007-2009 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -27,44 +27,32 @@ PWD = `pwd`
 
 
 #
 
 
 #
-# Test that the 10.4 and 10.5 ways to re-export a framework work
+# Test re-exported frameworks work
 #
 
 all-check: all check
 
 check:
 #
 
 all-check: all check
 
 check:
-       ./main4
-       ./main5
+       ./main
 
 
-all: main4 main5
+all:  main
 
 
-Bar4.framework/Bar4 : bar.c
-       mkdir -p Bar4.framework
-       ${CC} bar.c -dynamiclib -install_name $(PWD)/Bar4.framework/Bar4 -o Bar4.framework/Bar4 -mmacosx-version-min=10.4
 
 
-Foo4.framework/Foo4 : foo.c Bar4.framework/Bar4
-       mkdir -p Foo4.framework
-       ${CC} foo.c -dynamiclib Bar4.framework/Bar4 -sub_umbrella Bar4 -install_name $(PWD)/Foo4.framework/Foo4 -o Foo4.framework/Foo4 -mmacosx-version-min=10.4
 
 
-main4 : main.c Foo4.framework/Foo4
-       ${CC} main.c -I${TESTROOT}/include -o main4 -framework Foo4 -F. -mmacosx-version-min=10.4
+Bar.framework/Bar : bar.c
+       mkdir -p Bar.framework
+       ${CC} bar.c -dynamiclib -install_name $(PWD)/Bar.framework/Bar -o Bar.framework/Bar 
 
 
+Foo.framework/Foo : foo.c Bar.framework/Bar
+       mkdir -p Foo.framework
+       ${CC} foo.c -dynamiclib Bar.framework/Bar -sub_umbrella Bar -install_name $(PWD)/Foo.framework/Foo -o Foo.framework/Foo 
 
 
-
-Bar5.framework/Bar5 : bar.c
-       mkdir -p Bar5.framework
-       ${CC} bar.c -dynamiclib -install_name $(PWD)/Bar5.framework/Bar5 -o Bar5.framework/Bar5 -mmacosx-version-min=10.5
-
-Foo5.framework/Foo5 : foo.c Bar5.framework/Bar5
-       mkdir -p Foo5.framework
-       ${CC} foo.c -dynamiclib Bar5.framework/Bar5 -sub_umbrella Bar5 -install_name $(PWD)/Foo5.framework/Foo5 -o Foo5.framework/Foo5 -mmacosx-version-min=10.5
-
-main5 : main.c Foo5.framework/Foo5
-       ${CC} main.c -I${TESTROOT}/include -o main5 -framework Foo5 -F. -mmacosx-version-min=10.5
+main : main.c Foo.framework/Foo
+       ${CC} main.c -I${TESTROOT}/include -o main -framework Foo -F.
 
 
 
        
 clean:
 
 
 
        
 clean:
-       rm -rf main4 Foo4.framework Bar4.framework main5 Foo5.framework Bar5.framework 
+       rm -rf  main Foo.framework Bar.framework 
        
\ No newline at end of file
        
\ No newline at end of file
index c2f76e75cec147ca3bfe4e04f5a6b5c5a7dd3887..d77a60722095446202aa9412733f826ec9ac3fca 100644 (file)
@@ -1,5 +1,5 @@
 ##
 ##
-# Copyright (c) 2007 Apple Inc. All rights reserved.
+# Copyright (c) 2007-2009 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -27,42 +27,30 @@ PWD = `pwd`
 
 
 #
 
 
 #
-# Test that the 10.4 and 10.5 ways to re-export a sub framework work
+# Test that the ways to re-export a sub framework work
 #
 
 all-check: all check
 
 check:
 #
 
 all-check: all check
 
 check:
-       ./main4
-       ./main5
+       ./main
 
 
-all: main4 main5
+all:  main
 
 
-Bar4.framework/Bar4 : bar.c
-       mkdir -p Bar4.framework
-       ${CC} bar.c -dynamiclib -install_name $(PWD)/Bar4.framework/Bar4 -o Bar4.framework/Bar4 -umbrella Foo4 -mmacosx-version-min=10.4
 
 
-Foo4.framework/Foo4 : foo.c Bar4.framework/Bar4
-       mkdir -p Foo4.framework
-       ${CC} foo.c -dynamiclib Bar4.framework/Bar4 -install_name $(PWD)/Foo4.framework/Foo4 -o Foo4.framework/Foo4 -mmacosx-version-min=10.4
+Bar.framework/Bar : bar.c
+       mkdir -p Bar.framework
+       ${CC} bar.c -dynamiclib -install_name $(PWD)/Bar.framework/Bar  -o Bar.framework/Bar -umbrella Foo 
 
 
-main4 : main.c Foo4.framework/Foo4
-       ${CC} main.c -I${TESTROOT}/include -o main4 -framework Foo4 -F. -mmacosx-version-min=10.4
+Foo.framework/Foo : foo.c Bar.framework/Bar
+       mkdir -p Foo.framework
+       ${CC} foo.c -dynamiclib Bar.framework/Bar -install_name $(PWD)/Foo.framework/Foo -o Foo.framework/Foo 
 
 
-
-Bar5.framework/Bar5 : bar.c
-       mkdir -p Bar5.framework
-       ${CC} bar.c -dynamiclib -install_name $(PWD)/Bar5.framework/Bar5  -o Bar5.framework/Bar5 -umbrella Foo5 -mmacosx-version-min=10.5
-
-Foo5.framework/Foo5 : foo.c Bar5.framework/Bar5
-       mkdir -p Foo5.framework
-       ${CC} foo.c -dynamiclib Bar5.framework/Bar5 -install_name $(PWD)/Foo5.framework/Foo5 -o Foo5.framework/Foo5 -mmacosx-version-min=10.5
-
-main5 : main.c Foo5.framework/Foo5
-       ${CC} main.c -I${TESTROOT}/include -o main5 -framework Foo5 -F. -mmacosx-version-min=10.5
+main : main.c Foo.framework/Foo
+       ${CC} main.c -I${TESTROOT}/include -o main -framework Foo -F. 
 
 
        
 clean:
 
 
        
 clean:
-       rm -rf main4 Foo4.framework Bar4.framework main5 Foo5.framework Bar5.framework 
+       rm -rf  main Foo.framework Bar.framework 
        
\ No newline at end of file
        
\ No newline at end of file
diff --git a/unit-tests/test-cases/re-export-symbol/Makefile b/unit-tests/test-cases/re-export-symbol/Makefile
new file mode 100644 (file)
index 0000000..3be2415
--- /dev/null
@@ -0,0 +1,62 @@
+##
+# 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 fine grain re-exports works
+#
+
+all-check: all_$(OS_BAROLO_FEATURES) check_$(OS_BAROLO_FEATURES)
+
+all: all_$(OS_BAROLO_FEATURES)
+
+check: check_$(OS_BAROLO_FEATURES)
+
+check_1:
+       ./main1
+       ./main2
+
+all_1:
+       # build base library
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o `pwd`/libbar.dylib
+
+       # build library the re-exports _bar from base library
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib libbar.dylib -exported_symbols_list foo.exp
+       # link against dylib and verify _bar is marked as coming from libfoo
+       ${CC} ${CCFLAGS} main1.c -I${TESTROOT}/include libfoo.dylib -o main1
+
+       # build library the re-exports _bar from base library as _mybar
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo2.dylib libbar.dylib -Wl,-alias,_bar,_mybar -exported_symbols_list foo2.exp
+       # link against dylib and verify _mybar is marked as coming from libfoo
+       ${CC} ${CCFLAGS} main2.c -I${TESTROOT}/include libfoo2.dylib -o main2
+
+check_:
+       ${PASS_IFF} true
+
+all_:
+       
+clean:
+       rm -rf libbar.dylib libfoo.dylib libfoo2.dylib  main1 main2
diff --git a/unit-tests/test-cases/re-export-symbol/bar.c b/unit-tests/test-cases/re-export-symbol/bar.c
new file mode 100644 (file)
index 0000000..f5837c1
--- /dev/null
@@ -0,0 +1,5 @@
+
+int bar(void)
+{
+       return 10;
+}
diff --git a/unit-tests/test-cases/re-export-symbol/foo.c b/unit-tests/test-cases/re-export-symbol/foo.c
new file mode 100644 (file)
index 0000000..9232d4c
--- /dev/null
@@ -0,0 +1,4 @@
+int foo(void)
+{
+       return 10;
+}
diff --git a/unit-tests/test-cases/re-export-symbol/foo.exp b/unit-tests/test-cases/re-export-symbol/foo.exp
new file mode 100644 (file)
index 0000000..b9e50b8
--- /dev/null
@@ -0,0 +1,2 @@
+_foo
+_bar
diff --git a/unit-tests/test-cases/re-export-symbol/foo2.exp b/unit-tests/test-cases/re-export-symbol/foo2.exp
new file mode 100644 (file)
index 0000000..d55b748
--- /dev/null
@@ -0,0 +1,2 @@
+_foo
+_mybar
diff --git a/unit-tests/test-cases/re-export-symbol/main1.c b/unit-tests/test-cases/re-export-symbol/main1.c
new file mode 100644 (file)
index 0000000..cd2bab7
--- /dev/null
@@ -0,0 +1,23 @@
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+extern int foo();
+extern int bar();
+
+int (*pbar)() = &bar;
+
+
+int main()
+{
+       if ( foo() != 10 )
+               FAIL("re-export-symbol: foo() returned wrong value");
+       if ( bar() != 10 )
+               FAIL("re-export-symbol: bar() returned wrong value");
+       if ( (*pbar)() != 10 )
+               FAIL("re-export-symbol: (*pbar)() returned wrong value");
+       PASS("re-export-symbol");
+       return 0;
+}
diff --git a/unit-tests/test-cases/re-export-symbol/main2.c b/unit-tests/test-cases/re-export-symbol/main2.c
new file mode 100644 (file)
index 0000000..7a11c92
--- /dev/null
@@ -0,0 +1,26 @@
+
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+
+extern int foo();
+extern int mybar();
+
+int (*pmybar)() = &mybar;
+
+int main()
+{
+       if ( foo() != 10 )
+               FAIL("re-export-symbol: foo() returned wrong value");
+       if ( mybar() != 10 )
+               FAIL("re-export-symbol: mybar() returned wrong value");
+       if ( (*pmybar)() != 10 )
+               FAIL("re-export-symbol: (*pmybar)() returned wrong value");
+       PASS("re-export-symbol");
+       return 0;
+}
+
diff --git a/unit-tests/test-cases/read-only-import-shared-cache-override/Makefile b/unit-tests/test-cases/read-only-import-shared-cache-override/Makefile
deleted file mode 100644 (file)
index e0e6bcb..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-##
-# Copyright (c) 2007 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:
-       cp /usr/lib/libSystem.B.dylib ./libSystem.B.dylib
-       export DYLD_LIBRARY_PATH=`pwd` && ./main
-
-all: main 
-
-main: main.c libfoo.dylib
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include  -o main main.c
-
-libfoo.dylib : foo.c
-       ${CC} ${CCFLAGS} -dynamiclib -I${TESTROOT}/include -o libfoo.dylib foo.c -framework CoreFoundation
-
-
-
-clean:
-       ${RM} ${RMFLAGS} *~ main libSystem.B.dylib libfoo.dylib 
-       
-
diff --git a/unit-tests/test-cases/read-only-import-shared-cache-override/foo.c b/unit-tests/test-cases/read-only-import-shared-cache-override/foo.c
deleted file mode 100644 (file)
index a5b10db..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-
-#include <strings.h>
-#include <CoreFoundation/CoreFoundation.h>
-
-#include "test.h"
-
-void __attribute__((constructor)) init()
-{
-       uintptr_t libSysFuncAddr = (uintptr_t)&strcmp;
-       uintptr_t cfFuncAddr     = (uintptr_t)&CFStringGetTypeID;
-       //fprintf(stderr, "libSysFuncAddr=0x%0lX, cfFuncAddr=0x%0lX\n", libSysFuncAddr, cfFuncAddr);
-       if ( cfFuncAddr - libSysFuncAddr < 256*1024*1024 )
-               FAIL("read-only-import-shared-cache-override");
-       else
-               PASS("read-only-import-shared-cache-override");
-}      
-
-
-
diff --git a/unit-tests/test-cases/read-only-import-shared-cache-override/main.c b/unit-tests/test-cases/read-only-import-shared-cache-override/main.c
deleted file mode 100644 (file)
index 9b3996c..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#include <dlfcn.h>
-#include "test.h"
-
-int main()
-{
-#if __arm__
-       // no shared cache on iPhone, so skip test
-       PASS("read-only-import-shared-cache-override");
-#else
-       // dynamically load libfoo.dylib which depends on libstdc++.dylib 
-       // being re-bound to libfoo's operator new.
-       dlopen("libfoo.dylib", RTLD_LAZY);
-#endif
-       return 0;
-}      
-
index c5f12e7e4194ff704e0c0b801c2b3e7eb90da788..68fb1fb960b0c00cbda4c688a02e6efe1205bae2 100644 (file)
@@ -74,7 +74,10 @@ static void* getStubAddr()
 #elif __x86_64__
        return getsectdatafromheader_64(&_mh_dylib_header, "__TEXT", "__symbol_stub1", &size) + slide;
 #elif __arm__
 #elif __x86_64__
        return getsectdatafromheader_64(&_mh_dylib_header, "__TEXT", "__symbol_stub1", &size) + slide;
 #elif __arm__
-       return getsectdatafromheader(&_mh_dylib_header, "__TEXT", "__picsymbolstub4", &size) + slide;
+       void* p = getsectdata("__TEXT", "__picsymbolstub4", (unsigned long*)&size);
+       if ( p != NULL ) 
+               return getsectdatafromheader(&_mh_dylib_header, "__TEXT", "__picsymbolstub4", &size) + slide;
+       return getsectdatafromheader(&_mh_dylib_header, "__TEXT", "__symbolstub1", &size) + slide;
 #else
        #error unknown arch
 #endif
 #else
        #error unknown arch
 #endif
index 45f6d8ff898df811df983bf1d10cfa225cfbd67b..fdadfc76c49a7980965cd06ab7bf54729c6987d9 100644 (file)
@@ -71,7 +71,10 @@ static void* getStubAddr()
 #elif __x86_64__
        return getsectdata("__TEXT", "__symbol_stub1", &size);
 #elif __arm__
 #elif __x86_64__
        return getsectdata("__TEXT", "__symbol_stub1", &size);
 #elif __arm__
-       return getsectdata("__TEXT", "__symbol_stub4", &size);
+       void* p = getsectdata("__TEXT", "__symbol_stub4", &size);
+       if ( p != NULL ) 
+               return p;
+       return getsectdata("__TEXT", "__symbolstub1", &size);
 #else
        #error unknown arch
 #endif
 #else
        #error unknown arch
 #endif
index a383d1a7aec1a3224f9a4aecb6ba10196adea891..8aa6bea413796277bf79a76cefeeea50061c6015 100644 (file)
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
+ifeq "$(OS_NAME)" "iPhoneOS"
+       RUN_AS_USER = login -f -l mobile
+else
+       RUN_AS_USER = 
+endif
+
+PWD = `pwd`
+
 all-check: all check
 
 check:
 all-check: all check
 
 check:
-       export DYLD_LIBRARY_PATH=/ && export DYLD_PRINT_LIBRARIES=/ &&  export DYLD_PREBIND_DEBUG=/ && ./main
+       ${RUN_AS_USER} $(PWD)/main-with-env
 
 all: main
 
 main: main.c
        ${CC} ${CCFLAGS} -w -I${TESTROOT}/include -o main main.c -sectcreate __RESTRICT __restrict /dev/null
 
 all: main
 
 main: main.c
        ${CC} ${CCFLAGS} -w -I${TESTROOT}/include -o main main.c -sectcreate __RESTRICT __restrict /dev/null
+       echo "#!/bin/sh" > main-with-env
+       echo "export DYLD_INSERT_LIBRARIES=/" >> main-with-env
+       echo "export DYLD_PRINT_LIBRARIES=/" >> main-with-env
+       echo "$(PWD)/main" >> main-with-env
+       chmod +x main-with-env
 
 clean:
 
 clean:
-       ${RM} ${RMFLAGS} *~ main
+       ${RM} ${RMFLAGS} *~ main main-with-env
 
 
index b22295187302159a44291eadac18e19140196817..ceb2e3b31ae679f1814996a8e89b670d2aedc703 100644 (file)
 # 
 # @APPLE_LICENSE_HEADER_END@
 ##
 # 
 # @APPLE_LICENSE_HEADER_END@
 ##
-TESTROOT = ../..
+PWD = $(shell pwd)
+TESTROOT = $(PWD)/../..
 include ${TESTROOT}/include/common.makefile
 
 SHELL = bash # use bash shell so we can redirect just stderr
 
 include ${TESTROOT}/include/common.makefile
 
 SHELL = bash # use bash shell so we can redirect just stderr
 
+ifeq "$(OS_NAME)" "iPhoneOS"
+       RUN_AS_USER = login -f -l mobile
+else
+       RUN_AS_USER = 
+endif
 
 #
 # Use of @exectuable_path in restricted binaries is not allowed
 
 #
 # Use of @exectuable_path in restricted binaries is not allowed
@@ -35,10 +41,9 @@ SHELL = bash # use bash shell so we can redirect just stderr
 all-check: all check
 
 check:
 all-check: all check
 
 check:
-       ${TESTROOT}/bin/exit-non-zero-pass.pl "restrict-executable_path @executable_path" "restrict-executable_path @executable_path" ./main_exe "restrict-executable_path"
-       ${TESTROOT}/bin/exit-non-zero-pass.pl "restrict-executable_path @loader_path" "restrict-executable_path @loader_path" ./main_loader "restrict-executable_path"
-       ${TESTROOT}/bin/exit-non-zero-pass.pl "restrict-executable_path relative path" "restrict-executable_path relative path" ./main_rel "restrict-executable_path"
-
+       ${RUN_AS_USER} ${PASS_IFF_FAILURE} "setuid-executable_path @executable_path" "setuid-executable_path @executable_path" $(PWD)/main_exe
+       ${RUN_AS_USER} ${PASS_IFF_FAILURE} "setuid-executable_path @loader_path" "setuid-executable_path @loader_path" $(PWD)/main_loader
+       ${RUN_AS_USER} ${PASS_IFF_FAILURE} "setuid-executable_path relative path" "setuid-executable_path relative path" $(PWD)/main_rel
 
 
 all: main_exe  main_loader main_rel 
 
 
 all: main_exe  main_loader main_rel 
diff --git a/unit-tests/test-cases/rpath-dlopen-rm-executable/Makefile b/unit-tests/test-cases/rpath-dlopen-rm-executable/Makefile
new file mode 100644 (file)
index 0000000..c166d10
--- /dev/null
@@ -0,0 +1,50 @@
+##
+# Copyright (c) 2009 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
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+PWD = $(shell pwd)
+
+#
+# a main executable linked with -rpath.  At runtime the exectuable
+# deletes itself than calls dlopen().  Test that @executable_path
+# does not cause malloc to abort.
+#
+
+all-check: all check
+
+check:
+       cp main main.rm
+       ${TESTROOT}/bin/exit-zero-pass.pl "rpath-dlopen-rm-executable" "rpath-dlopen-rm-executable" ./main.rm 2> /dev/null
+
+all: main
+
+
+main : main.c 
+       ${CC} -I${TESTROOT}/include main.c -o main -Wl,-rpath -Wl,@executable_path/hide/hole
+
+clean:
+       ${RM} ${RMFLAGS} *~  main main.rm
diff --git a/unit-tests/test-cases/rpath-dlopen-rm-executable/foo.c b/unit-tests/test-cases/rpath-dlopen-rm-executable/foo.c
new file mode 100644 (file)
index 0000000..79572f9
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+void foo()
+{
+}
diff --git a/unit-tests/test-cases/rpath-dlopen-rm-executable/main.c b/unit-tests/test-cases/rpath-dlopen-rm-executable/main.c
new file mode 100644 (file)
index 0000000..d4f0b33
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <mach-o/dyld.h>
+
+#include "test.h"
+
+
+int main()
+{
+       char buf[2048];
+       uint32_t bufSize = sizeof(buf);
+       if ( _NSGetExecutablePath(buf, &bufSize) ) {
+               FAIL("rpath-dlopen-rm-exectuable: _NSGetExecutablePath()");
+               return EXIT_SUCCESS;
+       }
+       
+       unlink(buf);
+       
+       void* handle = dlopen("libz.dylib", RTLD_LAZY);
+       if ( handle == NULL ) {
+               FAIL("rpath-dlopen-rm-exectuable: %s", dlerror());
+               return EXIT_SUCCESS;
+       }
+               
+       PASS("rpath-dlopen-rm-exectuable");
+       return EXIT_SUCCESS;
+}
index fa534f2b4049f1dc87f8ea0fea59c8f39f087d18..6f96b7e7fe6d931690f95de08c56d3f03739a713 100644 (file)
@@ -1,5 +1,5 @@
 ##
 ##
-# Copyright (c) 2007 Apple Inc. All rights reserved.
+# Copyright (c) 2007-2009 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 # 
 # @APPLE_LICENSE_HEADER_END@
 ##
 # 
 # @APPLE_LICENSE_HEADER_END@
 ##
-TESTROOT = ../..
+PWD = $(shell pwd)
+TESTROOT = $(PWD)/../..
 include ${TESTROOT}/include/common.makefile
 
 include ${TESTROOT}/include/common.makefile
 
-PWD = $(shell pwd)
+ifeq "$(OS_NAME)" "iPhoneOS"
+       RUN_AS_USER = login -f -l mobile
+else
+       RUN_AS_USER = 
+endif
 
 #
 # a setuid main executable linked with -rpath links against a dylib 
 
 #
 # a setuid main executable linked with -rpath links against a dylib 
@@ -35,9 +40,9 @@ all-check: all check
 
 check:
        ./main || echo "FAIL rpath-indirect-suid absolute path"
 
 check:
        ./main || echo "FAIL rpath-indirect-suid absolute path"
-       ${TESTROOT}/bin/exit-non-zero-pass.pl "rpath-indirect-suid @loader_path path" "rpath-indirect-suid @loader_path path" ./main_bad1
-       ${TESTROOT}/bin/exit-non-zero-pass.pl "rpath-indirect-suid relative path" "rpath-indirect-suid relative path" ./main_bad2
-       ${TESTROOT}/bin/exit-non-zero-pass.pl "rpath-indirect-suid @rpath spoof" "rpath-indirect-suid @rpath spoof" ./main_bad3
+       ${RUN_AS_USER} ${PASS_IFF_FAILURE} "rpath-indirect-suid @loader_path path" "rpath-indirect-suid @loader_path path" $(PWD)/main_bad1
+       ${RUN_AS_USER} ${PASS_IFF_FAILURE} "rpath-indirect-suid relative path" "rpath-indirect-suid relative path" $(PWD)/main_bad2
+       ${RUN_AS_USER} ${PASS_IFF_FAILURE} "rpath-indirect-suid @rpath spoof" "rpath-indirect-suid @rpath spoof" $(PWD)/main_bad3
 
 all: main main_bad1 main_bad2 main_bad3
 
 
 all: main main_bad1 main_bad2 main_bad3
 
diff --git a/unit-tests/test-cases/rpath-install-name/Makefile b/unit-tests/test-cases/rpath-install-name/Makefile
new file mode 100644 (file)
index 0000000..622ade0
--- /dev/null
@@ -0,0 +1,55 @@
+##
+# Copyright (c) 2009 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)
+
+#
+# check that a loaded dylib with an @rpath install name will 
+# be found by a client.
+#
+
+all-check: all check
+
+check:
+       ./main
+
+all: main
+
+libstuff.dylib : stuff.c
+       ${CC} stuff.c -I${TESTROOT}/include -dynamiclib -o libstuff.dylib -install_name @rpath/libstuff.dylib
+       
+libstuff_better.dylib : stuff.c
+       ${CC} stuff.c -DBETTER=1 -I${TESTROOT}/include -dynamiclib -o libstuff_better.dylib -install_name @rpath/libstuff.dylib
+
+libbar.dylib : bar.c libstuff.dylib 
+       ${CC} bar.c -dynamiclib libstuff.dylib  -o libbar.dylib 
+
+
+main : main.c libbar.dylib libstuff_better.dylib
+       ${CC} -I${TESTROOT}/include main.c -o main -Wl,-rpath,${PWD}
+
+
+clean:
+       ${RM} ${RMFLAGS} *~  main libbar.dylib libstuff.dylib libstuff_better.dylib
diff --git a/unit-tests/test-cases/rpath-install-name/bar.c b/unit-tests/test-cases/rpath-install-name/bar.c
new file mode 100644 (file)
index 0000000..a27d788
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2009 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@
+ */
+
+extern void stuff(); 
+void bar()
+{
+       stuff();
+}
diff --git a/unit-tests/test-cases/rpath-install-name/main.c b/unit-tests/test-cases/rpath-install-name/main.c
new file mode 100644 (file)
index 0000000..87e0ae4
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2009 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 <stdlib.h>
+#include <dlfcn.h>
+
+#include "test.h"
+
+
+int main()
+{
+       void* h1 = dlopen("./libstuff_better.dylib", RTLD_LAZY);
+       if ( h1 == NULL ) {
+               FAIL("rpath-install-name: %s", dlerror());
+               return EXIT_SUCCESS;
+       }
+       
+
+       void* handle = dlopen("libbar.dylib", RTLD_LAZY);
+       if ( handle == NULL ) {
+               FAIL("rpath-install-name: %s", dlerror());
+               return EXIT_SUCCESS;
+       }
+       
+       typedef void (*BarProc)(void);
+       BarProc pBar = (BarProc)dlsym(handle, "bar");
+       if ( pBar == NULL ) {
+               FAIL("rpath-install-name: %s", dlerror());
+               return EXIT_SUCCESS;
+       }
+       
+       (*pBar)();
+       
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/rpath-install-name/stuff.c b/unit-tests/test-cases/rpath-install-name/stuff.c
new file mode 100644 (file)
index 0000000..6b60cb2
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2009 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 <stdlib.h>
+#include <dlfcn.h>
+
+#include "test.h"
+
+
+void stuff()
+{
+#if BETTER
+       PASS("rpath-install-name");
+#else
+       FAIL("rpath-install-name");
+#endif
+}
index ab1c6b65691186d575f150106b9a572029e52c25..fc038c1227e48b7afe8a2823aae98fbbadbfbfc5 100644 (file)
@@ -55,22 +55,11 @@ int main()
                return EXIT_SUCCESS;
        }
 
                return EXIT_SUCCESS;
        }
 
-       // walk images to get slide
-       uint32_t count = _dyld_image_count();
-       for(uint32_t i=0; i < count; ++i) {
-               if ( _dyld_get_image_header(i) == info.dli_fbase ) {
-                       if ( _dyld_get_image_vmaddr_slide(i) == 0 ) {
-                               // images in shared cache have a slide of zero
-                               PASS("shared-cache-symlink");
-                               return EXIT_SUCCESS;
-                       }
-                       else {
-                               FAIL("shared-cache-symlink: libz.dylib not loaded from shared cache");
-                               return EXIT_SUCCESS;
-                       }
-               }
-        }
+       const struct mach_header* mh = (struct mach_header*)info.dli_fbase;
+       if ( mh->flags & 0x80000000 ) 
+               PASS("shared-cache-symlink");
+       else 
+               FAIL("shared-cache-symlink: libz.dylib not loaded from shared cache");
 
 
-       FAIL("shared-cache-symlink libz.dylib not found");
        return EXIT_SUCCESS;
 }
        return EXIT_SUCCESS;
 }
diff --git a/unit-tests/test-cases/shared-region-overlap/Makefile b/unit-tests/test-cases/shared-region-overlap/Makefile
new file mode 100644 (file)
index 0000000..8a194a2
--- /dev/null
@@ -0,0 +1,47 @@
+##
+# Copyright (c) 2009 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
+
+# rosetta does not support very large stack sizes
+BASE_ADDRESS = 0x90030000
+ifeq "x86_64" "$(ARCH)"
+       BASE_ADDRESS = 0x7FFF80100000
+endif
+
+
+ifeq "iPhoneOS" "$(OS_NAME)"
+       BASE_ADDRESS = 0x2FF80000
+endif
+
+
+all-check: all check
+
+check:
+       ${TESTROOT}/bin/exit-zero-pass.pl "shared-region-overlap" "shared-region-overlap" ./main
+
+all:
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c -Wl,-image_base,${BASE_ADDRESS}
+
+clean:
+       ${RM} ${RMFLAGS} main
diff --git a/unit-tests/test-cases/shared-region-overlap/main.c b/unit-tests/test-cases/shared-region-overlap/main.c
new file mode 100644 (file)
index 0000000..83dfd8a
--- /dev/null
@@ -0,0 +1,12 @@
+#include <stdlib.h> // EXIT_SUCCESS
+
+#include "test.h"
+
+
+int
+main()
+{
+       return EXIT_SUCCESS;
+}
+
+
index 85aa95465b4084891f08e0e30e1731e99b864837..7797d2e4942537162e344183ed735917942d66b6 100644 (file)
@@ -1,5 +1,5 @@
 ##
 ##
-# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2006-2009 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
+ifeq "$(OS_NAME)" "iPhoneOS"
+       RUN_AS_USER = login -f -l mobile
+else
+       RUN_AS_USER = 
+endif
+
+PWD = `pwd`
+
 all-check: all check
 
 check:
 all-check: all check
 
 check:
-       export DYLD_INSERT_LIBRARIES=/ && export DYLD_PRINT_LIBRARIES=/ &&  export DYLD_PREBIND_DEBUG=/ && ./main
+       ${RUN_AS_USER} $(PWD)/main-with-env
 
 all: main
 
 
 all: main
 
@@ -34,7 +42,12 @@ main: main.c
        ${CC} ${CCFLAGS} -w -I${TESTROOT}/include -o main main.c
        sudo chown root main
        sudo chmod 4755 main
        ${CC} ${CCFLAGS} -w -I${TESTROOT}/include -o main main.c
        sudo chown root main
        sudo chmod 4755 main
-
+       echo "#!/bin/sh" > main-with-env
+       echo "export DYLD_INSERT_LIBRARIES=/" >> main-with-env
+       echo "export DYLD_PRINT_LIBRARIES=/" >> main-with-env
+       echo "$(PWD)/main" >> main-with-env
+       chmod +x main-with-env
+       
 clean:
 clean:
-       ${RM} ${RMFLAGS} *~ main
+       ${RM} ${RMFLAGS} *~ main main-with-env
 
 
index 87690821a9fffc635473ab4bdbcc55c881a2a797..aab4ca27fd4f1655d5db88f41ad8914c3f4be8cf 100644 (file)
 # 
 # @APPLE_LICENSE_HEADER_END@
 ##
 # 
 # @APPLE_LICENSE_HEADER_END@
 ##
-TESTROOT = ../..
+PWD = $(shell pwd)
+TESTROOT = $(PWD)/../..
 include ${TESTROOT}/include/common.makefile
 
 SHELL = bash # use bash shell so we can redirect just stderr
 
 include ${TESTROOT}/include/common.makefile
 
 SHELL = bash # use bash shell so we can redirect just stderr
 
+ifeq "$(OS_NAME)" "iPhoneOS"
+       RUN_AS_USER = login -f -l mobile
+else
+       RUN_AS_USER = 
+endif
 
 #
 # Use of @exectuable_path in setuid binaries is not allowed
 
 #
 # Use of @exectuable_path in setuid binaries is not allowed
@@ -36,11 +42,11 @@ all-check: all check
 
 check:
        ./main_exe "setuid-executable_path" || echo "FAIL setuid-executable_path @executable_path not setuid"
 
 check:
        ./main_exe "setuid-executable_path" || echo "FAIL setuid-executable_path @executable_path not setuid"
-       ${TESTROOT}/bin/exit-non-zero-pass.pl "setuid-executable_path @executable_path" "setuid-executable_path @executable_path" ./main_exe-suid "setuid-executable_path"
        ./main_loader "setuid-executable_path" || echo "FAIL setuid-executable_path @loader_path not setuid" 
        ./main_loader "setuid-executable_path" || echo "FAIL setuid-executable_path @loader_path not setuid" 
-       ${TESTROOT}/bin/exit-non-zero-pass.pl "setuid-executable_path @loader_path" "setuid-executable_path @loader_path" ./main_loader-suid "setuid-executable_path"
        ./main_rel "setuid-executable_path" || echo "FAIL setuid-executable_path relative path not setuid" 
        ./main_rel "setuid-executable_path" || echo "FAIL setuid-executable_path relative path not setuid" 
-       ${TESTROOT}/bin/exit-non-zero-pass.pl "setuid-executable_path relative path" "setuid-executable_path relative path" ./main_rel-suid "setuid-executable_path"
+       ${RUN_AS_USER} ${PASS_IFF_FAILURE} "setuid-executable_path @executable_path" "setuid-executable_path @executable_path" $(PWD)/main_exe-suid
+       ${RUN_AS_USER} ${PASS_IFF_FAILURE} "setuid-executable_path @loader_path" "setuid-executable_path @loader_path" $(PWD)/main_loader-suid
+       ${RUN_AS_USER} ${PASS_IFF_FAILURE} "setuid-executable_path relative path" "setuid-executable_path relative path" $(PWD)/main_rel-suid
 
 
 
 
 
 
diff --git a/unit-tests/test-cases/symbol-resolver-basic/Makefile b/unit-tests/test-cases/symbol-resolver-basic/Makefile
new file mode 100644 (file)
index 0000000..cfc8ac0
--- /dev/null
@@ -0,0 +1,55 @@
+##
+# 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
+
+
+##
+## Basic test of symbol-resolver functions
+##
+
+all-check: all_$(OS_BAROLO_FEATURES) check_$(OS_BAROLO_FEATURES)
+
+all: all_$(OS_BAROLO_FEATURES) 
+
+check: check_$(OS_BAROLO_FEATURES)
+
+check_:
+       ${PASS_IFF} true
+
+all_:
+
+
+check_1:
+       ./main
+       export TEN=1 && ./main
+
+all_1:  
+       ${CC} ${CCFLAGS} -dynamiclib foo.c foo2.c -o libfoo.dylib 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c libfoo.dylib -o main 
+
+
+
+clean:
+       ${RM} ${RMFLAGS} main libfoo.dylib
+
diff --git a/unit-tests/test-cases/symbol-resolver-basic/foo.c b/unit-tests/test-cases/symbol-resolver-basic/foo.c
new file mode 100644 (file)
index 0000000..f7b6b4b
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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>
+
+
+static int foo_ten()
+{
+       return 10;
+}
+
+static int foo_zero()
+{
+       return 0;
+}
+
+
+// This foo is a "resolver" function that return the actual address of "foo"
+void* foo()
+{
+       __asm__(".symbol_resolver _foo");  // magic until we have compiler support
+       if ( getenv("TEN") != NULL )
+               return &foo_ten;
+       else
+               return &foo_zero;
+}
+
diff --git a/unit-tests/test-cases/symbol-resolver-basic/foo2.c b/unit-tests/test-cases/symbol-resolver-basic/foo2.c
new file mode 100644 (file)
index 0000000..3c80d3f
--- /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 foo();
+
+// test that calls to resolver based function in same dylib work
+int fooPlusOne()
+{
+       return foo() + 1;
+}
+
diff --git a/unit-tests/test-cases/symbol-resolver-basic/main.c b/unit-tests/test-cases/symbol-resolver-basic/main.c
new file mode 100644 (file)
index 0000000..670984e
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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 <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+extern int foo();
+extern int fooPlusOne();
+
+
+int main()
+{
+       if ( getenv("TEN") != NULL ) {
+               if ( foo() != 10 )
+                       FAIL("symbol-resolver-basic: foo() != 10");
+               else if ( fooPlusOne() != 11 )
+                       FAIL("symbol-resolver-basic: fooPlusOne() != 11");
+               else
+                       PASS("symbol-resolver-basic");
+       }
+       else {
+               if ( foo() != 0 )
+                       FAIL("symbol-resolver-basic: foo() != 0");
+               else if ( fooPlusOne() != 1 )
+                       FAIL("symbol-resolver-basic: fooPlusOne() != 1");
+               else
+                       PASS("symbol-resolver-basic");
+       }
+  
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/symbol-resolver-pointer/Makefile b/unit-tests/test-cases/symbol-resolver-pointer/Makefile
new file mode 100644 (file)
index 0000000..9143671
--- /dev/null
@@ -0,0 +1,54 @@
+##
+# 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
+
+
+##
+## Basic test of symbol-resolver functions
+##
+
+all-check: all_$(OS_BAROLO_FEATURES) check_$(OS_BAROLO_FEATURES)
+
+all: all_$(OS_BAROLO_FEATURES) 
+
+check: check_$(OS_BAROLO_FEATURES)
+
+check_:
+       ${PASS_IFF} true
+
+all_:
+
+
+check_1:
+       ./main
+
+all_1:  
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib foo.c -o libfoo.dylib 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c libfoo.dylib -o main 
+
+
+
+clean:
+       ${RM} ${RMFLAGS} main libfoo.dylib
+
diff --git a/unit-tests/test-cases/symbol-resolver-pointer/foo.c b/unit-tests/test-cases/symbol-resolver-pointer/foo.c
new file mode 100644 (file)
index 0000000..71d67bc
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+int resolverCallCount = 0;
+int realTestCallCount = 0;
+
+
+void test$FOO();
+void test$FOO() {
+    //printf("test\n");
+       ++realTestCallCount;
+}
+
+void* test_chooser() __asm__("_test");
+void* test_chooser() {
+    __asm__(".symbol_resolver _test");
+    //printf("resolver\n");
+       ++resolverCallCount;
+    return test$FOO;
+}
+
+void test();
+static void (*t)(void) = test;
+
+void check() {
+    t();        // call through initialized pointer
+    t = test;  // re-assign pointer via non-lazy-poitner
+    t();        // call agin through pointer
+    test();     // call through stub
+       if ( resolverCallCount != 1 )
+               FAIL("symbol-resolver-pointer: resolved called %d times", resolverCallCount);
+       else if ( realTestCallCount != 3 )
+               FAIL("symbol-resolver-pointer: real test function called %d times", realTestCallCount);
+       else
+               PASS("symbol-resolver-pointer");
+}
+
+
+
+
diff --git a/unit-tests/test-cases/symbol-resolver-pointer/main.c b/unit-tests/test-cases/symbol-resolver-pointer/main.c
new file mode 100644 (file)
index 0000000..9e7a73b
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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 <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+extern void check();
+
+
+int main()
+{
+       check();
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/text-relocs-perms/Makefile b/unit-tests/test-cases/text-relocs-perms/Makefile
new file mode 100644 (file)
index 0000000..2e1ec0f
--- /dev/null
@@ -0,0 +1,44 @@
+##
+# 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
+
+all-check: all check
+
+check:
+       ./main
+
+all: main
+
+
+main: main.c libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c libfoo.dylib -o main 
+
+libfoo.dylib: foo.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib foo.c -o libfoo.dylib -seg1addr 0x20000000
+
+
+
+clean:
+       ${RM} ${RMFLAGS} main libfoo.dylib 
+       
diff --git a/unit-tests/test-cases/text-relocs-perms/foo.c b/unit-tests/test-cases/text-relocs-perms/foo.c
new file mode 100644 (file)
index 0000000..6a03b28
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2007-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 <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <unistd.h>
+#include <mach-o/getsect.h>
+#include <mach-o/ldsyms.h>
+#include <mach/mach.h> 
+#include <mach/mach_vm.h> 
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+static vm_prot_t getPermission(void* addr)
+{
+    mach_vm_address_t                          address = (mach_vm_address_t)(uintptr_t)addr;
+    kern_return_t                                      result;
+    mach_port_t                                                object_name;
+    vm_region_basic_info_data_64_t     info;
+    mach_msg_type_number_t                     count;
+    mach_vm_size_t                                     size = 4096;
+       
+       count = VM_REGION_BASIC_INFO_COUNT_64;
+       result = mach_vm_region(mach_task_self(),
+                                       &address,
+                                       &size,
+                                       VM_REGION_BASIC_INFO_64,
+                                       (vm_region_info_t)&info,
+                                       &count,
+                                       &object_name);   
+       if ( result == KERN_SUCCESS ) 
+               return info.protection;
+       return 0;
+}
+
+
+static void* getStubAddr()
+{
+#if __LP64__
+       uint64_t size;
+#else
+       uint32_t size;
+#endif
+       uintptr_t slide = (uintptr_t)&_mh_dylib_header; // assume dylib is zero-base so slide == load address
+#if __i386__
+       return getsectdatafromheader(&_mh_dylib_header, "__IMPORT", "__symbol_stub", &size) + slide;
+#elif __ppc__
+       return getsectdatafromheader(&_mh_dylib_header, "TEXT", "__picsymbolstub1", &size) + slide;
+#elif __ppc64__
+       return getsectdatafromheader_64(&_mh_dylib_header, "__TEXT", "__picsymbolstub1", &size) + slide;
+#elif __x86_64__
+       return getsectdatafromheader_64(&_mh_dylib_header, "__TEXT", "__symbol_stub1", &size) + slide;
+#elif __arm__
+       void* p = getsectdata("__TEXT", "__picsymbolstub4", (unsigned long*)&size);
+       if ( p != NULL ) 
+               return getsectdatafromheader(&_mh_dylib_header, "__TEXT", "__picsymbolstub4", &size) + slide;
+       return getsectdatafromheader(&_mh_dylib_header, "__TEXT", "__symbolstub1", &size) + slide;
+#else
+       #error unknown arch
+#endif
+}
+
+
+static void checkStubs(void* addr)
+{
+       vm_prot_t perm = getPermission(addr);
+       //fprintf(stderr, "perm=0x%02X\n", perm);
+       if ( (perm == 0) || ((perm & VM_PROT_EXECUTE) == 0) ) {
+               FAIL("text-reloc-perms: missing exec permission 0x%0X at address %p", perm, addr);
+               exit(0);
+       }
+}
+
+
+void foo()
+{
+       void* stubAddr = getStubAddr(); 
+       checkStubs(stubAddr);
+}
+
+
diff --git a/unit-tests/test-cases/text-relocs-perms/main.c b/unit-tests/test-cases/text-relocs-perms/main.c
new file mode 100644 (file)
index 0000000..b4994b0
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2007 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 <unistd.h>
+#include <mach-o/getsect.h>
+#include <mach/mach.h> 
+#include <mach/mach_vm.h> 
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+extern void foo();
+
+static vm_prot_t getPermission(void* addr)
+{
+    mach_vm_address_t                          address = (mach_vm_address_t)(uintptr_t)addr;
+    kern_return_t                                      result;
+    mach_port_t                                                object_name;
+    vm_region_basic_info_data_64_t     info;
+    mach_msg_type_number_t                     count;
+    mach_vm_size_t                                     size = 4096;
+       
+       count = VM_REGION_BASIC_INFO_COUNT_64;
+       result = mach_vm_region(mach_task_self(),
+                                       &address,
+                                       &size,
+                                       VM_REGION_BASIC_INFO_64,
+                                       (vm_region_info_t)&info,
+                                       &count,
+                                       &object_name);       
+       //fprintf(stderr, "result=%X, info.protection=%X\n", result, info.protection);
+       if ( result == KERN_SUCCESS ) 
+               return info.protection;
+       return 0;
+}
+
+
+static void* getStubAddr()
+{
+       unsigned long size;
+#if __i386__
+       return getsectdata("__IMPORT", "__jump_table", &size);
+#elif __ppc__
+       void* p = getsectdata("__TEXT", "__picsymbolstub1", &size);
+       if ( p != NULL ) 
+               return p;
+       return getsectdata("__TEXT", "__symbol_stub1", &size);
+#elif __ppc64__
+       return getsectdata("__TEXT", "__picsymbolstub1", &size);
+#elif __x86_64__
+       return getsectdata("__TEXT", "__symbol_stub1", &size);
+#elif __arm__
+       void* p = getsectdata("__TEXT", "__symbol_stub4", &size);
+       if ( p != NULL ) 
+               return p;
+       return getsectdata("__TEXT", "__symbolstub1", &size);
+#else
+       #error unknown arch
+#endif
+}
+
+
+static void checkStubs(void* addr)
+{
+       vm_prot_t perm = getPermission(addr);
+       if ( (perm == 0) || ((perm & VM_PROT_WRITE) != 0) ) {
+               FAIL("read-only-stubs: bad permissions %d at address %p", perm, addr);
+               exit(0);
+       }
+}
+
+
+int main()
+{
+       foo();
+
+       void* stubAddr = getStubAddr(); 
+#if __i386__
+       if ( stubAddr != NULL )
+#endif
+       {
+       checkStubs(stubAddr);
+       checkStubs(stubAddr);
+       }
+       PASS("text-relocs-perms");
+       return EXIT_SUCCESS;
+}
+
+
index cfadedaeb511881077a5d9c4132a919b59b81086..a024a28f5f3a5f32414de99b299d27502a4fc208 100644 (file)
@@ -24,7 +24,7 @@ TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
 ### 
 include ${TESTROOT}/include/common.makefile
 
 ### 
-### This test case is to verify __TEXT reliocations work in dylibs
+### This test case is to verify __TEXT relocations work in dylibs
 ### 
 ### 
 
 ### 
 ### 
 
@@ -35,10 +35,6 @@ ifeq "ppc64" "$(ARCH)"
        # ppc64 does not support text relocs
        TEXT_RELOC_FLAGS = 
 endif 
        # ppc64 does not support text relocs
        TEXT_RELOC_FLAGS = 
 endif 
-ifeq "armv6" "$(ARCH)"
-       # arm does not support text relocs
-       TEXT_RELOC_FLAGS = 
-endif 
 
 
 all-check: all check
 
 
 all-check: all check
@@ -46,14 +42,12 @@ all-check: all check
 check:
        ./main
 
 check:
        ./main
 
-all: main 
-
-main: main.c libbar.dylib
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libbar.dylib
-
-libbar.dylib: bar.c
-       ${CC} ${CCFLAGS} -dynamiclib -o libbar.dylib bar.c -Os ${TEXT_RELOC_FLAGS}
+all:  
+       ${CC} ${CCFLAGS} -dynamiclib bar.c space.s -Os -o libbar.dylib  ${TEXT_RELOC_FLAGS}
+       ${CC} ${CCFLAGS} bind.c -static -Os -c -o bind.o
+       ${CC} ${CCFLAGS} -dynamiclib bind.o libbar.dylib -o libbind.dylib ${TEXT_RELOC_FLAGS}
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libbar.dylib libbind.dylib
        
 clean:
        
 clean:
-       ${RM} ${RMFLAGS} *~ main libbar.dylib
+       ${RM} ${RMFLAGS} *~ main libbar.dylib libbind.dylib bind.o
 
 
index acf643ca33131b2a39b42bf0a43cd38d630a01dc..a87566e9458db5c88c7b6faec97a1775de726b9e 100644 (file)
 #include <stdlib.h> // exit(), EXIT_SUCCESS
 #include <stdbool.h>
 
 #include <stdlib.h> // exit(), EXIT_SUCCESS
 #include <stdbool.h>
 
+int y = 0;
+
 static int x = 0;
 
 int getx() { return x; }
 void setx(int a) { x = a; }
 
 static int x = 0;
 
 int getx() { return x; }
 void setx(int a) { x = a; }
 
+void bar()
+{
+       printf("hello\n");
+}
diff --git a/unit-tests/test-cases/text-relocs/bind.c b/unit-tests/test-cases/text-relocs/bind.c
new file mode 100644 (file)
index 0000000..fa0dd81
--- /dev/null
@@ -0,0 +1,7 @@
+
+extern int y;
+
+int test()
+{
+       return y;
+}
diff --git a/unit-tests/test-cases/text-relocs/space.s b/unit-tests/test-cases/text-relocs/space.s
new file mode 100644 (file)
index 0000000..2767b5d
--- /dev/null
@@ -0,0 +1,2 @@
+       .text
+_junk: .space  1024*1024
diff --git a/unit-tests/test-cases/threaded-flat-lookup/Makefile b/unit-tests/test-cases/threaded-flat-lookup/Makefile
new file mode 100644 (file)
index 0000000..1c8f897
--- /dev/null
@@ -0,0 +1,41 @@
+##
+# 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
+
+all-check: all check
+
+check:
+       ./main
+
+all: main 
+
+main : main.c foo.c
+       ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo1.dylib
+       ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo2.dylib
+       ${CC} ${CCFLAGS} client.c -dynamiclib -o libclient.dylib -flat_namespace -undefined dynamic_lookup
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libfoo1.dylib libfoo2.dylib libclient.dylib
+
diff --git a/unit-tests/test-cases/threaded-flat-lookup/client.c b/unit-tests/test-cases/threaded-flat-lookup/client.c
new file mode 100644 (file)
index 0000000..72ba218
--- /dev/null
@@ -0,0 +1,11 @@
+
+extern void foo();
+extern void bar();
+extern void baz();
+
+void doit()
+{
+       foo();
+       bar();
+       baz();
+}
diff --git a/unit-tests/test-cases/threaded-flat-lookup/foo.c b/unit-tests/test-cases/threaded-flat-lookup/foo.c
new file mode 100644 (file)
index 0000000..3f2cbaf
--- /dev/null
@@ -0,0 +1,4 @@
+
+void foo() {}
+void bar() {}
+void baz() {}
diff --git a/unit-tests/test-cases/threaded-flat-lookup/main.c b/unit-tests/test-cases/threaded-flat-lookup/main.c
new file mode 100644 (file)
index 0000000..09ee55f
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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 <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <string.h>
+#include <dlfcn.h>
+#include <pthread.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+void* h1 = NULL;
+void* h2 = NULL;
+
+static void* work(void* ignore)
+{
+       for (int i=0; i < 10000; ++i) {
+               h1 = dlopen("libfoo1.dylib", 0);
+               if ( h1 == NULL ) {
+                       FAIL("dlopen failed: %s", dlerror());
+                       exit(0);
+               }
+               dlclose(h2);    
+               h2 = dlopen("libfoo2.dylib", 0);
+               if ( h2 == NULL ) {
+                       FAIL("dlopen failed: %s", dlerror());
+                       exit(0);
+               }
+               dlclose(h1);    
+       }
+       
+       //fprintf(stderr, "done with foos\n");
+       return NULL;
+}
+
+
+int main()
+{
+       h2 = dlopen("libfoo2.dylib", 0);
+       if ( h2 == NULL ) {
+               FAIL("dlopen failed: %s", dlerror());
+               exit(0);
+       }
+
+       // other thread dlopens and closes libfoo.dylib 500 times
+       pthread_t other;
+       if ( pthread_create(&other, NULL, work, NULL) != 0 ) {
+               FAIL("pthread_create failed");
+               exit(0);
+       }
+               
+       // this thread looks up a symbol 10,000 times
+       for (int i=0; i < 15000; ++i) {
+               void* handle = dlopen("libclient.dylib", 0);
+               if ( handle == NULL ) {
+                       FAIL("dlopen failed: %s", dlerror());
+                       exit(0);
+               }
+               typedef void (*proc_t)();
+               proc_t proc = dlsym(handle, "doit");
+               if ( proc == NULL ) {
+                       FAIL("dlsym failed: %s", dlerror());
+                       exit(0);
+               }
+               (*proc)();
+               dlclose(handle);        
+       }
+       //fprintf(stderr, "done with libclient\n");
+
+       void* result;
+       pthread_join(other, &result);
+       
+       PASS("threaded-flat-lookup");
+       return 0;
+}
diff --git a/unit-tests/test-cases/tlv-basic/Makefile b/unit-tests/test-cases/tlv-basic/Makefile
new file mode 100644 (file)
index 0000000..977b5a8
--- /dev/null
@@ -0,0 +1,44 @@
+##
+# 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
+
+
+##
+## Basic test of thread-local-variables in a main executable
+##
+
+all-check: all check
+
+check:
+       ./main
+
+all: main 
+
+main : main.c 
+       clang -arch ${ARCH} ${CCFLAGS} -I${TESTROOT}/include main.c -o main 
+
+
+clean:
+       ${RM} ${RMFLAGS} main 
+
diff --git a/unit-tests/test-cases/tlv-basic/main.c b/unit-tests/test-cases/tlv-basic/main.c
new file mode 100644 (file)
index 0000000..0fa5240
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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 <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <pthread.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+__thread int a;
+__thread int b = 5;
+__thread static int c;
+__thread static int d = 5;
+
+
+static void* work(void* arg)
+{
+       //fprintf(stderr, "self=%p, &a=%p\n", pthread_self(), get_a());
+       if ( a != 0 ) {
+               FAIL("tlv-basic: get_a() non-zero");
+               exit(0);
+       }
+       if ( b != 5 ) {
+               FAIL("tlv-basic: get_b() not five");
+               exit(0);
+       }
+       if ( c != 0 ) {
+               FAIL("tlv-basic: get_c() non-zero");
+               exit(0);
+       }
+       if ( d != 5 ) {
+               FAIL("tlv-basic: get_d() not five");
+               exit(0);
+       }
+       return NULL;
+}
+
+int main()
+{
+       pthread_t worker1;
+       if ( pthread_create(&worker1, NULL, work, NULL) != 0 ) {
+               FAIL("pthread_create failed");
+               exit(0);
+       }
+
+       pthread_t worker2;
+       if ( pthread_create(&worker2, NULL, work, NULL) != 0 ) {
+               FAIL("pthread_create failed");
+               exit(0);
+       }
+
+       void* result;
+       //fprintf(stderr, "waiting for worker 1\n");
+       pthread_join(worker1, &result);
+       //fprintf(stderr, "waiting for worker 2\n");
+       pthread_join(worker2, &result);
+
+       work(NULL);
+
+       PASS("tlv-basic");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/tlv-dylib/Makefile b/unit-tests/test-cases/tlv-dylib/Makefile
new file mode 100644 (file)
index 0000000..ff8103e
--- /dev/null
@@ -0,0 +1,43 @@
+##
+# 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
+
+
+##
+## Basic test of thread-local-variables in a main executable
+##
+
+all-check: all check
+
+check:
+       ./main
+
+all:  
+       clang -arch ${ARCH} ${CCFLAGS} -I${TESTROOT}/include foo.c -dynamiclib -o libfoo.dylib 
+       clang -arch ${ARCH} ${CCFLAGS} -I${TESTROOT}/include main.c libfoo.dylib -o main 
+
+
+clean:
+       ${RM} ${RMFLAGS} libfoo.dylib main 
+
diff --git a/unit-tests/test-cases/tlv-dylib/foo.c b/unit-tests/test-cases/tlv-dylib/foo.c
new file mode 100644 (file)
index 0000000..4a47edb
--- /dev/null
@@ -0,0 +1,8 @@
+
+
+
+__thread int a;
+__thread int b = 5;
+
+
+int getB() { return b; }
diff --git a/unit-tests/test-cases/tlv-dylib/main.c b/unit-tests/test-cases/tlv-dylib/main.c
new file mode 100644 (file)
index 0000000..117a646
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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 <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <pthread.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+extern __thread int a;
+extern __thread int b;
+__thread static int c;
+__thread static int d = 5;
+
+
+static void* work(void* arg)
+{
+       //fprintf(stderr, "self=%p, &a=%p\n", pthread_self(), get_a());
+       if ( a != 0 ) {
+               FAIL("tlv-basic: get_a() non-zero");
+               exit(0);
+       }
+       if ( b != 5 ) {
+               FAIL("tlv-basic: get_b() not five");
+               exit(0);
+       }
+       if ( c != 0 ) {
+               FAIL("tlv-basic: get_c() non-zero");
+               exit(0);
+       }
+       if ( d != 5 ) {
+               FAIL("tlv-basic: get_d() not five");
+               exit(0);
+       }
+       return NULL;
+}
+
+int main()
+{
+       pthread_t worker1;
+       if ( pthread_create(&worker1, NULL, work, NULL) != 0 ) {
+               FAIL("pthread_create failed");
+               exit(0);
+       }
+
+       pthread_t worker2;
+       if ( pthread_create(&worker2, NULL, work, NULL) != 0 ) {
+               FAIL("pthread_create failed");
+               exit(0);
+       }
+
+       void* result;
+       //fprintf(stderr, "waiting for worker 1\n");
+       pthread_join(worker1, &result);
+       //fprintf(stderr, "waiting for worker 2\n");
+       pthread_join(worker2, &result);
+
+       work(NULL);
+
+       PASS("tlv-basic");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/tlv-initializer/Makefile b/unit-tests/test-cases/tlv-initializer/Makefile
new file mode 100644 (file)
index 0000000..62cd36a
--- /dev/null
@@ -0,0 +1,50 @@
+##
+# 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
+
+
+##
+## Basic test of thread-local-variables in a main executable
+##
+
+all-check: all_$(OS_BAROLO_FEATURES) check_$(OS_BAROLO_FEATURES)
+
+check: check_$(OS_BAROLO_FEATURES)
+
+check_:
+       ${PASS_IFF} true
+
+all_:
+
+
+check_1:
+       ./main
+
+all_1:  
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c get.s -o main
+
+
+clean:
+       ${RM} ${RMFLAGS} main 
+
diff --git a/unit-tests/test-cases/tlv-initializer/get.s b/unit-tests/test-cases/tlv-initializer/get.s
new file mode 100644 (file)
index 0000000..5116395
--- /dev/null
@@ -0,0 +1,99 @@
+
+               # _a is zerofill global TLV
+               .tbss _a$tlv$init,4,2
+
+               # _b is an initialized global TLV
+               .tdata
+_b$tlv$init:    
+               .long   5
+
+
+#if __x86_64__
+
+               # _a is global TLV
+               .tlv
+               .globl _a
+_a:            .quad   __tlv_bootstrap
+               .quad   0
+               .quad   _a$tlv$init
+
+               # _b is a global TLV
+               .tlv
+               .globl _b
+_b:            .quad   __tlv_bootstrap
+               .quad   0
+               .quad   _b$tlv$init
+
+               # _myinit sets up TLV content
+               .thread_init_func
+               .quad   _myinit
+
+
+       .text
+       .globl  _get_a
+_get_a:
+       pushq   %rbp
+       movq    %rsp, %rbp
+       movq    _a@TLVP(%rip), %rdi
+       call    *(%rdi)
+       popq    %rbp
+       ret
+
+       .globl  _get_b
+_get_b:
+       pushq   %rbp
+       movq    %rsp, %rbp
+       movq    _b@TLVP(%rip), %rdi
+       call    *(%rdi)
+       popq    %rbp
+       ret
+
+#endif
+
+#if __i386__
+
+               # _a is global TLV
+               .tlv
+               .globl _a
+_a:            .long   __tlv_bootstrap
+               .long   0
+               .long   _a$tlv$init
+
+               # _b is a global TLV
+               .tlv
+               .globl _b
+_b:            .long   __tlv_bootstrap
+               .long   0
+               .long   _b$tlv$init
+
+               # _myinit sets up TLV content
+               .thread_init_func
+               .long   _myinit
+
+
+       .text
+       .globl  _get_a
+_get_a:
+       pushl   %ebp
+       movl    %esp, %ebp
+       subl    $8, %esp
+       movl    _a@TLVP, %eax
+       call    *(%eax)    
+       movl    %ebp, %esp
+       popl    %ebp
+       ret
+
+       .globl  _get_b
+_get_b:
+       pushl   %ebp
+       movl    %esp, %ebp
+       subl    $8, %esp
+       movl    _b@TLVP, %eax
+       call    *(%eax)    
+       movl    %ebp, %esp
+       popl    %ebp
+       ret
+
+#endif
+
+.subsections_via_symbols
diff --git a/unit-tests/test-cases/tlv-initializer/main.c b/unit-tests/test-cases/tlv-initializer/main.c
new file mode 100644 (file)
index 0000000..af11a86
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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 <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <pthread.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+extern int* get_a();           // initially 0
+extern int* get_b();           // initially 5
+
+void myinit()
+{
+       *get_a() = 11;
+       *get_b() = 42;
+}
+
+
+static void* work(void* arg)
+{
+       //fprintf(stderr, "self=%p, &a=%p\n", pthread_self(), get_a());
+       if ( *get_a() != 11 ) {
+               FAIL("tlv-initializer: get_a() not initialized to 11");
+               exit(0);
+       }
+       if ( *get_b() != 42 ) {
+               FAIL("tlv-initializer: get_b() not initialized to 42");
+               exit(0);
+       }
+       return NULL;
+}
+
+int main()
+{
+       pthread_t worker1;
+       if ( pthread_create(&worker1, NULL, work, NULL) != 0 ) {
+               FAIL("pthread_create failed");
+               exit(0);
+       }
+
+       pthread_t worker2;
+       if ( pthread_create(&worker2, NULL, work, NULL) != 0 ) {
+               FAIL("pthread_create failed");
+               exit(0);
+       }
+
+       void* result;
+       //fprintf(stderr, "waiting for worker 1\n");
+       pthread_join(worker1, &result);
+       //fprintf(stderr, "waiting for worker 2\n");
+       pthread_join(worker2, &result);
+
+       work(NULL);
+
+       PASS("tlv-initializer");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/tlv-terminators/Makefile b/unit-tests/test-cases/tlv-terminators/Makefile
new file mode 100644 (file)
index 0000000..f27c54e
--- /dev/null
@@ -0,0 +1,50 @@
+##
+# 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
+
+
+##
+## Basic test of thread-local-variables in a main executable
+##
+
+all-check: all_$(OS_BAROLO_FEATURES) check_$(OS_BAROLO_FEATURES)
+
+check: check_$(OS_BAROLO_FEATURES)
+
+check_:
+       ${PASS_IFF} true
+
+all_:
+
+
+check_1:
+       ./main
+
+all_1:  
+       clang ${CCFLAGS} -I${TESTROOT}/include main.c init.s -o main
+
+
+clean:
+       ${RM} ${RMFLAGS} main 
+
diff --git a/unit-tests/test-cases/tlv-terminators/init.s b/unit-tests/test-cases/tlv-terminators/init.s
new file mode 100644 (file)
index 0000000..9bb901c
--- /dev/null
@@ -0,0 +1,10 @@
+
+               # _myinit sets up TLV content
+               .thread_init_func
+    #if __LP64__
+               .quad   _myinit
+    #else
+               .long   _myinit
+    #endif
+
+.subsections_via_symbols
diff --git a/unit-tests/test-cases/tlv-terminators/main.c b/unit-tests/test-cases/tlv-terminators/main.c
new file mode 100644 (file)
index 0000000..94d1d2a
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * 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 <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <pthread.h>
+#include <stdbool.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+struct thread_var_info
+{
+    pthread_t th;
+    int*    a_addr;
+    int*    b_addr;
+    bool    a_terminated;
+    bool    b_terminated;
+};
+
+struct thread_var_info threadmain;
+struct thread_var_info thread1;
+struct thread_var_info thread2;
+
+
+__thread int a;         // statically, initially 0
+__thread int b = 5;     // statically, initially 5
+
+extern void _tlv_atexit(void (*termfunc)(void* objAddr), void* objAddr);
+
+void myinit()
+{
+       a = 11;      // dynamically initialized to 11
+       b = 42;      // dynamically initialized to 42
+}
+
+void myterm(void* objAddr)
+{
+    pthread_t self = pthread_self();
+    //fprintf(stderr, "myterm(%p), self=%p\n", objAddr, self);
+    if ( thread1.th == self && thread1.a_addr == objAddr )
+        thread1.a_terminated = true;
+    else if ( thread1.th == self && thread1.b_addr == objAddr )
+        thread1.b_terminated = true;
+    else if ( thread2.th == self && thread2.a_addr == objAddr )
+        thread2.a_terminated = true;
+    else if ( thread2.th == self && thread2.b_addr == objAddr )
+        thread2.b_terminated = true;
+    else if ( threadmain.th == self && threadmain.a_addr == objAddr )
+        threadmain.a_terminated = true;
+    else if ( threadmain.th == self && threadmain.b_addr == objAddr )
+        threadmain.b_terminated = true;
+}
+
+static void* work(void* arg)
+{
+       if ( a != 11 ) {
+               FAIL("tlv-terminators: a not initialized to 11");
+               exit(0);
+       }
+       if ( b != 42 ) {
+               FAIL("tlv-terminators: b not initialized to 42");
+               exit(0);
+       }
+    struct thread_var_info* s = (struct thread_var_info*)arg;
+    s->th = pthread_self();
+    s->a_addr = &a;
+    s->b_addr = &b;
+    s->a_terminated = false;
+    s->b_terminated = false;
+       //fprintf(stderr, "self=%p, arg=%p, &a=%p, &b=%p\n", s->th, arg, s->a_addr , s->b_addr);
+
+    _tlv_atexit(myterm, &a);
+    _tlv_atexit(myterm, &b);
+   
+       return NULL;
+}
+
+int main()
+{
+       pthread_t worker1;
+       if ( pthread_create(&worker1, NULL, work, &thread1) != 0 ) {
+               FAIL("pthread_create failed");
+               exit(0);
+       }
+
+       pthread_t worker2;
+       if ( pthread_create(&worker2, NULL, work, &thread2) != 0 ) {
+               FAIL("pthread_create failed");
+               exit(0);
+       }
+
+       void* result;
+       //fprintf(stderr, "waiting for worker 1\n");
+       pthread_join(worker1, &result);
+       //fprintf(stderr, "waiting for worker 2\n");
+       pthread_join(worker2, &result);
+
+       work(&threadmain);
+
+       //fprintf(stderr, "thread1: &a=%p, &b=%p\n", thread1.a_addr, thread1.b_addr);
+       //fprintf(stderr, "thread2: &a=%p, &b=%p\n", thread2.a_addr, thread2.b_addr);
+       //fprintf(stderr, "threadm: &a=%p, &b=%p\n", threadmain.a_addr, threadmain.b_addr);
+
+    if ( ! thread1.a_terminated ) {
+               FAIL("tlv-terminators: terminator for a on thread 1 not run");
+               exit(0);
+    }
+    if ( ! thread1.b_terminated ) {
+               FAIL("tlv-terminators: terminator for b on thread 1 not run");
+               exit(0);
+    }
+
+    if ( ! thread2.a_terminated ) {
+               FAIL("tlv-terminators: terminator for a on thread 2 not run");
+               exit(0);
+    }
+    if ( ! thread2.b_terminated ) {
+               FAIL("tlv-terminators: terminator for b on thread 2 not run");
+               exit(0);
+    }
+
+   if ( threadmain.a_terminated ) {
+               FAIL("tlv-terminators: terminator for a on main thread run early");
+               exit(0);
+    }
+    if ( threadmain.b_terminated ) {
+               FAIL("tlv-terminators: terminator for b on main thread run early");
+               exit(0);
+    }
+
+
+       PASS("tlv-terminators");
+       return EXIT_SUCCESS;
+}
index 34d1a637afd1b4ea816967b3b38a1cf6e119a1f8..e3d07f1e105d97c64f234679fbab309d0667fb42 100644 (file)
@@ -25,6 +25,8 @@
 #include <mach-o/dyld.h>
 #include <mach/mach.h>
 #include <sys/mman.h>
 #include <mach-o/dyld.h>
 #include <mach/mach.h>
 #include <sys/mman.h>
+#include <dlfcn.h>  
+#include <Availability.h>  
 
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
@@ -49,8 +51,11 @@ int main()
        // call a dyld API that uses the string
        // if dyld reads past the end of the string, it will crash
        // <rdar://problem/6493245> trie parser can read past end of input symbol name
        // call a dyld API that uses the string
        // if dyld reads past the end of the string, it will crash
        // <rdar://problem/6493245> trie parser can read past end of input symbol name
+#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && (__MAC_OS_X_VERSION_MIN_REQUIRED <= __MAC_10_5)
        _dyld_lookup_and_bind(sym, NULL, NULL);
        _dyld_lookup_and_bind(sym, NULL, NULL);
-  
+#else
+       dlsym(RTLD_DEFAULT, sym);
+#endif
        PASS("trie-symbol-overrun");
        return EXIT_SUCCESS;
 }
        PASS("trie-symbol-overrun");
        return EXIT_SUCCESS;
 }
index fc39c25cc37da8fdf167df0d2eb3376fc5220f9d..d1bab845b64fd02ed6e3d03383065a32d1afe98f 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <stdio.h>
 #include <string.h>
 #include <mach-o/dyld.h>
 #include <stdio.h>
 #include <string.h>
 #include <mach-o/dyld.h>
+#include <dlfcn.h>
+#include <Availability.h>
 
 #include "test.h" // PASS(), FAIL()
 
 
 int main()
 {
 
 #include "test.h" // PASS(), FAIL()
 
 
 int main()
 {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        // load libfoo which depends on libbar
        const struct mach_header* mh = NSAddImage("libfoo.dylib", NSADDIMAGE_OPTION_RETURN_ON_ERROR);
        if ( mh != NULL ) {
                FAIL("library-cant-be-bound: NSAddImage should have failed");
                return 1;
        }
        // load libfoo which depends on libbar
        const struct mach_header* mh = NSAddImage("libfoo.dylib", NSADDIMAGE_OPTION_RETURN_ON_ERROR);
        if ( mh != NULL ) {
                FAIL("library-cant-be-bound: NSAddImage should have failed");
                return 1;
        }
-       
+#else
+       if ( dlopen("libfoo.dylib", RTLD_LAZY) != NULL ){
+               FAIL("library-cant-be-bound: dlopen should have failed");
+               return 1;
+       }
+#endif
+
         uint32_t count = _dyld_image_count();
         for(uint32_t i=0; i < count; ++i) {
                const char*  name = _dyld_get_image_name(i);
         uint32_t count = _dyld_image_count();
         for(uint32_t i=0; i < count; ++i) {
                const char*  name = _dyld_get_image_name(i);
diff --git a/unit-tests/test-cases/upward-dylib/Makefile b/unit-tests/test-cases/upward-dylib/Makefile
new file mode 100644 (file)
index 0000000..9488bac
--- /dev/null
@@ -0,0 +1,52 @@
+##
+# 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
+
+all-check: all_$(OS_BAROLO_FEATURES) check_$(OS_BAROLO_FEATURES)
+
+all: all_$(OS_BAROLO_FEATURES) 
+
+check: check_$(OS_BAROLO_FEATURES)
+
+check_:
+       ${PASS_IFF} true
+
+all_:
+
+
+check_1:
+       ./main1
+       ./main2
+
+all_1: 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib up.c -DSTUB -o libup.stub -install_name libup.dylib 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib down.c -o libdown.dylib -Wl,-upward_library,libup.stub 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib up.c libdown.dylib -o libup.dylib  
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c  libdown.dylib libup.dylib -o main2
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c  libup.dylib libdown.dylib -o main1
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main1 main2 libup.dylib libdown.dylib  libup.stub
+       
diff --git a/unit-tests/test-cases/upward-dylib/down.c b/unit-tests/test-cases/upward-dylib/down.c
new file mode 100644 (file)
index 0000000..c5624bd
--- /dev/null
@@ -0,0 +1,22 @@
+#include <stdio.h>
+#include "up.h"
+
+static int state = 0;
+
+
+// should run second because down.dylib is lower than up.dylib 
+static __attribute__((constructor)) void myInit3() 
+{
+       //fprintf(stderr, "myInit3()\n");
+       state = 1;
+}
+
+int getdown()
+{
+       return state;
+}
+
+void other()
+{
+       whatsup();
+}
\ No newline at end of file
diff --git a/unit-tests/test-cases/upward-dylib/down.h b/unit-tests/test-cases/upward-dylib/down.h
new file mode 100644 (file)
index 0000000..534eb92
--- /dev/null
@@ -0,0 +1,2 @@
+extern int getdown();
+
diff --git a/unit-tests/test-cases/upward-dylib/main.c b/unit-tests/test-cases/upward-dylib/main.c
new file mode 100644 (file)
index 0000000..06b272b
--- /dev/null
@@ -0,0 +1,19 @@
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+#include "up.h"
+#include "down.h"
+
+int main()
+{
+       if ( whatsup() )
+               PASS("upward-dylib");
+       else
+               FAIL("upward-dylib");
+       return EXIT_SUCCESS;
+}
+
+
diff --git a/unit-tests/test-cases/upward-dylib/up.c b/unit-tests/test-cases/upward-dylib/up.c
new file mode 100644 (file)
index 0000000..2451d74
--- /dev/null
@@ -0,0 +1,21 @@
+#include <stdio.h>
+#include "down.h"
+
+static int state = 0;
+
+#ifndef STUB
+// should run second because up.dylib is higher than down.dylib
+static __attribute__((constructor)) void myInit1() 
+{
+       //fprintf(stderr, "myInit1()\n");
+       if ( getdown() ) {
+               state = 1;
+       }
+}
+#endif
+
+int whatsup()
+{
+       return state;
+}
+
diff --git a/unit-tests/test-cases/upward-dylib/up.h b/unit-tests/test-cases/upward-dylib/up.h
new file mode 100644 (file)
index 0000000..9ed804c
--- /dev/null
@@ -0,0 +1,2 @@
+
+extern int whatsup();
diff --git a/unit-tests/test-cases/weak-coalesce-stubs/Makefile b/unit-tests/test-cases/weak-coalesce-stubs/Makefile
new file mode 100644 (file)
index 0000000..03cb107
--- /dev/null
@@ -0,0 +1,18 @@
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+all-check: all check
+
+check:
+       ./main
+
+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       
+       
+clean:
+       ${RM} ${RMFLAGS} libbar.dylib libfoo.dylib libstub.dylib main
diff --git a/unit-tests/test-cases/weak-coalesce-stubs/bar.c b/unit-tests/test-cases/weak-coalesce-stubs/bar.c
new file mode 100644 (file)
index 0000000..344a82c
--- /dev/null
@@ -0,0 +1,6 @@
+void bar() {}
+
+void foo() __attribute__((weak));
+void foo()
+{
+}
\ No newline at end of file
diff --git a/unit-tests/test-cases/weak-coalesce-stubs/foo.c b/unit-tests/test-cases/weak-coalesce-stubs/foo.c
new file mode 100644 (file)
index 0000000..348cf65
--- /dev/null
@@ -0,0 +1,61 @@
+
+
+void foo() __attribute__((weak));
+
+void foo()
+{
+}
+
+void abcdefghijklmnopqrstuvwxzy() {}
+void abcde3fghijklmnopqrstuvwxzy() {}
+void abcdef4ghijklmnopqrstuvwxzy() {}
+void abcdefgh5ijklmnopqrstuvwxzy() {}
+void abcdefghij6klmnopqrstuvwxzy() {}
+void abcdefghijk7lmnopqrstuvwxzy() {}
+void abcdefghijklm8nopqrstuvwxzy() {}
+void abcdefghijklmn9opqrstuvwxzy() {}
+void a1bcdefghijklmnopqrstuvwxzy() {}
+void a2bcdefghijklmnopqrstuvwxzy() {}
+void a3bcdefghijklmnopqrstuvwxzy() {}
+void a4bcdefghijklmnopqrstuvwxzy() {}
+void a5bcdefghijklmnopqrstuvwxzy() {}
+void a6bcdefghijklmnopqrstuvwxzy() {}
+void a7bcdefghijklmnopqrstuvwxzy() {}
+void a8bcdefghijklmnopqrstuvwxzy() {}
+void a9bcdefghijklmnopqrstuvwxzy() {}
+void ab1cdefghijklmnopqrstuvwxzy() {}
+void ab2cdefghijklmnopqrstuvwxzy() {}
+void ab3cdefghijklmnopqrstuvwxzy() {}
+void ab4cdefghijklmnopqrstuvwxzy() {}
+void ab5cdefghijklmnopqrstuvwxzy() {}
+void ab6cdefghijklmnopqrstuvwxzy() {}
+void ab7cdefghijklmnopqrstuvwxzy() {}
+void ab8cdefghijklmnopqrstuvwxzy() {}
+void ab9cdefghijklmnopqrstuvwxzy() {}
+void abc1defghijklmnopqrstuvwxzy() {}
+void abc2defghijklmnopqrstuvwxzy() {}
+void abc3defghijklmnopqrstuvwxzy() {}
+void abc4defghijklmnopqrstuvwxzy() {}
+void abc5defghijklmnopqrstuvwxzy() {}
+void abc6defghijklmnopqrstuvwxzy() {}
+void abc7defghijklmnopqrstuvwxzy() {}
+void abc8defghijklmnopqrstuvwxzy() {}
+void abc9defghijklmnopqrstuvwxzy() {}
+void abcd1efghijklmnopqrstuvwxzy() {}
+void abcd2efghijklmnopqrstuvwxzy() {}
+void abcd3efghijklmnopqrstuvwxzy() {}
+void abcd4efghijklmnopqrstuvwxzy() {}
+void abcd5efghijklmnopqrstuvwxzy() {}
+void abcd6efghijklmnopqrstuvwxzy() {}
+void abcd7efghijklmnopqrstuvwxzy() {}
+void abcd8efghijklmnopqrstuvwxzy() {}
+void abcd9efghijklmnopqrstuvwxzy() {}
+void abcde1fghijklmn9opqrstuvwxzy() {}
+void abcde2fghijklmn9opqrstuvwxzy() {}
+void abcde3fghijklmn9opqrstuvwxzy() {}
+void abcde4fghijklmn9opqrstuvwxzy() {}
+void abcde5fghijklmn9opqrstuvwxzy() {}
+void abcde6fghijklmn9opqrstuvwxzy() {}
+void abcde7fghijklmn9opqrstuvwxzy() {}
+void abcde8fghijklmn9opqrstuvwxzy() {}
+void abcde9fghijklmn9opqrstuvwxzy() {}
diff --git a/unit-tests/test-cases/weak-coalesce-stubs/main.c b/unit-tests/test-cases/weak-coalesce-stubs/main.c
new file mode 100644 (file)
index 0000000..11a4c89
--- /dev/null
@@ -0,0 +1,22 @@
+#include <stdio.h>
+#include <dlfcn.h>
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+//<rdar://problem/7886402> Loading MH_DYLIB_STUB causing coalescable miscount
+
+int main()
+{
+       // try to load stub many times
+       for (int i=0; i < 10; ++i) {
+               void* handle = dlopen("libstub.dylib", RTLD_LAZY);
+               if ( handle != NULL ) {
+                       FAIL("weak-coalesce-stubs: load of libstub.dylib unexpectedly succeeded");
+               }
+       }
+       // try to load real dylib
+       dlopen("libbar.dylib", RTLD_LAZY);
+       PASS("weak-coalesce-stubs");
+       return 0;
+}