]> 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
@@ -6,10 +6,14 @@ DYLD_FRAMEWORK_PATH
 .br
 DYLD_FALLBACK_FRAMEWORK_PATH
 .br
+DYLD_VERSIONED_FRAMEWORK_PATH
+.br
 DYLD_LIBRARY_PATH
 .br
 DYLD_FALLBACK_LIBRARY_PATH
 .br
+DYLD_VERSIONED_LIBRARY_PATH
+.br
 DYLD_ROOT_PATH
 .br
 DYLD_SHARED_REGION
@@ -48,7 +52,7 @@ DYLD_PRINT_STATISTICS
 .br
 DYLD_PRINT_DOFS
 .br
-DYLD_NO_PIE
+DYLD_PRINT_RPATHS
 .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
+.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
@@ -122,6 +137,15 @@ path.
 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.    
@@ -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_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
@@ -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.
+.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).
@@ -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 
-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
-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
index f5baa1b6da825e625b1f03320abe3dee591e17d4..9d524ad0d0499fe2a1ae58b233a1b12da8b017bd 100644 (file)
@@ -15,6 +15,8 @@
 .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
@@ -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.  
+.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
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,
@@ -107,7 +107,10 @@ copies the path of the main executable into the buffer
 .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. 
index 75cd83f4e06314c98d004fa0b0d21fe45c9ff295..21650208c07feb210f1dadfbf2232bdaeb094063 100644 (file)
@@ -3,10 +3,27 @@
        archiveVersion = 1;
        classes = {
        };
-       objectVersion = 46;
+       objectVersion = 45;
        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" */;
 /* 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 */; };
+               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 */; };
-               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 */; };
-               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"; }; };
-               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 */; };
-               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 */; };
-               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 */; };
+               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 */; };
-               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 */; };
 /* 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 */;
                        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;
-                       remoteInfo = dsc;
+                       remoteInfo = libdsc;
+               };
+               F9CE330A120F40EA0098B590 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = F9ED4C8B0630A72300DF4E74 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = F9F2A5580F7AEE9800B7C9EB;
+                       remoteInfo = libdsc;
                };
                F9ED4CA60630A78A00DF4E74 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXCopyFilesBuildPhase section */
-               F90CF2950E71D1FB000BF0F1 /* usr|local|include */ = {
+               F908135111D3ED9000626CC1 /* usr|include|mach-o */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = /usr/local/include;
+                       dstPath = "/usr/include/mach-o";
                        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;
                };
-               F93AA9B30630AE8200301D9F /* usr|include|mach-o */ = {
+               F908137011D3FB5000626CC1 /* usr|include */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = "/usr/include/mach-o";
+                       dstPath = /usr/include;
                        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;
                };
-               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 = (
-                               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;
                };
-               F93AA9C20630AF0700301D9F /* usr|share|man|man1 */ = {
+               F908137211D3FB5000626CC1 /* usr|share|man|man1 */ = {
                        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;
                };
-               F93AA9C60630AF1F00301D9F /* usr|share|man|man3 */ = {
+               F908137311D3FB5000626CC1 /* usr|share|man|man3 */ = {
                        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;
                };
-               F9574CB206C95C0D00142BFA /* usr|include */ = {
+               F98C78D10F7C00EA006257D2 /* usr|local|include|mach-o */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = /usr/include;
+                       dstPath = "$(INSTALL_LOCATION)/usr/local/include/mach-o";
                        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;
                };
-               F98C78D10F7C00EA006257D2 /* usr|local|include|mach-o */ = {
+               F9B0913511F11D8B00096D49 /* usr|local|include|mach-o */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = "/usr/local/include/mach-o";
+                       dstPath = "usr/local/include/mach-o";
                        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;
                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 */,
                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>"; };
+               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>"; };
+               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; };
+               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; };
-               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; };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               F99B8E540FEC10F600701838 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                F9F2A5570F7AEE9800B7C9EB /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                                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>";
                        isa = PBXGroup;
                        children = (
                                F9ED4C980630A76000DF4E74 /* dyld */,
-                               F9ED4C9F0630A76B00DF4E74 /* libdyldapis.a */,
+                               F9ED4C9F0630A76B00DF4E74 /* libdyld.dylib */,
                                F93937320A94FAF700070A07 /* update_dyld_shared_cache */,
                                F9F2A5590F7AEE9800B7C9EB /* libdsc.a */,
+                               F99B8E670FEC121100701838 /* dyld_shared_cache_util */,
+                               F9B0912311F11D1600096D49 /* libdsc_slider.a */,
                        );
                        name = Products;
                        sourceTree = "<group>";
                                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 */,
+                               F9A6D6E2116F9DF20051CC16 /* threadLocalVariables.c */,
+                               F9A6D70B116FBBD10051CC16 /* threadLocalHelpers.s */,
                        );
                        name = src;
                        sourceTree = "<group>";
                                F939372F0A94FAF700070A07 /* Sources */,
                                F93937300A94FAF700070A07 /* Frameworks */,
                                F9D238DD0A9E2FEE002B55C7 /* usr|share|man|man1 */,
+                               F991E3030FF1A4EC0082CCC9 /* do not install duplicates */,
                        );
                        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";
                };
+               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 = (
+                               F9D050C811DD701A00FB0A29 /* configure archives */,
                                F9ED4C950630A76000DF4E74 /* Sources */,
+                               F907E2490FA6469000BFEDBD /* install iPhone file */,
+                               F99B8EB60FEC236500701838 /* suppress macosx dyld_shared_cache_util */,
                        );
                        buildRules = (
                                F921D318070376B0000D1056 /* PBXBuildRule */,
                                F921D3160703769A000D1056 /* PBXBuildRule */,
                        );
                        dependencies = (
+                               F99B8EB20FEC220C00701838 /* PBXTargetDependency */,
                        );
                        name = dyld;
                        productName = dyld;
                        productReference = F9ED4C980630A76000DF4E74 /* dyld */;
                        productType = "com.apple.product-type.tool";
                };
-               F9ED4C9E0630A76B00DF4E74 /* libdyld */ = {
+               F9ED4C9E0630A76B00DF4E74 /* libdyld.dylib */ = {
                        isa = PBXNativeTarget;
-                       buildConfigurationList = F9D8C7E1087B087300E93EFB /* Build configuration list for PBXNativeTarget "libdyld" */;
+                       buildConfigurationList = F9D8C7E1087B087300E93EFB /* Build configuration list for PBXNativeTarget "libdyld.dylib" */;
                        buildPhases = (
-                               F9AC7E7E0B7BB3D300FEB38B /* create version.c */,
                                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 */,
                        );
                        dependencies = (
                        );
-                       name = libdyld;
+                       name = libdyld.dylib;
                        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;
-                       buildConfigurationList = F9F2A56B0F7AEEB100B7C9EB /* Build configuration list for PBXNativeTarget "dsc" */;
+                       buildConfigurationList = F9F2A56B0F7AEEB100B7C9EB /* Build configuration list for PBXNativeTarget "libdsc" */;
                        buildPhases = (
                                F9F2A5560F7AEE9800B7C9EB /* Sources */,
                                F9F2A5570F7AEE9800B7C9EB /* Frameworks */,
                        );
                        dependencies = (
                        );
-                       name = dsc;
+                       name = libdsc;
                        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" */;
-                       compatibilityVersion = "Xcode 2.4";
+                       compatibilityVersion = "Xcode 3.1";
+                       developmentRegion = English;
                        hasScannedForEncodings = 1;
+                       knownRegions = (
+                               English,
+                               Japanese,
+                               French,
+                               German,
+                       );
                        mainGroup = F9ED4C870630A72200DF4E74;
                        productRefGroup = F9ED4C990630A76000DF4E74 /* Products */;
                        projectDirPath = "";
                        targets = (
                                F9ED4C920630A73900DF4E74 /* all */,
                                F9ED4C970630A76000DF4E74 /* dyld */,
-                               F9ED4C9E0630A76B00DF4E74 /* libdyld */,
+                               F908134211D3ED0B00626CC1 /* libdyld */,
+                               F9ED4C9E0630A76B00DF4E74 /* libdyld.dylib */,
                                F93937310A94FAF700070A07 /* update_dyld_shared_cache */,
-                               F9F2A5580F7AEE9800B7C9EB /* dsc */,
+                               F9F2A5580F7AEE9800B7C9EB /* libdsc */,
+                               F99B8E550FEC10F600701838 /* dyld_shared_cache_util */,
+                               F9B0912211F11D1600096D49 /* libdsc_slider */,
                        );
                };
 /* End PBXProject section */
 
 /* Begin PBXShellScriptBuildPhase section */
-               F918692408B16F6900E0F9DB /* install symlinks */ = {
+               F907E2490FA6469000BFEDBD /* install iPhone file */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 8;
                        files = (
                        );
                        inputPaths = (
                        );
-                       name = "install symlinks";
+                       name = "install iPhone file";
                        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;
                };
-               F9AC7E7E0B7BB3D300FEB38B /* create version.c */ = {
+               F991E3030FF1A4EC0082CCC9 /* do not install duplicates */ = {
                        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 = (
                        );
-                       name = "create version.c";
+                       name = "configure archives";
                        outputPaths = (
-                               "$(BUILT_PRODUCTS_DIR)/version.c",
+                               "$(DERIVED_SOURCES_DIR)/archives.txt",
                        );
                        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 */
                        );
                        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;
                                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 */,
                        );
                        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 */,
-                               F9AC7E940B7BB67700FEB38B /* version.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;
                };
                        buildActionMask = 2147483647;
                        files = (
                                F9F2A5700F7AEEE300B7C9EB /* dsc_iterator.cpp in Sources */,
+                               F9CE307A1208F1B50098B590 /* dsc_extractor.cpp in Sources */,
                        );
                        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 */;
                };
-               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;
-                       target = F9F2A5580F7AEE9800B7C9EB /* dsc */;
-                       targetProxy = F98C78D90F7C017F006257D2 /* PBXContainerItemProxy */;
+                       target = F9F2A5580F7AEE9800B7C9EB /* libdsc */;
+                       targetProxy = F9CE330A120F40EA0098B590 /* PBXContainerItemProxy */;
                };
                F9ED4CA70630A78A00DF4E74 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                };
                F9ED4CA90630A78A00DF4E74 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = F9ED4C9E0630A76B00DF4E74 /* libdyld */;
+                       target = F9ED4C9E0630A76B00DF4E74 /* libdyld.dylib */;
                        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 = {
                                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 = {
+                               ARCHS = x86_64;
                                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;
-                               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;
                        };
                        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 = (
-                                       ppc,
                                        i386,
                                        x86_64,
                                );
                                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;
                                        "./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))",
-                                       "-lstdc++-static",
-                                       "$(LIBC_OVERRIDES_$(PLATFORM_NAME))",
+                                       "@$(DERIVED_SOURCES_DIR)/archives.txt",
                                        "-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",
                                );
-                               PER_ARCH_CFLAGS_ppc = "";
                                PREBINDING = NO;
                                PRODUCT_NAME = dyld;
                                STRIPFLAGS = "-S";
                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;
                                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;
                                        "./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))",
-                                       "-lstdc++-static",
-                                       "$(LIBC_OVERRIDES_$(PLATFORM_NAME))",
+                                       "@$(DERIVED_SOURCES_DIR)/archives.txt",
                                        "-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",
                                );
-                               PER_ARCH_CFLAGS_ppc = "";
                                PREBINDING = NO;
                                PRODUCT_NAME = dyld;
                                STRIPFLAGS = "-S";
                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;
-                               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",
                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_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                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",
                                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_SYMBOLS_PRIVATE_EXTERN = YES;
                                INSTALL_PATH = /usr/local/lib;
                                PREBINDING = NO;
                                PRODUCT_NAME = dsc;
                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_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_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;
-                               INSTALL_PATH = /usr/local/lib;
-                               PREBINDING = NO;
+                               INSTALLHDRS_COPY_PHASE = YES;
+                               INSTALL_PATH = "$(INSTALL_LOCATION)/usr/local/lib";
                                PRODUCT_NAME = dsc;
                                ZERO_LINK = NO;
                        };
 /* 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 = (
                        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 = (
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               F9D8C7E1087B087300E93EFB /* Build configuration list for PBXNativeTarget "libdyld" */ = {
+               F9D8C7E1087B087300E93EFB /* Build configuration list for PBXNativeTarget "libdyld.dylib" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                F9D8C7E2087B087300E93EFB /* Debug */,
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               F9F2A56B0F7AEEB100B7C9EB /* Build configuration list for PBXNativeTarget "dsc" */ = {
+               F9F2A56B0F7AEEB100B7C9EB /* Build configuration list for PBXNativeTarget "libdsc" */ = {
                        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
- * 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 
@@ -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 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@
  * 
@@ -24,6 +24,7 @@
 #define _DYLD_IMAGES_
 
 #include <stdbool.h>
+#include <unistd.h>
 #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.
+ *
+ * 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 };
@@ -67,8 +73,22 @@ struct dyld_image_info {
                                                                                                        /* 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[]);
 
+/* 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;
@@ -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 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;
-       /* 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;
-       /* 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;
-       /* 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;
+       /* 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;
 
-
 /*
  * 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 -*-
  *
- * Copyright (c) 2003-2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2003-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -24,7 +24,8 @@
 #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>
 
@@ -33,6 +34,24 @@ extern "C" {
 #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
 //
@@ -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);
 
 
+//
+// 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
@@ -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); }
 
-       //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); }
 
@@ -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); }
 
-       //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;
@@ -67,23 +70,23 @@ private:
 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:
-       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              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;
 };
 
+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__
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); }
+
+    // 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); }
+
+    // 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 -*- 
  *
- * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2006-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -40,6 +40,8 @@
 
 #include <vector>
 #include <set>
+#include <ext/hash_map>
+#include <ext/hash_set>
 
 #include "MachOFileAbstraction.hpp"
 #include "Architectures.hpp"
@@ -47,6 +49,9 @@
 #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);
-       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; };
+       struct SymbolReExport { const char* exportName; int dylibOrdinal; const char* importName; };
        typedef __gnu_cxx::hash_map<const char*, pint_t, __gnu_cxx::hash<const char*>, CStringEquals> NameToAddrMap;
+       typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> NameSet;
+    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                                                                            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, 
-                                                                                                                               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);
-       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();
+       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;
+       NameSet                                                                         fSymbolResolvers;
+       std::vector<SymbolReExport>                                     fReExportedSymbols;
        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;
+       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),
-         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)
@@ -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_UPWARD_DYLIB:
                                ((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;
-               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) {
-                       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);
                }
        }
@@ -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[name] = sym->n_value();
+                               fHashTable[name] = runtimeAddressFromNList(sym);
                                //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()];
-                               fHashTable[name] = sym->n_value();
+                               fHashTable[name] = runtimeAddressFromNList(sym);
                                //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)
@@ -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_UPWARD_DYLIB:
                                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>
-void Binder<A>::bind()
+void Binder<A>::bind(std::vector<void*>& pointersInData)
 {
        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 {
@@ -382,7 +533,8 @@ void Binder<A>::doSetUpDyldSection()
 }
 
 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();
@@ -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 "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";
@@ -407,8 +559,26 @@ void Binder<A>::bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uin
        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];
@@ -433,12 +603,13 @@ void Binder<A>::bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uin
                default:
                        throw "bad bind type";
        }
+       pointersInData.push_back(mappedAddr);
 }
 
 
 
 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()];
@@ -486,7 +657,7 @@ void Binder<A>::doBindDyldLazyInfo()
                                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:
@@ -503,7 +674,7 @@ void Binder<A>::doBindDyldLazyInfo()
 }
 
 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()];
@@ -560,22 +731,22 @@ void Binder<A>::doBindDyldInfo()
                                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:
-                               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:
-                               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) {
-                                       bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName);
+                                       bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName, false, pointersInData);
                                        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 {
-                       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());
@@ -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
-                       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
-                       return undefinedSymbol->n_value();
+                       return runtimeAddressFromNList(undefinedSymbol);
                }
        }
        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;
-               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>
-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());
+        *foundIn = this;
                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;
                }
        }
@@ -829,6 +1036,144 @@ bool Binder<A>::findExportedSymbolAddress(const char* name, pint_t* result)
        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__
index cba7f8a591a8c99254d70379c6f9c7ca29451a43..3be3fa2eb0c7d8d7fe052062f889b902a3f79f3d 100644 (file)
@@ -43,6 +43,27 @@ struct uuid_command {
        #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"
@@ -738,29 +759,28 @@ public:
 
     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_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;
                 }
             }
-            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
     {
-        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);
-        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;
index 945227b727b55054012fbd9994e4d36fcb63b3c9..e23cbac280dfc8214d6532bc2dff39783999b4d1 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- 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@
  * 
@@ -27,6 +27,7 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/errno.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 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                                                            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;
@@ -142,6 +148,9 @@ public:
        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 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                                                            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; }
@@ -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 const uint8_t*                                          getDyldInfoExports() const              { return fDyldInfoExports; }
+       virtual void                                                            setDyldInfoExports(const uint8_t* newExports) const { fDyldInfoExports = newExports; }
        
 private:
        typedef typename A::P                                   P;
@@ -209,6 +225,11 @@ private:
        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;
 
-       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;
@@ -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
 {
-       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;
 }
 
-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) {
-               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;
 }
@@ -414,8 +326,13 @@ UniversalMachOLayout::UniversalMachOLayout(const char* path, const std::set<Arch
 {
        // 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);
@@ -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);
-                       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) {
-                               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);
                                        }
+                                       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:
@@ -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)) {
-                                       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)) {
-                                       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)) {
-                                       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)) {
-                                       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)) {
@@ -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),
-   fShareableLocation(false)
+   fShareableLocation(false), fDynamicLookupLinkage(false), fMainExecutableLookupLinkage(false), fIsDylib(false), 
+       fHasDyldInfo(false), fDyldInfoExports(NULL)
 {
        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:
+                       fIsDylib = true;
+                       break;
                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();
        
+       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;
@@ -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_UPWARD_DYLIB:
                                {
                                        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;
+                       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());
        }
@@ -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 ( (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; }
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 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 void                                                            rebase();
+       virtual void                                                            rebase(std::vector<void*>&);
 
 protected:
        typedef typename A::P                                   P;
@@ -85,11 +85,13 @@ private:
        void                                                                            calculateRelocBase();
        void                                                                            adjustLoadCommands();
        void                                                                            adjustSymbolTable();
+       void                                                                            optimzeStubs();
+       void                                                                            makeNoPicStub(uint8_t* stub, pint_t logicalAddress);
        void                                                                            adjustDATA();
        void                                                                            adjustCode();
-       void                                                                            applyRebaseInfo();
+       void                                                                            applyRebaseInfo(std::vector<void*>& pointersInData);
        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);
@@ -111,6 +113,8 @@ private:
        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), 
-       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() ) {
@@ -205,11 +210,11 @@ uint64_t Rebaser<A>::getVMSize() const
 
 
 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 )
-               this->applyRebaseInfo();
+               this->applyRebaseInfo(pointersInData);
        else
                this->adjustDATA();
 
@@ -225,6 +230,9 @@ void Rebaser<A>::rebase()
        // update symbol table  
        this->adjustSymbolTable();
        
+       // optimize stubs 
+       this->optimzeStubs();
+       
        // 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_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;
@@ -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()
 {
@@ -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
-       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 {
@@ -425,29 +494,13 @@ void Rebaser<A>::adjustExportInfo()
        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();
-       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)
 {
-       //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;
@@ -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;
+               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;
@@ -542,6 +606,21 @@ void Rebaser<A>::adjustCode()
                                                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());
                }
@@ -559,7 +638,7 @@ void Rebaser<A>::adjustCode()
                                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);
                }
@@ -567,7 +646,7 @@ void Rebaser<A>::adjustCode()
 }
 
 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() )
@@ -603,11 +682,12 @@ void Rebaser<A>::doRebase(int segIndex, uint64_t segOffset, uint8_t type)
                default:
                        throw "bad rebase type";
        }
+       pointersInData.push_back(mappedAddr);
 }
 
 
 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()];
@@ -641,26 +721,26 @@ void Rebaser<A>::applyRebaseInfo()
                                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) {
-                                       doRebase(segIndex, segOffset, type);
+                                       doRebase(segIndex, segOffset, type, pointersInData);
                                        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) {
-                                       doRebase(segIndex, segOffset, type);
+                                       doRebase(segIndex, segOffset, type, pointersInData);
                                        segOffset += skip + sizeof(pint_t);
                                }
                                break;
index 7c5d4a7e79d5fc713060275ff02891f2f6ea34a8..05a8e070387fbee0682a8f9ed5b9e39dcf9062e3 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- 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@
  * 
 #ifndef __MACH_O_TRIE__
 #define __MACH_O_TRIE__
 
+#include <algorithm>
 
 #include "MachOFileAbstraction.hpp"
 
+
 namespace mach_o {
 namespace trie {
 
@@ -41,25 +43,28 @@ struct Edge
 
 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;
-       uint32_t                        fFlags;
+       uint64_t                        fFlags;
+       uint64_t                        fOther;
+       const char*                     fImportedName;
        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
-                               e.fChild->addSymbol(fullStr, address, flags);
+                               e.fChild->addSymbol(fullStr, address, flags, other, importName);
                                return;
                        }
                        else {
@@ -80,18 +85,24 @@ struct Node
                                                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;
                                        }
                                }
                        }
                }
+
                // 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;
        }
        
@@ -114,14 +125,26 @@ struct 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) {
-               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) {
@@ -138,13 +161,42 @@ struct Node
 
        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 {
-                       // no export info
+                       // no export info uleb128 of zero is one byte of zero
                        out.push_back(0);
                }
                // write number of children
@@ -215,22 +267,25 @@ struct Entry
        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
-       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;
-       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);
        }
        
@@ -262,18 +317,31 @@ struct EntryWithOffset
 
 
 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 )
-               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);
-               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++;
@@ -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;
-       
        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 -*- 
  *
- * Copyright (c) 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -67,8 +67,8 @@ struct objc_class {
     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>
@@ -81,8 +81,8 @@ struct objc_category {
     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>
@@ -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); }
-    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>
@@ -106,7 +106,7 @@ struct objc_module {
     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>
@@ -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 *
     
-    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> *)
-                cache->mappedCacheAddressForAddress(imageInfoSection->addr());
+                cache->mappedAddressForVMAddress(imageInfoSection->addr());
             info->setSelectorsPrebound();
         }
     }
index ef200a5a0d738ad147287e755b56ede5e43eae81..9dc9b90adcad59e5de6a99df4658d0047a581f5f 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- 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_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
-
+       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); }
+
+    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>
@@ -39,14 +138,67 @@ class objc_method_list_t {
     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:
-    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 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>
@@ -64,8 +216,128 @@ class objc_ivar_list_t {
     uint32_t count;
     objc_ivar_t<A> first;
 
+    // use newIvarList instead
+    void* operator new (size_t) { return NULL; }
+    void* operator new (size_t, void* buf) { return buf; }
+
+public:
+
+    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:
-    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>
@@ -80,35 +352,85 @@ class objc_protocol_t {
     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 {
-    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;
-    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;
@@ -118,7 +440,37 @@ class objc_class_data_t {
     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>
@@ -130,11 +482,44 @@ class objc_class_t {
     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_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:
-    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>
@@ -165,38 +570,34 @@ public:
     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>
-class SelectorUpdater {
+class MethodListWalker {
 
     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");
+            
         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))) {
-                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))) {
-                visitMethodList(mlist, visitor);
+                mVisitor.visitMethodList(mlist);
             }
             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))) {
-                visitMethodList(mlist, visitor);
+                mVisitor.visitMethodList(mlist);
             }
             if ((mlist = proto->getClassMethods(cache))) {
-                visitMethodList(mlist, visitor);
+                mVisitor.visitMethodList(mlist);
             }
             if ((mlist = proto->getOptionalInstanceMethods(cache))) {
-                visitMethodList(mlist, visitor);
+                mVisitor.visitMethodList(mlist);
             }
             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);
-            pint_t newValue = visitor.visit(oldValue);
+            pint_t newValue = mVisitor.visit(oldValue);
             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();
-            pint_t newValue = visitor.visit(oldValue);
+            pint_t newValue = mVisitor.visit(oldValue);
             msg.setName(newValue);
         }
 
@@ -258,8 +693,562 @@ public:
             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();
         }
     }
 };
+
+
+// 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 -*- 
  *
- * Copyright (c) 2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -23,6 +23,9 @@
  */
 
 #include <stdlib.h>
+#include <stdio.h>
+#include <Availability.h>
+
 
 #include "dsc_iterator.h"
 #include "dyld_cache_format.h"
 #include "CacheFileAbstraction.hpp"
 
 
+
 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)
@@ -50,7 +55,7 @@ namespace dyld {
 
        // call the callback block on each segment in this image                                                          
        template <typename A>
-       void walkSegments(const uint8_t* cache, const char* dylibPath, const uint8_t* machHeader, 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;      
@@ -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;
-                               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());
                }
        }
-                                               
+                       
                                                          
        // 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;
+               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());
-                       walkSegments<A>(cache, dylibPath, machHeader, callback);
+                       walkSegments<A>(cache, dylibPath, machHeader, slide, callback);
                }
                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.
-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 ) 
@@ -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);
+       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;
 }
 
+// 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 -*- 
  *
- * Copyright (c) 2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 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 
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 -*- 
  *
- * Copyright (c) 2006-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2006-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <mach/shared_region.h>
 
 
- struct dyld_cache_header
+struct dyld_cache_header
 {
        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
+       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
@@ -48,7 +60,22 @@ struct dyld_cache_image_info
        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_"
 
 
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 -*- 
  *
- * Copyright (c) 2006-2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2006-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -44,8 +44,6 @@
 #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"
 
 #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                                                    iPhoneOS = false;
 static std::vector<const char*>                warnings;
 
 
@@ -95,6 +100,11 @@ static uint64_t pageAlign(uint64_t addr) { return ( (addr + 4095) & (-4096) ); }
 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);
@@ -104,6 +114,7 @@ public:
        
        ArchPair                                                                                        getArchPair() { return fArchPair; }
        std::set<const class MachOLayoutAbstraction*>&          getSharedDylibs() { return fSharedDylibs; }
+       StringToString&                                                                         getDylibAliases() { return fAliasesMap; }
        const char*                                                                                     archName() { return archName(fArchPair); }
        
 private:
@@ -128,9 +139,6 @@ private:
                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;
 
 
@@ -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);
+       static bool                                     sharable(const MachOLayoutAbstraction* layout, ArchPair ap, char** msg);
 
        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
+       StringToString                                                          fAliasesMap;
 };
 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);
-                               fgPerArchGraph[*ait]->addRoot(path, layout);
+                               if ( layout != NULL )
+                                       fgPerArchGraph[*ait]->addRoot(path, layout);
                        }
                        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) {
-               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);
 }
 
+// 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)
 {
@@ -229,12 +241,32 @@ ArchGraph::DependencyNode* ArchGraph::getNodeForVirtualPath(const char* vpath)
                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);
-                       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);
+                       }
                }
                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);
-       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;
+       }
        
        // 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) ) {
-               //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;
 }
@@ -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];
-                                       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]);
@@ -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];
-                                       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]);
@@ -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";
                                }
-                               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() ) {
@@ -355,15 +440,27 @@ void ArchGraph::findSharedDylibs(ArchPair ap)
 {
        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();
-                       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
@@ -416,14 +534,8 @@ bool ArchGraph::canBeShared(const MachOLayoutAbstraction* layout, ArchPair ap, c
        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);
@@ -470,22 +582,28 @@ template <typename A>
 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);
 
-    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;
 
-       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);
-       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();
@@ -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 bool                             addCacheSlideInfo();
        
-       
-       void                                    assignNewBaseAddresses();
-       uint64_t                                cacheFileOffsetForAddress(uint64_t addr);
+       void                                    assignNewBaseAddresses(bool verify);
 
        struct LayoutInfo {
                const MachOLayoutAbstraction*           layout;
+               std::vector<const char*>                        aliases;
                dyld_cache_image_info                           info;
        };
        
@@ -520,8 +638,8 @@ private:
                 // 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) {
@@ -542,13 +660,15 @@ private:
                std::map<const MachOLayoutAbstraction*, uint32_t>& fMap;
        };
        
-
+       
        ArchGraph*                                                      fArchGraph;
        const bool                                                      fVerify;
        bool                                                            fExistingIsNotUpToDate;
+       bool                                                            fCacheFileInFinalLocation;
        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;
@@ -561,6 +681,15 @@ private:
        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;
 };
 
@@ -572,17 +701,17 @@ class PointerSection
     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))
-        , 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)
     {
     }
@@ -595,13 +724,27 @@ public:
     }
 
     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 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
@@ -620,7 +763,7 @@ public:
                  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)
     {
     }
@@ -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<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<arm>::sharedRegionWritableStartAddress()    { return 0x38000000; }
+template <>     uint64_t       SharedCache<arm>::sharedRegionWritableStartAddress()    { return 0x3E000000; }
 
 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<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"; }
@@ -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>
-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
+       unsigned int aliasCount = 0;
        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;
@@ -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.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);
        }
 
-       // 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);
-       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 ) {
-               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 ) {
@@ -730,7 +901,30 @@ SharedCache<A>::SharedCache(ArchGraph* graph, const char* rootPath, bool alphaSo
        }
        
        // 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 ) {
@@ -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);
 }
 
@@ -775,11 +964,42 @@ uint64_t SharedCache<ppc>::getWritableSegmentNewAddress(uint64_t proposedNewAddr
 
 
 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;
@@ -859,13 +1079,19 @@ void SharedCache<A>::assignNewBaseAddresses()
        }
        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;
-       if ( currentExecuteAddress > sharedRegionReadOnlyStartAddress() + 0x3000 ) {
+       if ( currentExecuteAddress > sharedCacheStartAddress + FIRST_DYLIB_TEXT_OFFSET ) {
                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;
@@ -906,7 +1132,7 @@ void SharedCache<A>::assignNewBaseAddresses()
                // 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;
@@ -917,26 +1143,43 @@ void SharedCache<A>::assignNewBaseAddresses()
 
 
 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>
-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>
-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
@@ -950,21 +1193,25 @@ bool SharedCache<A>::notUpToDate(const void* cache)
                        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
-       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 {
-                       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;
                }
        }
+       // 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());
@@ -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 ) {
+                               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;
@@ -986,6 +1237,10 @@ bool SharedCache<A>::notUpToDate(const void* cache)
                                }
                        }
                        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) 
@@ -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 {
-                               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;
                        }
                }
@@ -1024,7 +1279,7 @@ bool SharedCache<A>::notUpToDate(const void* cache)
 
 
 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);        
@@ -1032,20 +1287,27 @@ bool SharedCache<A>::notUpToDate(const char* path)
                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);
-       if ( mappingAddr == (uint8_t*)(-1) )
-               return true;
 
        // 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
-               ::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);
        }
@@ -1128,7 +1390,7 @@ template <typename A>
 class LinkEditOptimizer
 {
 public:
-                                                                                       LinkEditOptimizer(const MachOLayoutAbstraction&, uint8_t*, StringPool&);
+                                                                                       LinkEditOptimizer(const MachOLayoutAbstraction&, const SharedCache<A>&, uint8_t*, StringPool&);
        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                                                            copyFunctionStarts(uint32_t& offset);
                void                                                            updateLoadCommands(uint64_t newVMAddress, uint64_t size, uint32_t stringPoolOffset, 
                                                                                                                                uint32_t linkEditsFileOffset, bool keepSignatures);
        
@@ -1151,12 +1414,14 @@ protected:
                        
 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;
+       macho_linkedit_data_command<P>*                         fFunctionStarts;
        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                                                                        fFunctionStartsOffsetInNewLinkEdit;
 };
 
 
 
 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),
@@ -1195,7 +1461,8 @@ LinkEditOptimizer<A>::LinkEditOptimizer(const MachOLayoutAbstraction& layout, ui
        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();
@@ -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_FUNCTION_STARTS:
+                               fFunctionStarts = (macho_linkedit_data_command<P>*)cmd;
+                               break;
                }
                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)
 {
-       if ( (fDyldInfo != NULL) && (fDyldInfo->export_off() != 0) ) {
+       if ( (fDyldInfo != NULL) && (fLayout.getDyldInfoExports() != NULL) ) {
                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();
        }
 }
@@ -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;
-                       newSymbolEntry->set_n_strx(fNewStringPool.add(&fStrings[entry->n_strx()]));
+                       newSymbolEntry->set_n_strx(fNewStringPool.addUnique(&fStrings[entry->n_strx()]));
                        ++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;
-                       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;
                }
@@ -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)
 {      
@@ -1431,6 +1710,20 @@ void LinkEditOptimizer<A>::updateLoadCommands(uint64_t newVMAddress, uint64_t si
                                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());
        }       
@@ -1475,6 +1768,11 @@ void LinkEditOptimizer<A>::updateLoadCommands(uint64_t newVMAddress, uint64_t si
        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;
@@ -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) {
-               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
@@ -1567,33 +1865,45 @@ uint8_t* SharedCache<A>::optimizeLINKEDIT(bool keepSignatures)
                (*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
-       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) {
-               (*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
-       uint32_t indirectSymbolTableOffset = externalRelocsOffset;
+       fOffsetOfOldIndirectSymbolsInCombinedLinkedit = offset;
        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
-       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) {
-               (*it)->updateLoadCommands(fLinkEditsStartAddress, fLinkEditsTotalUnoptimizedSize, stringPoolOffset, linkEditsFileOffset, keepSignatures);
+               (*it)->updateLoadCommands(fLinkEditsStartAddress, fLinkEditsTotalUnoptimizedSize, fOffsetOfOldStringPoolInCombinedLinkedit, linkEditsFileOffset, keepSignatures);
        }
 
        //fprintf(stderr, "fLinkEditsTotalUnoptimizedSize=%llu, fLinkEditsTotalOptimizedSize=%u\n", fLinkEditsTotalUnoptimizedSize, fLinkEditsTotalOptimizedSize);
@@ -1627,7 +1937,7 @@ template <typename A>
 class ObjCSelectorUniquer
 {
 private:
-    objc_selopt::string_map fSelectorStrings;
+    objc_opt::string_map fSelectorStrings;
     SharedCache<A> *fCache;
     size_t fCount;
 
@@ -1643,97 +1953,164 @@ public:
     {
         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;
     }
 
-    objc_selopt::string_map& strings() { 
+    objc_opt::string_map& strings() { 
         return fSelectorStrings;
     }
 
     size_t count() const { return fCount; }
 };
 
-template <>
-void SharedCache<arm>::optimizeObjC()
-{
-       // objc optimizations on arm not yet supported
-}
-
 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 ) {
-        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) {
-        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
-    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.
+    ObjCSelectorUniquer<A> uniq(this);
     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);
-        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());
     }
 
-    // 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 ) {
+        size_t totalSize = headerSize + selTableSize;
         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, "
+                "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;
 }
 
@@ -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)
@@ -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;
-                               if ( end > cacheFileSize )
+                               if ( end > cacheFileSize ) 
                                        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_imagesCount(fDylibs.size());
+                       header->set_imagesCount(fDylibs.size()+fDylibAliases.size());
                        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>)];
@@ -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_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;
                        }
                                                
@@ -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();
-                                                       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 )
@@ -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 )
-                                               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);
                                }
                        }
+       
+                       // 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);
-                                       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);
                                }
@@ -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
@@ -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 {
-                                       (*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());
@@ -1953,16 +2353,118 @@ bool SharedCache<A>::update(bool usesOverlay, bool force, bool optimize, bool de
                                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
-            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 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;
@@ -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);
                                
-                               // 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);
-                                       
+                               
+                               
                                // 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);
-                                       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+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 (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];
@@ -2227,7 +2771,15 @@ static void parsePathsFile(const char* filePath, std::vector<const char*>& paths
                                                *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;
                                }
@@ -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 ( 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 ) {
+                               struct stat tmpStatPathsFile;
                                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);
@@ -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()
 {
-       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 ) {
-                                       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;
@@ -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
-                                       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
-                                       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:
                                {
-                                       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:
                                {
-                                       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:
                                {
-                                       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;
                }
        }
        
-       deleteOrphanTempCacheFiles();
+       if ( !iPhoneOS )
+               deleteOrphanTempCacheFiles();
        
        return didUpdate;
 }
@@ -2436,6 +2998,7 @@ int main(int argc, const char* argv[])
        bool hasOverlay = false;
        bool verify = false;
        bool keepSignatures = false;
+       const char* cacheDir = NULL;
        
        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, "-iPhone") == 0 ) {
+                                       iPhoneOS = true;
+                               }
                                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 )
@@ -2485,6 +3050,11 @@ int main(int argc, const char* argv[])
                                                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 ) 
@@ -2523,41 +3093,55 @@ int main(int argc, const char* argv[])
                }
                                
                // 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' ) {
-                       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 ) {
-                       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));
+                               }
+                               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) )
@@ -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);
-               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) {
index 23f89cbde1341333932f7daea3e7164f2576421b..3b0e8242155f1c6829f64b00821761a329866ddc 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- 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@
  * 
@@ -40,7 +40,6 @@
 
 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;
@@ -59,6 +58,7 @@ uint64_t                                                              ImageLoader::fgTotalWeakBindTime;
 uint64_t                                                               ImageLoader::fgTotalDOF;
 uint64_t                                                               ImageLoader::fgTotalInitTime;
 uint16_t                                                               ImageLoader::fgLoadOrdinal = 0;
+std::vector<ImageLoader::InterposeTuple>ImageLoader::fgInterposingTuples;
 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), 
-       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),
-       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 )
@@ -82,9 +83,11 @@ void ImageLoader::deleteImage(ImageLoader* image)
 {
        // this cannot be done in destructor because libImage() is implemented
        // in a subclass
+       DependentLibraryInfo libraryInfos[image->libraryCount()]; 
+       image->doGetDependentLibraries(libraryInfos);
        for(unsigned int i=0; i < image->libraryCount(); ++i) {
                ImageLoader* lib = image->libImage(i);
-               if ( lib != NULL )
+               if ( (lib != NULL) && ! libraryInfos[i].upward )
                        lib->fStaticReferenceCount--;
        }
        delete image;
@@ -96,7 +99,7 @@ ImageLoader::~ImageLoader()
        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;
@@ -118,10 +121,20 @@ void ImageLoader::setMapped(const LinkContext& context)
 
 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());
@@ -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);
+               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) )
@@ -332,11 +352,20 @@ const ImageLoader::Symbol* ImageLoader::findExportedSymbolInImageOrDependentImag
        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);
        
+       // 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);
@@ -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 t5 = mach_absolute_time();     
+
        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);
-       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;
-       fgTotalDOF += t6 - t5;
+       fgTotalDOF += t7 - t6;
        
        // done with initial dylib loads
        fgNextPIEDylibAddress = 0;
@@ -393,11 +431,11 @@ bool ImageLoader::decrementDlopenReferenceCount()
        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();
-       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();
@@ -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
-                               setLibImage(i, NULL, false);
+                               setLibImage(i, NULL, false, false);
                                continue;
                        }
 #endif
@@ -500,7 +538,8 @@ void ImageLoader::recursiveLoadLibraries(const LinkContext& context, bool prefli
                                }
                                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 );
@@ -511,13 +550,18 @@ void ImageLoader::recursiveLoadLibraries(const LinkContext& context, bool prefli
                                }
                                // 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);
                                }
-                               // 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;
+                                       
                                //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;
+                                       // 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
                        }
-                       setLibImage(i, dependentLib, depLibReExported);
+                       setLibImage(i, dependentLib, depLibReExported, requiredLibInfo.upward);
                }
                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;
+            CRSetCrashLogMessage2(NULL);
                        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;
+            CRSetCrashLogMessage2(NULL);
                        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;
+       int countOfImagesWithWeakDefinitionsNotInSharedCache = 0;
        for(int i=0; i < count; ++i) {
                if ( ! imagesNeedingCoalescing[i]->fWeakSymbolsBound )
                        ++countNotYetWeakBound;
-               if ( imagesNeedingCoalescing[i]->hasCoalescedExports() )
+               if ( imagesNeedingCoalescing[i]->hasCoalescedExports() ) {
                        ++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
-       if ( (countOfImagesWithWeakDefinitions > 1) && (countNotYetWeakBound > 0) ) {
+       if ( (countOfImagesWithWeakDefinitionsNotInSharedCache > 0) && (countNotYetWeakBound > 0) ) {
                // 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);
@@ -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
-                               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
@@ -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
+                       uint64_t t1 = mach_absolute_time();
                        fState = dyld_image_state_dependents_initialized;
                        oldState = fState;
                        context.notifySingle(dyld_image_state_dependents_initialized, this);
-
+                       
                        // 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);
+                       
+                       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
@@ -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);
-       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);
@@ -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);
+       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 -*-
  *
- * Copyright (c) 2004-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <mach-o/nlist.h> 
 #include <stdint.h>
 #include <vector>
-#include <set>
 #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"
 
        #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 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 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
@@ -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)));
+#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);
+               void                    (*setErrorStrings)(unsigned errorCode, const char* errorClientOfDylibPath,
+                                                                               const char* errorTargetDylibPath, const char* errorSymbol);
 #if SUPPORT_OLD_CRT_INITIALIZATION
                void                    (*setRunInitialzersOldWay)();
 #endif
@@ -188,7 +213,6 @@ public:
                bool                    bindFlat;
                bool                    linkingMainExecutable;
                bool                    startedInitializingMainExecutable;
-               bool                    noPIE;
                bool                    processIsRestricted;
                bool                    verboseOpts;
                bool                    verboseEnv;
@@ -199,7 +223,10 @@ public:
                bool                    verboseInit;
                bool                    verboseDOF;
                bool                    verbosePrebinding;
+               bool                    verboseCoreSymbolication;
                bool                    verboseWarnings;
+               bool                    verboseRPaths;
+               bool                    verboseInterposing;
        };
        
        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;
        
+       struct InitializerTimingList
+       {
+               uintptr_t       count;
+               struct {
+                       ImageLoader*    image;
+                       uint64_t                initTime;
+               }                       images[1];
+       };
        
        
                                                                                // 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
-       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);
@@ -272,6 +307,9 @@ public:
                                                                                // 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;
 
@@ -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 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;
@@ -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                                       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;
@@ -414,6 +454,13 @@ public:
        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; }
        
@@ -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
-       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);
@@ -481,9 +528,16 @@ protected:
                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);
        
@@ -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;
-       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.
@@ -504,8 +559,9 @@ protected:
        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                            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;
@@ -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;
        
+                                                               // do interpose
+       virtual void                            doInterpose(const LinkContext& context) = 0;
+
                                                                // 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;
@@ -560,7 +619,6 @@ protected:
        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;
@@ -578,6 +636,7 @@ protected:
        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;
@@ -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
-       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 {
@@ -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
+                                                               fInterposed : 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 -*-
  *
- * Copyright (c) 2004-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -27,7 +27,7 @@
 #define __eip  eip 
 #define __rip  rip 
 
-
+#define __STDC_LIMIT_MACROS
 #include <string.h>
 #include <fcntl.h>
 #include <errno.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"
 
+// <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__
@@ -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),
-       fHasInitializers(false), fHasTerminators(false)
+       fHasInitializers(false), fHasTerminators(false), fGoodFirstSegment(false), fRegisteredAsRequiresCoalescing(false)
 {
        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, 
-                                                                                       unsigned int* segCount, unsigned int* libCount)
+                                                                                       unsigned int* segCount, unsigned int* libCount,
+                                                                                       const linkedit_data_command** codeSigCmd)
 {
        *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);
@@ -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_UPWARD_DYLIB:
                                *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);
@@ -163,7 +175,8 @@ ImageLoader* ImageLoaderMachO::instantiateMainExecutable(const macho_header* mh,
        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);
@@ -190,27 +203,29 @@ ImageLoader* ImageLoaderMachO::instantiateFromFile(const char* path, int fd, con
        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 ) 
-               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
-               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
-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;
-       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::instantiateFromCache(mh, path, info, segCount, libCount, context);
+               return ImageLoaderMachOCompressed::instantiateFromCache(mh, path, slide, info, segCount, libCount, context);
        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
@@ -219,7 +234,8 @@ ImageLoader* ImageLoaderMachO::instantiateFromMemory(const char* moduleName, con
        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);
@@ -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 ( segHasRebaseFixUps(i) )
+                       if ( segHasRebaseFixUps(i) && (fSlide != 0) )
                                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;
+               fRegisteredAsRequiresCoalescing = true;
                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_LOAD_UPWARD_DYLIB:
                                // 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()
 {
-       // keep count of images with weak exports
-       if ( this->participatesInCoalescing() ) {
+       // update count of images with weak exports
+       if ( fRegisteredAsRequiresCoalescing ) {
                --fgImagesRequiringCoalescing;
                if ( this->hasCoalescedExports() ) 
                        --fgImagesHasWeakDefinitions;
@@ -629,36 +647,16 @@ void ImageLoaderMachO::setSlide(intptr_t slide)
 }
 
 #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
 
@@ -672,6 +670,52 @@ const char* ImageLoaderMachO::getInstallPath() const
        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
@@ -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_UPWARD_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->upward = false;
        }
        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_UPWARD_DYLIB:
                                {
                                        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->upward = (cmd->cmd == LC_LOAD_UPWARD_DYLIB);
                                }
                                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:
+                               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) ) {
@@ -825,7 +874,7 @@ void ImageLoaderMachO::getRPaths(const LinkContext& context, std::vector<const c
                                                        strcpy(&addPoint[1], &path[13]);
                                                else
                                                        strcpy(newRealPath, &path[13]);
-                                               path = strdup(newRealPath);
+                                               pathToAdd = strdup(newRealPath);
                                        }
                                }
                                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]);
-                                               path = strdup(newRealPath);
+                                               pathToAdd = strdup(newRealPath);
                                        }
                                }
                                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);
-                                                       path = strdup(newPath);
+                                                       pathToAdd = strdup(newPath);
                                                        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
-                                       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);
@@ -972,8 +1022,9 @@ void ImageLoaderMachO::makeTextSegmentWritable(const LinkContext& context, bool
                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));
+               segProtect(textSegmentIndex, context);
        }
 }
 #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;
 }
 
@@ -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); 
 }
 
@@ -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);
        }
+#if LOG_BINDINGS
+//     dyld::logBindings("%s: %s\n", targetImage->getShortName(), symbolName);
+#endif
        
        // 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 )
-               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 )
-               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 )
-               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 )
-               vars.__prognamePtr = (const char**)this->getExportedSymbolAddress(sym, context, this);
+               vars.__prognamePtr = (const char**)this->getExportedSymbolAddress(sym, context, this, false);
                
        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
-       if ( (this->isPrebindable() || fInSharedCache)
-               && (this->getSlide() == 0) 
+       if ( ((this->isPrebindable() && (this->getSlide() == 0)) || fInSharedCache)
                && 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 ) {
+#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;
@@ -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);
-                                       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);
@@ -1402,6 +1492,16 @@ void ImageLoaderMachO::doImageInit(const LinkContext& context)
 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;
@@ -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];
-                                                       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);
+       
+       CRSetCrashLogMessage2(NULL);
+       
+       return (fHasDashInit || fHasInitializers);
 }
 
 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 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)) )
-                               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 {
@@ -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 ) {
-               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;
@@ -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());
+       // <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);
-               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) ) {
-                       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;
@@ -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);
                        }
-                       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", 
-                                       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 )
-                       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' : '.' );
        }
+
        // 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);
-       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' : '.' );
@@ -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;
-       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);
-       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' : '.' );
index 5d735bfc764a9b03a0b80578939ea461b4e0c4cb..a2b657a9c554aa9b426daf5202cf732030f9f7c2 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- 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@
  * 
@@ -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*                                     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);
 
 
+       bool                                                            inSharedCache() const { return fInSharedCache; }
        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 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;
@@ -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                                       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);
@@ -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 void                                            registerInterposing();
                        
        
-       static void                                                     printStatistics(unsigned int imageCount);
+       static void                                                     printStatistics(unsigned int imageCount, const InitializerTimingList&);
        
 protected:
                                                ImageLoaderMachO(const ImageLoaderMachO&);
@@ -108,7 +111,7 @@ protected:
 
        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;
@@ -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 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;
@@ -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            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;      
@@ -150,10 +153,11 @@ protected:
 
                        void            destroy();
        static void                     sniffLoadCommands(const macho_header* mh, const char* path, bool* compressed,
-                                                                                       unsigned int* segCount, unsigned int* libCount);
+                                                                                       unsigned int* segCount, unsigned int* libCount,
+                                                                                       const linkedit_data_command** codeSigCmd);
        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();
@@ -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            __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);
@@ -183,8 +188,10 @@ protected:
                        void            preFetchDATA(int fd, uint64_t offsetInFat, const LinkContext& context);
 
 
+                       void            doInterpose(const LinkContext& context) = 0;
                        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:                     
@@ -210,7 +217,9 @@ protected:
                                                                                        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;
index 182047e1df697115d5b166a96aa50f4605591fac..33b055d94bee273ef19a8d5c9a851f3de26d7171 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- 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@
  * 
@@ -106,11 +106,12 @@ ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateMainExecutable(cons
        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);
-       
+       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 ) {
@@ -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, 
-                                                                                                                       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);
 
-               // mmap segments
-               image->mapSegmentsClassic(fd, offsetInFat, lenInFat, info.st_size, context);
-
        #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
                
+               // 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] == '/') )
@@ -168,13 +174,14 @@ ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateFromFile(const char
                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);
 
-               // finish up
-               image->instantiateFinish(context);
        }
        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
-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);
@@ -208,6 +215,7 @@ ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateFromCache(const mac
                }
 
                image->instantiateFinish(context);
+               image->setMapped(context);
        }
        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->setMapped(context);
        }
        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();
-       
-       // notify state change
-       this->setMapped(context);
 }
 
 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)));
-       // 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
@@ -309,13 +315,22 @@ bool ImageLoaderMachOClassic::libReExported(unsigned int libIndex) const
        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;
+       if ( upward ) 
+               value |= 2;
        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    
-       // 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
 
@@ -779,6 +797,7 @@ void ImageLoaderMachOClassic::resetPreboundLazyPointers(const LinkContext& conte
 
 void ImageLoaderMachOClassic::rebase(const LinkContext& context)
 {
+       CRSetCrashLogMessage2(this->getPath());
        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;
+       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;
@@ -1066,9 +1086,9 @@ bool ImageLoaderMachOClassic::symbolIsWeakReference(const struct macho_nlist* sy
        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, 
@@ -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
-                       uintptr_t addr = this->getSymbolAddress(undefinedSymbol, context);
+                       uintptr_t addr = this->getSymbolAddress(undefinedSymbol, context, false);
                        *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;
                }
-               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)
@@ -1118,14 +1138,14 @@ uintptr_t ImageLoaderMachOClassic::resolveUndefined(const LinkContext& context,
                                        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
-                       uintptr_t addr = this->getSymbolAddress(undefinedSymbol, context);
+                       uintptr_t addr = this->getSymbolAddress(undefinedSymbol, context, false);
                        *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);
                        
-                       throwSymbolNotFound(symbolName, this->getPath(), "dynamic lookup");
+                       throwSymbolNotFound(context, symbolName, this->getPath(), "dynamic lookup");
                }
                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;
-                       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
@@ -1186,7 +1206,7 @@ uintptr_t ImageLoaderMachOClassic::resolveUndefined(const LinkContext& context,
                }
                
                // 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;
 }
 
-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";
 }
@@ -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());
+#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;
+#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 )
-                                                       addend += 1;
+                                                       addend &= -2;
                        #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);
+               #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
@@ -1905,6 +1938,7 @@ void ImageLoaderMachOClassic::initializeLazyStubs(const LinkContext& context)
 
 void ImageLoaderMachOClassic::doBind(const LinkContext& context, bool forceLazysBound)
 {
+       CRSetCrashLogMessage2(this->getPath());
 #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:
                
+       #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);
                
@@ -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 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);
+       
+       CRSetCrashLogMessage2(NULL);
 }
 
 void ImageLoaderMachOClassic::doBindJustLazies(const LinkContext& context)
@@ -1937,6 +1984,100 @@ void ImageLoaderMachOClassic::doBindJustLazies(const LinkContext& context)
        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;
@@ -1970,7 +2111,14 @@ const char* ImageLoaderMachOClassic::findClosestSymbol(const void* addr, const v
                }
        }
        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);
+#endif
                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*         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);
@@ -51,11 +52,12 @@ public:
 
        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 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&);
@@ -63,6 +65,7 @@ public:
        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;
@@ -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 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;
@@ -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);
-       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, 
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;
 
-               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;
                }
-       } 
-       while (*p++ & 0x80);
+       } while (*p++ & 0x80);
        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
-       if ( (mh->flags & MH_PIE) && !context.noPIE )
+       if ( slide != 0 )
                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);
@@ -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, 
-                                                                                                                       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);
 
@@ -139,6 +140,12 @@ ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromFile(cons
                // record info about file  
                image->setFileInfo(info.st_dev, info.st_ino, info.st_mtime);
 
+       #if CODESIGNING_SUPPORT
+               // if this image is code signed, let kernel validate signature before mapping any pages from image
+               if ( codeSigCmd != NULL )
+                       image->loadCodeSignature(codeSigCmd, fd, offsetInFat);
+       #endif
+               
                // mmap segments
                image->mapSegments(fd, offsetInFat, lenInFat, info.st_size, context);
 
@@ -165,6 +172,9 @@ ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromFile(cons
                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()) {
@@ -183,8 +193,9 @@ ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromFile(cons
 }
 
 // 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 {
@@ -193,7 +204,9 @@ ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromCache(con
 
                // remember this is from shared cache and cannot be unloaded
                image->fInSharedCache = true;
+               image->fGoodFirstSegment = true;
                image->setNeverUnload();
+               image->setSlide(slide);
 
                // segments already mapped in cache
                if ( context.verboseMapping ) {
@@ -204,6 +217,7 @@ ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromCache(con
                }
 
                image->instantiateFinish(context);
+               image->setMapped(context);
        }
        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->setMapped(context);
        }
        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();
-               
-       // notify state change
-       this->setMapped(context);
 }
 
 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)));
-       // 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
@@ -306,13 +318,22 @@ bool ImageLoaderMachOCompressed::libReExported(unsigned int libIndex) const
        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;
+       if ( upward ) 
+               value |= 2;
        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";
-               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)
 {
+       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];
@@ -481,70 +503,117 @@ void ImageLoaderMachOCompressed::rebase(const LinkContext& context)
                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 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) ) {
-                       // 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;
+                       //dyld::log("trieWalk(%p) child str=%s\n", start, (char*)p);
                        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
-                       while ( *e != '\0' ) {
+                       char c = *p;
+                       while ( c != '\0' ) {
                                if ( !wrongEdge ) {
-                                       if ( *e != *ss++ )
+                                       if ( c != *ss )
                                                wrongEdge = true;
+                                       ++ss;
                                }
-                               ++e;
+                               ++p;
+                               c = *p;
                        }
                        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 {
-                               // the symbol so far matches this edge (child)
+                               // the symbol so far matches this edge (child)
                                // 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;
-                               //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;
                        }
                }
-               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 {
-                       //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";
+       //dyld::log("exportedSymbolAddress(): node=%p, nodeOffset=0x%04X in %s\n", symbol, (int)((uint8_t*)symbol - exportTrieStart), this->getShortName());
        uint32_t flags = read_uleb128(exportNode, exportTrieEnd);
-       if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_REGULAR )
+       if ( (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;
+       }
        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
@@ -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);
-               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 )
-                       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;
        }
-       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, 
-                                                                                               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 ) {
-               return (*foundIn)->getExportedSymbolAddress(sym, context, this);
+               return (*foundIn)->getExportedSymbolAddress(sym, context, this, runResolver);
        }
        
        if ( weak_import ) {
@@ -652,13 +739,13 @@ uintptr_t ImageLoaderMachOCompressed::resolveTwolevel(const LinkContext& context
        }
 
        // 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,
-                                                                                                       LastLookup* last)
+                                                                                                       LastLookup* last, bool runResolver)
 {
        *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) ) {
-               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 ) {
@@ -706,7 +793,7 @@ uintptr_t ImageLoaderMachOCompressed::resolve(const LinkContext& context, const
                        }
                }
                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, 
-                                                               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
-       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);
@@ -746,28 +834,50 @@ void ImageLoaderMachOCompressed::throwBadBindingAddress(uintptr_t address, uintp
 
 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 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);
                        
-               // 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
-               if ( forceLazysBound || fInSharedCache )
+               if ( forceLazysBound || fInSharedCache ) 
                        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);
-       
-       // 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);
-                                       (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);
-                                       (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);
-                                       (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:
@@ -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);
-                                               (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;
@@ -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);
-                                       (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:
@@ -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];
-       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;
@@ -1094,7 +1217,9 @@ uintptr_t ImageLoaderMachOCompressed::doBindFastLazySymbol(uint32_t lazyBindingI
                                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:
@@ -1105,6 +1230,12 @@ uintptr_t ImageLoaderMachOCompressed::doBindFastLazySymbol(uint32_t lazyBindingI
                                dyld::throwf("bad lazy bind opcode %d", *p);
                }
        }       
+       
+       if ( !this->usesTwoLevelNameSpace() ) {
+               // release dyld global lock
+               if ( unlock != NULL )
+                       unlock();
+       }
        return result;
 }
 
@@ -1290,6 +1421,35 @@ void ImageLoaderMachOCompressed::updateUsesCoalIterator(CoalIterator& it, uintpt
                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 __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);
+#endif
                return &symbolTableStrings[bestSymbol->n_un.n_strx];
        }
        return NULL;
@@ -1368,3 +1535,96 @@ void ImageLoaderMachOCompressed::resetPreboundLazyPointers(const LinkContext& co
 }
 #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*      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);
@@ -52,11 +53,12 @@ public:
 
        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 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&);
@@ -65,6 +67,7 @@ public:
 
        
 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; }
@@ -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 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;
@@ -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, 
-                                                                                       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);
@@ -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,
-                                                                                               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, 
-                                                                                               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 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;
 };
 
index 3d5bcd000bdb7cd7a7305d69a04149482f31ef51..d86e0b1717850cd5b37816474212680108331e20 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- 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@
  * 
 #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/syscall.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 <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_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>
@@ -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 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" {
@@ -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_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;
@@ -130,6 +146,7 @@ struct EnvironmentVariables {
        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
@@ -149,16 +166,21 @@ struct EnvironmentVariables {
                                                        //      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; };
+struct DylibOverride { const char* installName; const char* override; };
 
 // 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;
+#endif
 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 long                                                    sSharedCacheSlide = 0;
 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;
@@ -187,7 +216,7 @@ const struct LibSystemHelpers*              gLibSystemHelpers = NULL;
 #if SUPPORT_OLD_CRT_INITIALIZATION
 bool                                                           gRunInitializersOldWay = false;
 #endif
-
+static std::vector<DylibOverride>      sDylibOverrides;
 
 //
 // 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;
 
+#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;
@@ -432,10 +490,13 @@ static void notifyAddImageCallbacks(ImageLoader* image)
 }
 
 
+
 // 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;
 }
 
@@ -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 ( 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);
                        }
                }
        }
-#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 ( 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++) {
@@ -584,6 +705,8 @@ static void notifyBatchPartial(dyld_image_states state, bool orLater, dyld_image
 #endif
 }
 
+
+
 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);
        
+       // <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);
 
@@ -747,19 +874,26 @@ const char* getExecutablePath()
 
 void initializeMainExecutable()
 {
+       // apply interposing to initial set of images
+       // do this before making the __IMPORT segments in shared cache read-only
+       sMainExecutable->applyInterposing(gLinkContext);
 
        // record that we've reached this step
        gLinkContext.startedInitializingMainExecutable = true;
 
        // run initialzers for any inserted dylibs
+       ImageLoader::InitializerTimingList initializerTimes[sAllImages.size()];
        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 
-       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 ) 
@@ -767,7 +901,7 @@ void initializeMainExecutable()
 
        // dump info if requested
        if ( sEnv.DYLD_PRINT_STATISTICS )
-               ImageLoaderMachO::printStatistics(sAllImages.size());
+               ImageLoaderMachO::printStatistics(sAllImages.size(), initializerTimes[0]);
 }
 
 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 };
 
@@ -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;
-                       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);
-       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;
        
+       //dyld::log("parseColonList(%s)\n", list);
+       //for(int i=0; result[i] != NULL; ++i)
+       //      dyld::log("  %s\n", result[i]);
        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)
 {
@@ -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 ) {
-               sEnv.DYLD_FRAMEWORK_PATH = parseColonList(value);
+               appendParsedColonList(value, mainExecutableDir, &sEnv.DYLD_FRAMEWORK_PATH);
        }
        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 ) {
-               sEnv.DYLD_LIBRARY_PATH = parseColonList(value);
+               appendParsedColonList(value, mainExecutableDir, &sEnv.DYLD_LIBRARY_PATH);
        }
        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 ) {
-                       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");
@@ -928,7 +1240,7 @@ void processDyldEnvironmentVarible(const char* key, const char* value)
                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;
@@ -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_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 ) {
@@ -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");
                }
        }
+#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);
        }
 }
 
 
+#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
@@ -1066,6 +1455,8 @@ static void pruneEnvironmentVariables(const char* envp[], const char*** applep)
                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
@@ -1088,7 +1479,7 @@ static void checkEnvironmentVariables(const char* envp[], bool ignoreEnviron)
                                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 ) {
@@ -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];
-                       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 ) {
@@ -1119,34 +1514,38 @@ static void checkEnvironmentVariables(const char* envp[], bool ignoreEnviron)
                        paths_expand_roots(paths, "$HOME", home);
                sEnv.DYLD_FALLBACK_LIBRARY_PATH = paths;
        }
+       
+#if SUPPORT_VERSIONED_PATHS
+       checkVersionedPaths();
+#endif 
 }
 
 
 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";
-       
        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()
 {
-       #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)) ) {
@@ -1154,7 +1553,8 @@ static void checkSharedRegionDisable()
                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)
@@ -1563,70 +1963,73 @@ static ImageLoader* instantiateFromLoadedImage(const macho_header* mh, uintptr_t
        throw "main executable not a known format";
 }
 
+
 #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 ) {
-               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) {
+#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 
-                               || ( ((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
-                               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 ( 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 ) {
-                                       // 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;
                                }
                        }
+#endif
                }       
        }
        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)
@@ -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);
+                                       removeImage(image);
                                        ImageLoader::deleteImage(image);
                                        return anImage;
                                }
@@ -1667,7 +2071,7 @@ static ImageLoader* checkandAddImage(ImageLoader* image, const LoadContext& cont
 }
 
 // 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;
@@ -1706,10 +2110,20 @@ static ImageLoader* loadPhase6(int fd, struct stat& stat_buf, const char* path,
        }
        
        // try mach-o loader
+       if ( shortPage ) 
+               throw "file too short";
        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);
                
@@ -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;
@@ -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
-       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
-       
-       // 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
-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);
@@ -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());
-               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 ( 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);
@@ -1826,37 +2351,46 @@ static ImageLoader* loadPhase5check(const char* path, const LoadContext& context
 
 
 // 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);
+       
+       // 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 ) 
-               return loadPhase5open(path, context, exceptions);
+               return loadPhase5load(path, orgPath, context, exceptions);
        else
-               return loadPhase5check(path, context);
+               return loadPhase5check(path, orgPath, context);
 }
 
 // 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);
-               image = loadPhase5(pathWithSuffix, context, exceptions);
+               image = loadPhase5(pathWithSuffix, orgPath, context, exceptions);
        }
        if ( image == NULL )
-               image = loadPhase5(path, context, exceptions);
+               image = loadPhase5(path, orgPath, context, exceptions);
        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
-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;
@@ -1873,7 +2407,7 @@ static ImageLoader* loadPhase3(const char* path, const LoadContext& context, std
                        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;
 
@@ -1887,7 +2421,7 @@ static ImageLoader* loadPhase3(const char* path, const LoadContext& context, std
                                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;
                }
@@ -1904,7 +2438,7 @@ static ImageLoader* loadPhase3(const char* path, const LoadContext& context, std
                        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;
                
@@ -1918,7 +2452,7 @@ static ImageLoader* loadPhase3(const char* path, const LoadContext& context, std
                                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;
                }
@@ -1934,7 +2468,13 @@ static ImageLoader* loadPhase3(const char* path, const LoadContext& context, std
                                        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;
                                }
@@ -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 ) {
-                       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;
                }
@@ -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);
        }
        
-       return loadPhase4(path, context, exceptions);
+       return loadPhase4(path, orgPath, context, exceptions);
 }
 
 
 // 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)
 {
@@ -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);
-                               image = loadPhase4(npath, context, exceptions);
+                               image = loadPhase4(npath, orgPath, context, exceptions);
                                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);
-                       image = loadPhase4(libpath, context, exceptions);
+                       image = loadPhase4(libpath, orgPath, context, exceptions);
                        if ( image != NULL )
                                return image;
                }
@@ -2001,27 +2541,27 @@ static ImageLoader* loadPhase2(const char* path, const LoadContext& context,
 }
 
 // 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) ) {
-               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)) ) {
-               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
-       image = loadPhase3(path, context, exceptions);
+       image = loadPhase3(path, orgPath, context, exceptions);
        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)) ) {
-               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;
        }
@@ -2039,7 +2579,7 @@ static ImageLoader* loadPhase1(const char* path, const LoadContext& context, std
 }
 
 // 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);
 
@@ -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);
-                       ImageLoader* image = loadPhase1(newPath, context, exceptions);
+                       ImageLoader* image = loadPhase1(newPath, orgPath, context, exceptions);
                        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)
 {
+       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
@@ -2084,18 +2627,36 @@ ImageLoader* load(const char* path, const LoadContext& context)
        }
        
        // 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;
+       }
 
-       // 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;
-       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;
+       }
        else if ( exceptions.size() == 0 ) {
-               if ( context.dontLoad )
+               if ( context.dontLoad ) {
                        return NULL;
+               }
                else
                        throw "image not found";
        }
@@ -2122,44 +2683,83 @@ ImageLoader* load(const char* path, const LoadContext& context)
 #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)
 {
-       if ( (gLinkContext.sharedRegionMode == ImageLoader::kUseSharedRegion) && newSharedRegionSyscallAvailable() 
+       if ( (gLinkContext.sharedRegionMode == ImageLoader::kUseSharedRegion) ) 
                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);
        
+       // 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()
-       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;
+               //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;
@@ -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;
-               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;
@@ -2227,6 +2839,58 @@ int openSharedCacheFile()
        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;
@@ -2239,6 +2903,17 @@ static void mapSharedCache()
                        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__
@@ -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
-                       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 ) {
-                                               ::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;
                                        }
@@ -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 ) {
-                                       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;
-                                               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.
-                                                       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;
                                                        }
                                                }
+#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;
@@ -2302,16 +3003,43 @@ static void mapSharedCache()
                                                        }                                       
                                                }
                                                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;
                                                }
                                        }
-                                                                               
+#endif                                                                         
                                        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;
+                                                       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 ) {
-               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::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 )
-                               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;
-               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 ) {
-                               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 ( (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_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 ) {
-                                               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
                }
+#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.origin                          = false;
-       context.rpath                           = false;
+       context.origin                          = NULL;
+       context.rpath                           = NULL;
        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;
-       if ( !gLinkContext.startedInitializingMainExecutable )
+       if ( !gLinkContext.startedInitializingMainExecutable ) 
                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)
 {
@@ -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;
@@ -2554,7 +3312,9 @@ uintptr_t fastBindLazySymbol(ImageLoader** imageLoaderCache, uintptr_t lazyBindi
        
        // 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);
@@ -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;
 }
-#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
+       gLinkContext.setErrorStrings            = &setErrorStrings;
 #if SUPPORT_OLD_CRT_INITIALIZATION
        gLinkContext.setRunInitialzersOldWay= &setRunInitialzersOldWay;
 #endif
@@ -2851,8 +3611,70 @@ static bool hasRestrictedSegment(const macho_header* mh)
                
        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()
 {
@@ -2866,7 +3688,6 @@ static void printAllImages()
 }
 #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
@@ -2891,7 +3712,9 @@ void link(ImageLoader* image, bool forceLazysBound, const ImageLoader::RPathChai
 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()
@@ -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.
@@ -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[])
 {      
+       CRSetCrashLogMessage("dyld: launch started");
 #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
+
+#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.
@@ -3016,13 +3886,18 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int a
        }
        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);
+               // 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 ) 
@@ -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);
+       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);
@@ -3046,6 +3922,7 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int a
 #endif
        
        try {
+               CRSetCrashLogMessage("dyld: launch, loading dependent libraries");
                // 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));
+                               // 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 ) 
@@ -3093,6 +3973,7 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int a
                initializeMainExecutable(); // run all initializers
        }
        catch(const char* message) {
+               syncAllImages();
                halt(message);
        }
        catch(...) {
@@ -3106,6 +3987,7 @@ _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int a
                sLogfile = STDERR_FILENO;
        }
 #endif
+       CRSetCrashLogMessage(NULL);
        
        return result;
 }
index 2deab7dbaf58df8faa474fce90f278ea22841264..9ad1ef8b7ea139da70dff3a0ca3cfc497e507a17 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- 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@
  * 
@@ -59,6 +59,7 @@ namespace dyld {
 
        extern ImageLoader::LinkContext                 gLinkContext;
        extern bool                                                             gLogAPIs;
+       extern bool                                                             gSharedCacheOverridden;
        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                                     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();
@@ -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);
-
+#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"
 
+// 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   
@@ -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.
-static void _dyld_fork_child();
 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
+#if !__arm__
 static bool client_dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info);
+#endif
 
 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_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 },
@@ -136,13 +141,17 @@ static struct dyld_func dyld_funcs[] = {
 #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 },
+#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
+    {"__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 },
@@ -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);
                }
-                       
+               
                // 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);
+                       // <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 )
@@ -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
-static void _dyld_fork_child()
+void _dyld_fork_child()
 {
        if ( dyld::gLogAPIs )
                dyld::log("%s()\n", __func__);
@@ -1243,12 +1259,23 @@ bool lookupDyldFunction(const char* name, uintptr_t* address)
        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;       
+       
+#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
        
+       CRSetCrashLogMessage("dyld: in dlopen_preflight()");
+       
        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] == '/');
+#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
@@ -1333,6 +1383,7 @@ bool dlopen_preflight(const char* path)
                const char* str = *it;
                free((void*)str);
        }
+       CRSetCrashLogMessage(NULL);
        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();
+               CRSetCrashLogMessage("dyld: in dlopen()");
                lockHeld = true;
        }
                
@@ -1376,6 +1428,27 @@ void* dlopen(const char* path, int mode)
  
                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
@@ -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 ) {
+                               CRSetCrashLogMessage(NULL);
                                dyld::gLibSystemHelpers->releaseGlobalDyldLock();
                                lockHeld = false;
                        }
@@ -1462,8 +1536,10 @@ void* dlopen(const char* path, int mode)
                dlerrorSet("image not already loaded");
        }
        
-       if ( lockHeld ) 
+       if ( lockHeld ) {
+               CRSetCrashLogMessage(NULL);
                dyld::gLibSystemHelpers->releaseGlobalDyldLock();
+       }
        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);
 
+       CRSetCrashLogMessage("dyld: in dladdr()");
        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;
+                       CRSetCrashLogMessage(NULL);
                        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);
+                       CRSetCrashLogMessage(NULL);
                        return 1; // success
                }
                info->dli_sname = NULL;
                info->dli_saddr = NULL;
+               CRSetCrashLogMessage(NULL);
                return 1; // success
        }
+       CRSetCrashLogMessage(NULL);
        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);
 
+       CRSetCrashLogMessage("dyld: in dlsym()");
        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) ) {
+                       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);
+               CRSetCrashLogMessage(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 ) {
+                       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);
+               CRSetCrashLogMessage(NULL);
                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
+#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 ) {
+                       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);
+               CRSetCrashLogMessage(NULL);
                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 ) {
+                       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);
+               CRSetCrashLogMessage(NULL);
                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 ) {
+                       CRSetCrashLogMessage(NULL);
                        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()");
        }
+       CRSetCrashLogMessage(NULL);
        return NULL;
 }
 
@@ -1675,7 +1775,6 @@ void dyld_register_image_state_change_handler(dyld_image_states state, bool batc
                dyld::registerImageStateSingleChangeHandler(state, handler);
 }
 
-
 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"
 
-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   
@@ -104,15 +109,16 @@ void NSInstallLinkEditErrorHandlers(
 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);
-       p(handlers->undefined, handlers->multiple, handlers->linkEdit);
+       mcallback_t m = handlers->multiple;
+       p(handlers->undefined, m, handlers->linkEdit);
 }
 
 const char* 
@@ -346,6 +352,7 @@ const char* libraryName)
                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)
@@ -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;
-    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);
@@ -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;
-    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);
@@ -972,7 +981,8 @@ void _dyld_moninit(
 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);
@@ -1067,7 +1077,7 @@ static void shared_cache_out_of_date()
 
 
 // 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,
@@ -1076,14 +1086,17 @@ static dyld::LibSystemHelpers sHelpers = { 6, &dyldGlobalLockAcquire, &dyldGloba
                                                #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.
 //
-extern "C" void _dyld_initializer() __attribute__((visibility("hidden")));
+extern "C" void tlv_initializer();
+extern "C" void _dyld_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);
+               
+       tlv_initializer();
 }
 
 
@@ -1187,7 +1202,6 @@ const struct dyld_all_image_infos* _dyld_get_all_image_infos()
 }
 
 #if !__arm__
-__attribute__((visibility("hidden"))) 
 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
 
 
-#if __i386__ || __x86_64__
+#if __i386__ || __x86_64__ || __arm__
 __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);
 }
 
+#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 <Availability.h>
 
 #include "mach-o/dyld_priv.h"
 #include "dyldLibSystemInterface.h"
@@ -52,12 +53,57 @@ extern struct LibSystemHelpers* _ZN4dyld17gLibSystemHelpersE;
 #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 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)
@@ -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
 
+#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)
 {
-       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
 
 
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
@@ -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();
 
@@ -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.
 //
-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);
        }
-       
-       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();
 
-       // 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];
        
@@ -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);
-       
-       // 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
+       uintptr_t appsSlide = slideOfMainExecutable(appsMachHeader);
        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 -*-
  *
- * Copyright (c) 2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  * @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
 //
 
-#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**); };
 
-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);
 }
 
-#endif
 
 
 
index 94062fc044b7328c6280e5b0ac2b49c91bfb8c93..874c49782eec0fe0e0c3daf4295bb4bdb69c34f7 100644 (file)
@@ -53,10 +53,14 @@ namespace dyld {
                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 7
+               void*           (*pthread_getspecific)(pthread_key_t);
+               // added in version 8
+               void            (*cxa_finalize)(const void*);
        };
 #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
-
+Lmh:   .long   ___dso_handle
 
        .text
        .align 2
@@ -115,12 +115,16 @@ __dyld_start:
        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
-       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
@@ -128,7 +132,7 @@ L__dyld_start_picbase:
        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
@@ -182,14 +186,15 @@ __dyld_start:
        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
-       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
@@ -206,7 +211,8 @@ __dyld_start:
        .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
@@ -246,7 +252,7 @@ __dyld_start:
        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
@@ -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
-       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
@@ -296,10 +305,23 @@ _offset_to_dyld_all_image_infos:
        .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:
-       // 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:
@@ -307,23 +329,25 @@ L__dyld_start_picbase:
        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
 
+
        .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
@@ -366,7 +390,16 @@ _dyld_fatal_error:
     #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_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;
index 7d79aade137ea0d290d8682b6a1d295bec59318d..2afa79cc9b8562d28c541c9b5492b6bd34b7011a 100644 (file)
 #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_uuid_info>  sImageUUIDs;
 
 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 ( sImageUUIDs.capacity() == 0 )
+               sImageUUIDs.reserve(4);
        // 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();
        
-       // 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];
+}
 
+
+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);
+       // <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)
@@ -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 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);
 }
 
-
+#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
@@ -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);
 }
+#endif
 
 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"))) 
-                                                       = { 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;
 
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)
+misaligned_stack_error_entering_dyld_stub_binder:
        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)
+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
@@ -160,4 +162,30 @@ dyld_stub_binder:
 #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 -*-
  *
- * Copyright (c) 2004-2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -29,6 +29,7 @@
 #include <unistd.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <mach/mach_error.h>
 
 // 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;
 }
 
+// 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;
-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
@@ -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("$!");
+unlink "/tmp/exit-non-zero.tmp";
 exit 0;
 
index 43de2a339aee46439e8fa522dd077b222f6e32af..bc0a99d857c26df85cd86c6639d9f93f11d870c1 100755 (executable)
@@ -38,5 +38,6 @@ while(<OUT>)
        print $_;
 }
 close(OUT) || die("$!");
+unlink "/tmp/exit-zero-pass.tmp";
 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
 
-# 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
+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
 
-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 " * * * 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
 
-       # 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 ""
-               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
-               ../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
+
+done
 
 # 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@
  * 
 #include <stdio.h>
 #include <stdlib.h>
 #include <mach-o/dyld.h>
-
+#include <Availability.h>
 #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);
-       if ( mh2 != NULL )
-               PASS("NSAddImage-MATCH_BY_INSTALLNAME");
-       else
+       if ( mh2 == NULL )
                FAIL("NSAddImage-MATCH_BY_INSTALLNAME");
+       else
+#endif
+               PASS("NSAddImage-MATCH_BY_INSTALLNAME");
        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@
  * 
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <mach-o/dyld.h>
+#include <Availability.h>
 
 #include "test.h"
 
 
 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);
-       if ( mh == NULL )
-               PASS("NSAddImage-RETURN_ONLY_IF_LOADED");
-       else
+       if ( mh != NULL )
                FAIL("NSAddImage-RETURN_ONLY_IF_LOADED");
+       else
+#endif
+               PASS("NSAddImage-RETURN_ONLY_IF_LOADED");
        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@
  * 
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <mach-o/dyld.h>
+#include <Availability.h>
 
 #include "test.h"
 
 
 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);
-       if ( mh != NULL )
-               PASS("NSAddImage-leafname");
-       else
+       if ( mh == NULL )
                FAIL("NSAddImage-leafname");
+       else
+#endif
+               PASS("NSAddImage-leafname");
        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@
  * 
@@ -23,6 +23,7 @@
 #include <stdio.h>  // fprintf(), NULL
 #include <stdlib.h> // exit(), EXIT_SUCCESS
 #include <string.h>
+#include <Availability.h>
 
 #include <mach-o/dyld.h>
 
 
 int main()
 {
+// NSAddressOfSymbol is only available on Mac OS X - not iPhone OS
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        NSAddressOfSymbol(NULL);
+#endif
        
        PASS("NSAddressOfSymbol-NULL");
        return 0;
index fd8099beb933776e02879a425284eab8bb0d9273..006adaa4e6fd94610d157bb4317dd643028dae6f 100644 (file)
@@ -57,4 +57,5 @@ int main()
        }
        
        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@
  * 
 #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;
 
-#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()
 {
@@ -71,9 +48,9 @@ struct dyld_all_image_infos* getImageInfosFromKernel()
 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);
        }
 
@@ -82,15 +59,25 @@ main()
                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 ) {
-               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);
        }
 
-       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;
index 80ee13793aa2abb3d3b4dc0600897853b6a2f6a8..287a47b5815c519280d0386fb0d2f9b19c5366e1 100644 (file)
@@ -27,13 +27,16 @@ all-check: all check
 
 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
+endif
 
 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
 
 
-ifeq "armv6" "$(ARCH)"
+ifeq "iPhoneOS" "$(OS_NAME)"
        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 <Availability.h>
 
 #include "test.h" // PASS(), FAIL()
 
@@ -30,6 +31,8 @@ typedef bool (*CheckFunc)();
 
 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");
@@ -63,7 +66,7 @@ int main()
                FAIL("NSDestroyObjectFileImage failed");
                return 1;
        }
-
+#endif
        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[])
 {
+// 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 ) {
@@ -84,8 +86,8 @@ int main(int argc, const char* argv[])
                FAIL("NSUnLinkModule failed");
                return 1;
        }
-               
-       
+#endif 
+
        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 <Availability.h>
 
 #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");
@@ -55,10 +58,11 @@ int main()
 
        // 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");
+       else
+#endif
+               PASS("bundle-memory-load-bad");
        
        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 <Availability.h>
 
 #include "test.h" // PASS(), FAIL()
 
@@ -35,6 +36,8 @@ typedef bool (*CheckFunc)();
 
 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");
@@ -90,6 +93,7 @@ int main()
        }
        
        // Should check that loadAddress is unmmaped now (by call to NSDestroyObjectFileImage)
+#endif
 
        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@
  * 
@@ -30,6 +30,7 @@
 #include <fcntl.h>
 #include <malloc/malloc.h>
 #include <stdlib.h>
+#include <Availability.h>
 
 
 #include "test.h" // PASS(), FAIL()
@@ -38,6 +39,8 @@ typedef bool (*CheckFunc)();
 
 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");
@@ -111,9 +114,8 @@ int main()
                return 1;
        }
        
-       
-       
        // Should check that loadAddress is unmmaped now (by call to NSDestroyObjectFileImage)
+#endif
 
        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 <Availability.h>
 
 #include "test.h" // PASS(), FAIL()
 
@@ -35,6 +36,8 @@ typedef bool (*CheckFunc)();
 
 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");
@@ -90,6 +93,7 @@ int main()
        }
        
        // Should check that loadAddress is unmmaped now (by call to NSDestroyObjectFileImage)
+#endif
 
        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@
  * 
@@ -22,6 +22,7 @@
  */
 #include <stdio.h>
 #include <mach-o/dyld.h>
+#include <Availability.h>
 
 #include "test.h" // PASS(), FAIL()
 
@@ -37,6 +38,8 @@ typedef int (*getter)(void);
 
 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");
@@ -173,7 +176,8 @@ int main()
                FAIL("NSDestroyObjectFileImage failed");
                return 0;
        }
-       
+#endif
+
        PASS("bundle-multi-link");
        return 0;
 }
index b9eb8b3867426051b4eb8b6ae832b57315b15af9..ab0382a40045d7b65c8266be1997510a42feb7aa 100644 (file)
@@ -22,6 +22,7 @@
  */
 #include <stdio.h>
 #include <mach-o/dyld.h>
+#include <Availability.h>
 
 #include "test.h" // PASS(), FAIL()
 
@@ -32,6 +33,8 @@
 
 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");
@@ -147,7 +150,7 @@ int main()
                FAIL("3rd NSDestroyObjectFileImage failed");
                return 0;
        }
-       
+#endif 
        PASS("bundle-multi-load");
        return 0;
 }
index 4244489e863cd1b7bbb00435a2d2305442751945..15c556351bcf70f9a44a44c8c4d48f5246d28a62 100644 (file)
@@ -31,6 +31,8 @@ typedef bool (*CheckFunc)();
 
 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;
@@ -77,7 +79,7 @@ int main()
                FAIL("NSDestroyObjectFileImage failed");
                return 0;
        }
-
+#endif
        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@
  * 
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <stdbool.h>
 #include <mach-o/dyld.h>
+#include <Availability.h>
 
 #include "test.h" // PASS(), FAIL()
 
@@ -30,6 +31,8 @@ typedef bool (*CheckFunc)();
 
 int main()
 {
+// NSCreateObjectFileImageFromMemory is only available on Mac OS X - not iPhone OS
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        NSObjectFileImage ofi;
        if ( NSCreateObjectFileImageFromFile("test.bundle", &ofi) != NSObjectFileImageSuccess ) {
                FAIL("NSCreateObjectFileImageFromFile failed");
@@ -89,7 +92,7 @@ int main()
                FAIL("NSDestroyObjectFileImage failed");
                return 1;
        }
-
+#endif
        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 <Availability.h>
 
 #include "test.h" // PASS(), FAIL()
 
@@ -36,6 +37,8 @@ typedef void (*fooProc)();
 // 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");
@@ -66,14 +69,17 @@ void doit()
                FAIL("NSDestroyObjectFileImage failed");
                exit(0);
        }
+#endif
 }
 
 
 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);
+#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@
  * 
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <mach-o/dyld.h>
+#include <Availability.h>
 
 #include "test.h" // PASS(), FAIL()
 
@@ -30,6 +31,8 @@ typedef bool (*CheckFunc)();
 
 int main()
 {
+// NSCreateObjectFileImageFromMemory is only available on Mac OS X - not iPhone OS
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        NSObjectFileImage ofi;
        if ( NSCreateObjectFileImageFromFile("test.bundle", &ofi) != NSObjectFileImageSuccess ) {
                FAIL("NSCreateObjectFileImageFromFile failed");
@@ -61,7 +64,7 @@ int main()
                        return 1;
                }
        }
-
+#endif
        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@
  * 
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <stdbool.h>
 #include <mach-o/dyld.h>
+#include <Availability.h>
 
 #include "test.h" // PASS(), FAIL()
 
@@ -30,6 +31,8 @@ typedef bool (*CheckFunc)();
 
 int main()
 {
+// NSCreateObjectFileImageFromMemory is only available on Mac OS X - not iPhone OS
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        NSObjectFileImage ofi;
        if ( NSCreateObjectFileImageFromFile("test.bundle", &ofi) != NSObjectFileImageSuccess ) {
                FAIL("NSCreateObjectFileImageFromFile failed");
@@ -66,7 +69,7 @@ int main()
 
        // call function again, even though bundle is unloaded
        func();
-       
+#endif 
 
        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@
  * 
 #include <sys/mman.h> 
 #include <unistd.h>
 #include <fcntl.h>
+#include <Availability.h>
 
 #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)
 {
@@ -79,10 +85,11 @@ void loadAsDylib(const char* path)
        }
 }
 
-extern void bar();
+#endif
 
 int main()
 {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        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);
-
+#endif
        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@
 # 
@@ -30,30 +30,27 @@ include ${TESTROOT}/include/common.makefile
 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:
-       ${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@
  * 
 
 
 ///
+/// verify parameters passed to initializer are same as passed to main()
 /// 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[])
 {
+       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
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@
 # 
@@ -30,19 +30,16 @@ include ${TESTROOT}/include/common.makefile
 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:
-       ${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@
 # 
@@ -31,20 +31,16 @@ include ${TESTROOT}/include/common.makefile
 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:
-       ${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@
  * 
@@ -23,6 +23,7 @@
 #include <stdio.h>  // fprintf(), NULL
 #include <stdlib.h> // exit(), EXIT_SUCCESS
 #include <dlfcn.h>
+#include <Availability.h>
 
 #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 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
+               // for iPhoneOS, initializers are always called before entry point
                #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__ 
-       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)
@@ -15,6 +22,22 @@ _mystart:
        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
 
 
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@
 # 
@@ -28,37 +28,23 @@ include ${TESTROOT}/include/common.makefile
 # the mechanism for 10.4 and 10.5 is different 
 #
 
+
 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:
-       ${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@
 # 
@@ -31,27 +31,20 @@ include ${TESTROOT}/include/common.makefile
 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:
-       ${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@
  */
 
+#include <stdlib.h>
 
 class A
 {
 public:
        A() { f = 10; }
-       ~A() { f = 0; }
+       ~A() { if ( f == 0 ) abort(); f = 0; }
        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@
  * 
@@ -25,6 +25,7 @@
 #include <mach-o/dyld.h>
 #include <pthread.h>
 #include <unistd.h>
+#include <Availability.h>
 
 #include "test.h"
 
@@ -40,6 +41,7 @@
 
 extern void foo();
 
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
 
 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);
        }
 }
+#endif
 
 int main()
 {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
        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);
+#endif
        
        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@
 # 
@@ -29,7 +29,7 @@ check:
        ./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:
index ab88475bafe8c684b9f605447580970c37c67209..c75c621a1a175652a65293ecaf73820abc0b7f12 100644 (file)
@@ -25,6 +25,7 @@
 #include <string.h> 
 #include <dlfcn.h> 
 #include <mach-o/dyld.h> 
+#include <Availability.h> 
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
@@ -66,10 +67,12 @@ static void verifybar()
                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);
        }
+#endif
 }
 
 // checks local symbol 
@@ -88,10 +91,12 @@ static void verifyfoo()
                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);
        }
+#endif
 }
 
 // checks hidden symbol 
@@ -110,10 +115,12 @@ static void verifyhide()
                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);
        }
+#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@
 # 
 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:
-       ./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
-       chmod -r libnoread.dylib
 
 clean:
        ${RM} ${RMFLAGS} *~ main libnoread.dylib
index a3afc96e62a43341b0089aabf94e9882dfac808e..2fc2da1c7f7d1c8beeefa6a57df9ea79e45c4a25 100644 (file)
@@ -35,7 +35,7 @@ main : main.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
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 <mach/mach.h>
 
 #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);
 }
 
+#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()
 {
-       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);
        
-       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 ) {
index b72a1a51675ec5c2a5697df7c72e15a897c8dadd..a48d74f22656e17f5f26bbd89c7d88af7114a07f 100644 (file)
@@ -1,3 +1,6 @@
+#include <string.h>
+
 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 
-       ${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
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@
  * 
@@ -24,6 +24,7 @@
 #include <stdlib.h> // exit(), EXIT_SUCCESS
 #include <dlfcn.h>
 #include <mach-o/dyld.h>
+#include <Availability.h>
 
 #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) 
 {
+// 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);
+#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 
 #
 
+ifeq "$(OS_NAME)" "iPhoneOS"
+       SUDO = 
+else
+       SUDO = sudo
+endif
+
 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 \
index 00ad15684b7ac4419ebafac904766d65dacf43b7..c2a8e2e75873c4147800cd803e5ab92d4f803651 100644 (file)
@@ -31,14 +31,14 @@ check:
 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
-       ${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
-       ${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@
  * 
  */
 
 #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);
 
@@ -42,3 +47,5 @@ bool check_dyld_func_lookup()
        // looks good
        return true;
 }
+
+#endif
index 270e34389544748f5c5b1f6de7c708b4a062697e..35bbd9ff525378f93132daa9ff6c8085aeda2361 100644 (file)
 #include <stdlib.h> // exit(), EXIT_SUCCESS
 #include <dlfcn.h>
 #include <stdbool.h>
+#include <Availability.h>
 
 #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);
@@ -53,17 +57,20 @@ static void trySO(const char* path)
        
        dlclose(handle);
 }
-
+#endif
 
 
 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");
-  
+#endif
+
        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@
  * 
 #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[])
 {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
   _dyld_launched_prebound();
+#endif
   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@
 # 
@@ -24,15 +24,23 @@ TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
 STACK_BASE = 0x8fe01000
+STACK_SIZE = 0x00100000
 
 ifeq "armv6" "$(ARCH)"
        STACK_BASE = 0x2fe01000
+       STACK_SIZE = 0x00100000
+endif
+ifeq "armv7" "$(ARCH)"
+       STACK_BASE = 0x2fe01000
+       STACK_SIZE = 0x00100000
 endif
 ifeq "ppc64" "$(ARCH)"
-       STACK_BASE = 0x7fff5fc00000
+       STACK_BASE = 0x7fff5ff00000
+       STACK_SIZE = 0x00400000
 endif
 ifeq "x86_64" "$(ARCH)"
-       STACK_BASE = 0x7fff5fc00000
+       STACK_BASE = 0x7fff5ff00000
+       STACK_SIZE = 0x00400000
 endif
 
 
@@ -43,7 +51,7 @@ check:
        ${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
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@
  * 
@@ -21,7 +21,8 @@
  * @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"
 
@@ -39,9 +40,9 @@
 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;
 }
 
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_END@
 ##
-TESTROOT = ../..
+PWD = $(shell pwd)
+TESTROOT = $(PWD)/../..
 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:
-       ${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
 
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@
 # 
@@ -35,11 +35,11 @@ main : main.c libfoo.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
-       ${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[])
 {
+#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);
-       if ( image != NULL )
-               PASS("AppKit loaded");
-       else
+       if ( image == NULL )
                FAIL("Could not load AppKit");
+       else
+#endif
+               PASS("AppKit loaded");
 
        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()
 
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+
 static bool doneRegistering = false;
 
 //
@@ -92,10 +95,13 @@ static void load(const char* name)
                }
        }
 }
+#endif
 
 
 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;
@@ -125,6 +131,7 @@ int main(int argc, const char* argv[])
        }
 
 //     dlopen("/usr/lib/libz.1.2.3.dylib", RTLD_LAZY);
+#endif
        
        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@
  * 
@@ -33,7 +33,7 @@ int main(int argc, const char* argv[])
        }
 
        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;
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@
 # 
 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:
-       export DYLD_INSERT_LIBRARIES="/usr/lib/libldap.dylib:/usr/lib/libpcap.dylib" && ./main
+       ${RUN_AS_USER} $(PWD)/main-with-env
 
 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
+       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:
-       ${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@
  * 
 #include <stdio.h>
 #include <stdlib.h>
 #include <mach-o/dyld.h>
+#include <Availability.h>
+#include <dlfcn.h>
 
 #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);
-
-       PASS("loader_path");
+#else
+       if ( dlopen("@loader_path/hide/libfoo3.dylib", 0) == NULL )
+               FAIL("loader_path");
+       else
+#endif
+               PASS("loader_path");
        return EXIT_SUCCESS;
 }
index 0c815549cedc6e59f8cd60f209eda8b4f25effef..9993ac408ce4bd86b4f8c8e2e6a0932d67388796 100644 (file)
@@ -29,6 +29,8 @@
 
 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 ) {
@@ -48,7 +50,7 @@ int main()
        if ( mh != NULL ) {
                return 1;
        }
-       
+#endif
 #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
-       ${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:
index b29599453ebe700fd4fbf0dd517fad3bb6b5d7e1..e8a5fd0503ee61d3264d135db80818f2afbb630d 100644 (file)
@@ -42,7 +42,7 @@ check:
 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:
index f7e3b8812d637fb0136659c15379f0164a5f446d..49d9a882662b90c351969bef3333537f632bca16 100644 (file)
  */
 #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()
 {
index 7c68dbce08bd9da0606a75c6e7d66b32909b32ae..e795c80d86103eb6adba5dccbe1a821afeb65153 100644 (file)
@@ -42,7 +42,7 @@ check:
 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:
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@
 # 
@@ -41,15 +41,15 @@ check:
        ./main >> main.out
        if [ `sort main.out -u | wc -l` == 4 ]; \
        then \
-               echo "PASS pie-basic"; \
+               echo "PASS pie-text-reloc"; \
        else \
-               echo "FAIL pie-basic"; \
+               echo "FAIL pie-text-reloc"; \
        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:
index a3edccc26df4614af2fd2cbe6c8c624bb9c1a02d..ce0d7d94310bbf1e8115823b536db0dde404fadb 100644 (file)
@@ -43,10 +43,10 @@ check:
 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
-       ${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:
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@
 # 
@@ -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:
-       ./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:
-       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
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@
 # 
@@ -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:
-       ./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:
-       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
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@
 # 
@@ -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:
-       ./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:
-       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
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__
-       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
index 45f6d8ff898df811df983bf1d10cfa225cfbd67b..fdadfc76c49a7980965cd06ab7bf54729c6987d9 100644 (file)
@@ -71,7 +71,10 @@ static void* getStubAddr()
 #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
index a383d1a7aec1a3224f9a4aecb6ba10196adea891..8aa6bea413796277bf79a76cefeeea50061c6015 100644 (file)
 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:
-       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
+       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:
-       ${RM} ${RMFLAGS} *~ main
+       ${RM} ${RMFLAGS} *~ main main-with-env
 
index b22295187302159a44291eadac18e19140196817..ceb2e3b31ae679f1814996a8e89b670d2aedc703 100644 (file)
 # 
 # @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
 
+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
@@ -35,10 +41,9 @@ SHELL = bash # use bash shell so we can redirect just stderr
 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 
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_END@
 ##
-TESTROOT = ../..
+PWD = $(shell pwd)
+TESTROOT = $(PWD)/../..
 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 
@@ -35,9 +40,9 @@ all-check: all check
 
 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
 
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;
        }
 
-       // 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;
 }
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@
 # 
 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:
-       export DYLD_INSERT_LIBRARIES=/ && export DYLD_PRINT_LIBRARIES=/ &&  export DYLD_PREBIND_DEBUG=/ && ./main
+       ${RUN_AS_USER} $(PWD)/main-with-env
 
 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
-
+       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:
-       ${RM} ${RMFLAGS} *~ main
+       ${RM} ${RMFLAGS} *~ main main-with-env
 
index 87690821a9fffc635473ab4bdbcc55c881a2a797..aab4ca27fd4f1655d5db88f41ad8914c3f4be8cf 100644 (file)
 # 
 # @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
 
+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
@@ -36,11 +42,11 @@ all-check: all check
 
 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" 
-       ${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" 
-       ${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
 
 ### 
-### 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 
-ifeq "armv6" "$(ARCH)"
-       # arm does not support text relocs
-       TEXT_RELOC_FLAGS = 
-endif 
 
 
 all-check: all check
@@ -46,14 +42,12 @@ all-check: all check
 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:
-       ${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>
 
+int y = 0;
+
 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 <dlfcn.h>  
+#include <Availability.h>  
 
 
 #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
+#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && (__MAC_OS_X_VERSION_MIN_REQUIRED <= __MAC_10_5)
        _dyld_lookup_and_bind(sym, NULL, NULL);
-  
+#else
+       dlsym(RTLD_DEFAULT, sym);
+#endif
        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@
  * 
 #include <stdio.h>
 #include <string.h>
 #include <mach-o/dyld.h>
+#include <dlfcn.h>
+#include <Availability.h>
 
 #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;
        }
-       
+#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);
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;
+}