]> git.saurik.com Git - apple/dyld.git/commitdiff
dyld-132.13.tar.gz mac-os-x-106 mac-os-x-1061 mac-os-x-1062 mac-os-x-1063 mac-os-x-1064 mac-os-x-1065 mac-os-x-1066 mac-os-x-1067 mac-os-x-1068 v132.13
authorApple <opensource@apple.com>
Wed, 2 Sep 2009 00:37:08 +0000 (00:37 +0000)
committerApple <opensource@apple.com>
Wed, 2 Sep 2009 00:37:08 +0000 (00:37 +0000)
388 files changed:
doc/man/man1/dyld.1
doc/man/man1/update_dyld_shared_cache.1
doc/man/man1/update_prebinding.1 [deleted file]
doc/man/man3/dlopen.3
doc/man/man3/dlsym.3
doc/man/man3/dyld.3
dyld.xcodeproj/project.pbxproj
include/dlfcn.h
include/mach-o/dyld-interposing.h
include/mach-o/dyld-update-prebinding.h [deleted file]
include/mach-o/dyld.h
include/mach-o/dyld_images.h
include/mach-o/dyld_priv.h
launch-cache/Architectures.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 [new file with mode: 0644]
launch-cache/ObjCLegacyAbstraction.hpp [new file with mode: 0644]
launch-cache/ObjCModernAbstraction.hpp [new file with mode: 0644]
launch-cache/com.apple.dyld.plist [deleted file]
launch-cache/dsc_iterator.cpp [new file with mode: 0644]
launch-cache/dsc_iterator.h [new file with mode: 0644]
launch-cache/dyld_cache_format.h
launch-cache/dyld_shared_cache.defs [deleted file]
launch-cache/update_dyld_shared_cache.cpp
src/ImageLoader.cpp
src/ImageLoader.h
src/ImageLoaderMachO.cpp
src/ImageLoaderMachO.h
src/ImageLoaderMachOClassic.cpp [new file with mode: 0644]
src/ImageLoaderMachOClassic.h [new file with mode: 0644]
src/ImageLoaderMachOCompressed.cpp [new file with mode: 0644]
src/ImageLoaderMachOCompressed.h [new file with mode: 0644]
src/ImageLoaderPE.cpp [deleted file]
src/ImageLoaderPE.h [deleted file]
src/dyld.cpp
src/dyld.exp
src/dyld.h
src/dyld64.exp [deleted file]
src/dyldAPIs.cpp
src/dyldAPIsInLibSystem.cpp
src/dyldExceptions.c
src/dyldInitialization.cpp
src/dyldLibSystemGlue.c [new file with mode: 0644]
src/dyldLibSystemInterface.h
src/dyldLock.cpp
src/dyldNew.cpp
src/dyldStartup.s
src/dyld_gdb.cpp
src/dyld_stub_binder.s [new file with mode: 0644]
src/glue.c
src/strip.exp [deleted file]
src/stub_binding_helper.s
unit-tests/bin/make-recursive.pl
unit-tests/bin/pass-iff-exit-zero.pl [new file with mode: 0755]
unit-tests/include/common.makefile
unit-tests/run-all-unit-tests
unit-tests/test-cases/NSAddImage-MATCH_BY_INSTALLNAME/Makefile
unit-tests/test-cases/NSAddImage-RETURN_ONLY_IF_LOADED/Makefile
unit-tests/test-cases/NSAddImage-leafname/Makefile
unit-tests/test-cases/NSAddressOfSymbol-NULL/Makefile [new file with mode: 0644]
unit-tests/test-cases/NSAddressOfSymbol-NULL/main.c [new file with mode: 0644]
unit-tests/test-cases/addend/Makefile [new file with mode: 0644]
unit-tests/test-cases/addend/foo.c [new file with mode: 0644]
unit-tests/test-cases/addend/main.c [new file with mode: 0644]
unit-tests/test-cases/all_image_infos/Makefile [new file with mode: 0644]
unit-tests/test-cases/all_image_infos/foo.c [new file with mode: 0644]
unit-tests/test-cases/all_image_infos/main.c [new file with mode: 0644]
unit-tests/test-cases/always-libSystem/Makefile [new file with mode: 0644]
unit-tests/test-cases/always-libSystem/main.c [new file with mode: 0644]
unit-tests/test-cases/big-jump-table/Makefile
unit-tests/test-cases/big-jump-table/funcs.c
unit-tests/test-cases/big-stack/Makefile
unit-tests/test-cases/big-stack/main.c
unit-tests/test-cases/bundle-basic/Makefile
unit-tests/test-cases/bundle-dont-gc/Makefile
unit-tests/test-cases/bundle-memory-load-bad/Makefile
unit-tests/test-cases/bundle-memory-load-fat/Makefile
unit-tests/test-cases/bundle-memory-load-malloc/Makefile [new file with mode: 0644]
unit-tests/test-cases/bundle-memory-load-malloc/bundle.c [new file with mode: 0644]
unit-tests/test-cases/bundle-memory-load-malloc/main.c [new file with mode: 0644]
unit-tests/test-cases/bundle-memory-load/Makefile
unit-tests/test-cases/bundle-multi-link/Makefile
unit-tests/test-cases/bundle-multi-load/Makefile
unit-tests/test-cases/bundle-name-ownership/Makefile
unit-tests/test-cases/bundle-private/Makefile
unit-tests/test-cases/bundle-reload/Makefile
unit-tests/test-cases/bundle-unlinkable/Makefile
unit-tests/test-cases/bundle-unload-keep-mapped/Makefile
unit-tests/test-cases/bundle-v-dylib/Makefile
unit-tests/test-cases/bundle-weak/Makefile
unit-tests/test-cases/bundle-weak/main.c
unit-tests/test-cases/crt-apple/Makefile
unit-tests/test-cases/crt-argv-NULL/Makefile
unit-tests/test-cases/crt-custom/Makefile
unit-tests/test-cases/crt-libSystem/Makefile
unit-tests/test-cases/crt-result/Makefile
unit-tests/test-cases/cxa_finalize/Makefile [new file with mode: 0644]
unit-tests/test-cases/cxa_finalize/foo.cxx [new file with mode: 0644]
unit-tests/test-cases/cxa_finalize/main.c [new file with mode: 0644]
unit-tests/test-cases/deadlock/Makefile
unit-tests/test-cases/dladdr-stripped/Makefile [new file with mode: 0644]
unit-tests/test-cases/dladdr-stripped/main.c [new file with mode: 0644]
unit-tests/test-cases/dladdr/Makefile
unit-tests/test-cases/dladdr/main.c
unit-tests/test-cases/dlclose-basic/Makefile
unit-tests/test-cases/dlclose-bundle-unload/Makefile
unit-tests/test-cases/dlclose-dylib-unload/Makefile
unit-tests/test-cases/dlclose-terminator-dlclose/Makefile
unit-tests/test-cases/dlclose-unload-c++/Makefile
unit-tests/test-cases/dlclose-unmap/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlclose-unmap/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlclose-unmap/main.c [new file with mode: 0644]
unit-tests/test-cases/dlerror-clear/Makefile
unit-tests/test-cases/dlerror/Makefile
unit-tests/test-cases/dlopen-DYLD_FALLBACK_LIBRARY_PATH/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen-DYLD_FALLBACK_LIBRARY_PATH/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-DYLD_FALLBACK_LIBRARY_PATH/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-DYLD_LIBRARY_PATH/Makefile
unit-tests/test-cases/dlopen-LD_LIBRARY_PATH/Makefile
unit-tests/test-cases/dlopen-NULL-RTLD_FIRST/Makefile
unit-tests/test-cases/dlopen-RTLD_FIRST/Makefile
unit-tests/test-cases/dlopen-RTLD_GLOBAL/Makefile
unit-tests/test-cases/dlopen-RTLD_LOCAL-ignore/Makefile
unit-tests/test-cases/dlopen-RTLD_LOCAL-weak/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen-RTLD_LOCAL-weak/bar.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-RTLD_LOCAL-weak/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-RTLD_LOCAL-weak/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-RTLD_LOCAL/Makefile
unit-tests/test-cases/dlopen-RTLD_NODELETE/Makefile
unit-tests/test-cases/dlopen-RTLD_NOLOAD-fallback/Makefile
unit-tests/test-cases/dlopen-RTLD_NOLOAD-in-initializer/Makefile
unit-tests/test-cases/dlopen-RTLD_NOLOAD-symlink/Makefile
unit-tests/test-cases/dlopen-RTLD_NOLOAD/Makefile
unit-tests/test-cases/dlopen-RTLD_NOW/Makefile
unit-tests/test-cases/dlopen-basic/Makefile
unit-tests/test-cases/dlopen-dyld-locking/Makefile
unit-tests/test-cases/dlopen-dyld-locking/base.c
unit-tests/test-cases/dlopen-dyld-locking/main.c
unit-tests/test-cases/dlopen-error/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen-error/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-error/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-executable/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen-executable/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-executable/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-from-anonymous-code/Makefile
unit-tests/test-cases/dlopen-in-initializer/Makefile
unit-tests/test-cases/dlopen-init-dlopen-notify/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen-init-dlopen-notify/bar.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-init-dlopen-notify/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-init-dlopen-notify/foo1.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-init-dlopen-notify/foo2.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-init-dlopen-notify/main.cxx [new file with mode: 0644]
unit-tests/test-cases/dlopen-init-dlopen-up/Makefile
unit-tests/test-cases/dlopen-init-dlopen/Makefile
unit-tests/test-cases/dlopen-init-up/Makefile
unit-tests/test-cases/dlopen-initializer/Makefile
unit-tests/test-cases/dlopen-leak-threaded/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen-leak-threaded/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-leak/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen-leak/bar.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-leak/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-leak/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-local-and-global/Makefile
unit-tests/test-cases/dlopen-multi/Makefile
unit-tests/test-cases/dlopen-notify-bind/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen-notify-bind/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-notify-bind/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen-zero/Makefile
unit-tests/test-cases/dlopen-zero/main.c
unit-tests/test-cases/dlopen_preflight-basic/Makefile
unit-tests/test-cases/dlopen_preflight-leak-image-deny-single/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen_preflight-leak-image-deny-single/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen_preflight-leak-image-deny-single/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen_preflight-leak/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen_preflight-leak/bar.c [new file with mode: 0644]
unit-tests/test-cases/dlopen_preflight-leak/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlopen_preflight-leak/main.c [new file with mode: 0644]
unit-tests/test-cases/dlopen_preflight-shared-cache/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlopen_preflight-shared-cache/bar.c [new file with mode: 0644]
unit-tests/test-cases/dlopen_preflight-shared-cache/main.c [new file with mode: 0644]
unit-tests/test-cases/dlsym-RTLD_DEFAULT/Makefile
unit-tests/test-cases/dlsym-RTLD_MAIN_ONLY/Makefile [new file with mode: 0644]
unit-tests/test-cases/dlsym-RTLD_MAIN_ONLY/foo.c [new file with mode: 0644]
unit-tests/test-cases/dlsym-RTLD_MAIN_ONLY/main.c [new file with mode: 0644]
unit-tests/test-cases/dlsym-RTLD_NEXT-missing/Makefile
unit-tests/test-cases/dlsym-RTLD_NEXT/Makefile
unit-tests/test-cases/dlsym-RTLD_SELF/Makefile
unit-tests/test-cases/dlsym-error/Makefile
unit-tests/test-cases/dlsym-indirect/Makefile
unit-tests/test-cases/dtrace-static-probes/Makefile [new file with mode: 0644]
unit-tests/test-cases/dtrace-static-probes/foo.d [new file with mode: 0644]
unit-tests/test-cases/dtrace-static-probes/main.c [new file with mode: 0644]
unit-tests/test-cases/dyld-func-lookup/Makefile
unit-tests/test-cases/dyld-launched-prebound/Makefile
unit-tests/test-cases/dyld-slide/Makefile
unit-tests/test-cases/dyld-slide/main.c
unit-tests/test-cases/dynamic_cast-basic/Makefile [new file with mode: 0644]
unit-tests/test-cases/dynamic_cast-basic/foo.cxx [new file with mode: 0644]
unit-tests/test-cases/dynamic_cast-basic/foo.h [new file with mode: 0644]
unit-tests/test-cases/dynamic_cast-basic/main.cxx [new file with mode: 0644]
unit-tests/test-cases/dynamic_cast-basic/realmain.cxx [new file with mode: 0644]
unit-tests/test-cases/env-DYLD_FALLBACK_LIBRARY_PATH/Makefile [new file with mode: 0644]
unit-tests/test-cases/env-DYLD_FALLBACK_LIBRARY_PATH/compress.c [new file with mode: 0644]
unit-tests/test-cases/env-DYLD_FALLBACK_LIBRARY_PATH/main.c [new file with mode: 0644]
unit-tests/test-cases/executable-image-index/Makefile
unit-tests/test-cases/fallback-non-unique-leaf-names/Makefile
unit-tests/test-cases/fallback-with-suid/Makefile
unit-tests/test-cases/flat-data/Makefile
unit-tests/test-cases/flat-insert/Makefile
unit-tests/test-cases/flat-insert/main.c
unit-tests/test-cases/flat-prebound/Makefile
unit-tests/test-cases/flat-private-extern/Makefile
unit-tests/test-cases/framework-fallback/Makefile
unit-tests/test-cases/framework-fallback/main.c
unit-tests/test-cases/ignore-bad-files/Makefile
unit-tests/test-cases/image-remove-notification/Makefile
unit-tests/test-cases/image-slide/Makefile [new file with mode: 0644]
unit-tests/test-cases/image-slide/foo.c [new file with mode: 0644]
unit-tests/test-cases/image-slide/main.c [new file with mode: 0644]
unit-tests/test-cases/image-state-change/Makefile
unit-tests/test-cases/image-state-change/main.c
unit-tests/test-cases/image-state-deny-OFI/Makefile
unit-tests/test-cases/image-state-deny-dlclose/Makefile
unit-tests/test-cases/image-state-deny/Makefile
unit-tests/test-cases/image-state-dependents-initialized/Makefile
unit-tests/test-cases/image-suffix/Makefile
unit-tests/test-cases/image_path_containing_address/Makefile [new file with mode: 0644]
unit-tests/test-cases/image_path_containing_address/foo.c [new file with mode: 0644]
unit-tests/test-cases/image_path_containing_address/main.c [new file with mode: 0644]
unit-tests/test-cases/init-libSystem-first/Makefile [new file with mode: 0644]
unit-tests/test-cases/init-libSystem-first/foo.c [new file with mode: 0644]
unit-tests/test-cases/init-libSystem-first/main.c [new file with mode: 0644]
unit-tests/test-cases/init-order/Makefile
unit-tests/test-cases/initializer-args/Makefile
unit-tests/test-cases/insert-libraries-weak-symbols/Makefile [new file with mode: 0644]
unit-tests/test-cases/insert-libraries-weak-symbols/insert.c [new file with mode: 0644]
unit-tests/test-cases/insert-libraries-weak-symbols/main.c [new file with mode: 0644]
unit-tests/test-cases/insert-libraries-with-initializer/Makefile
unit-tests/test-cases/insert-libraries-with-suid/Makefile
unit-tests/test-cases/interpose-basic-prebound/Makefile
unit-tests/test-cases/interpose-basic/Makefile
unit-tests/test-cases/interpose-chained/Makefile
unit-tests/test-cases/interpose-dlsym/Makefile
unit-tests/test-cases/interpose-shared-cache/Makefile [new file with mode: 0644]
unit-tests/test-cases/interpose-shared-cache/main.c [new file with mode: 0644]
unit-tests/test-cases/interpose-shared-cache/mymalloc.c [new file with mode: 0644]
unit-tests/test-cases/jump-table-dynamic-lookup/Makefile
unit-tests/test-cases/jump-table-race/Makefile
unit-tests/test-cases/lazy-binding-reg-params/Makefile
unit-tests/test-cases/lazy-binding-reg-params/foo.c
unit-tests/test-cases/lazy-binding-reg-params/foo.h
unit-tests/test-cases/lazy-binding-reg-params/main.c
unit-tests/test-cases/lazy-dylib-init-order/Makefile [new file with mode: 0644]
unit-tests/test-cases/lazy-dylib-init-order/expected.out [new file with mode: 0644]
unit-tests/test-cases/lazy-dylib-init-order/foo.c [new file with mode: 0644]
unit-tests/test-cases/lazy-dylib-init-order/main.c [new file with mode: 0644]
unit-tests/test-cases/lazy-dylib-missing-dylib/Makefile [new file with mode: 0644]
unit-tests/test-cases/lazy-dylib-missing-dylib/foo.c [new file with mode: 0644]
unit-tests/test-cases/lazy-dylib-missing-dylib/main.c [new file with mode: 0644]
unit-tests/test-cases/lazy-dylib-missing-symbol/Makefile [new file with mode: 0644]
unit-tests/test-cases/lazy-dylib-missing-symbol/foo.c [new file with mode: 0644]
unit-tests/test-cases/lazy-dylib-missing-symbol/main.c [new file with mode: 0644]
unit-tests/test-cases/lazy-pointer-binding/Makefile
unit-tests/test-cases/lib-name-overload/Makefile
unit-tests/test-cases/loader_path-dup/Makefile
unit-tests/test-cases/loader_path/Makefile
unit-tests/test-cases/missing-symlink-framework-fallback-path/Makefile
unit-tests/test-cases/non-lazy-slide/Makefile [new file with mode: 0644]
unit-tests/test-cases/non-lazy-slide/bar.c [new file with mode: 0644]
unit-tests/test-cases/non-lazy-slide/foo.c [new file with mode: 0644]
unit-tests/test-cases/non-lazy-slide/main.c [new file with mode: 0644]
unit-tests/test-cases/non-lazy-weak/Makefile [new file with mode: 0644]
unit-tests/test-cases/non-lazy-weak/bar.c [new file with mode: 0644]
unit-tests/test-cases/non-lazy-weak/foo.c [new file with mode: 0644]
unit-tests/test-cases/non-lazy-weak/main.c [new file with mode: 0644]
unit-tests/test-cases/non-weak-library/Makefile
unit-tests/test-cases/operator-new-dylib/Makefile [new file with mode: 0644]
unit-tests/test-cases/operator-new-dylib/foo.cxx [new file with mode: 0644]
unit-tests/test-cases/operator-new-dylib/main.cxx [new file with mode: 0644]
unit-tests/test-cases/operator-new/Makefile
unit-tests/test-cases/operator-new/main.cxx
unit-tests/test-cases/partial-library-load/Makefile
unit-tests/test-cases/pie-DYLD_NO_PIE/Makefile [new file with mode: 0644]
unit-tests/test-cases/pie-DYLD_NO_PIE/main.c [new file with mode: 0644]
unit-tests/test-cases/pie-basic/Makefile
unit-tests/test-cases/pie-big/Makefile
unit-tests/test-cases/pie-custom-stack/Makefile
unit-tests/test-cases/pie-dylib/Makefile [new file with mode: 0644]
unit-tests/test-cases/pie-dylib/foo.c [new file with mode: 0644]
unit-tests/test-cases/pie-dylib/main.c [new file with mode: 0644]
unit-tests/test-cases/pie-text-reloc/Makefile [new file with mode: 0644]
unit-tests/test-cases/pie-text-reloc/main.c [new file with mode: 0644]
unit-tests/test-cases/prebased-performance/Makefile
unit-tests/test-cases/progname/Makefile
unit-tests/test-cases/pthread-keys/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/read-only-import-shared-cache-coalesce/Makefile
unit-tests/test-cases/read-only-import-shared-cache-dlopen-override/Makefile
unit-tests/test-cases/read-only-import-shared-cache-override/Makefile
unit-tests/test-cases/read-only-import-shared-cache-override/foo.c
unit-tests/test-cases/read-only-import-shared-cache-override/main.c
unit-tests/test-cases/read-only-stubs/Makefile
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 [new file with mode: 0644]
unit-tests/test-cases/restrict-environ/main.c [new file with mode: 0644]
unit-tests/test-cases/restrict-executable_path/Makefile [new file with mode: 0644]
unit-tests/test-cases/restrict-executable_path/foo.c [new file with mode: 0644]
unit-tests/test-cases/restrict-executable_path/main.c [new file with mode: 0644]
unit-tests/test-cases/rpath-DYLD_FALLBACK_LIBRARY_PATH/Makefile
unit-tests/test-cases/rpath-DYLD_LIBRARY_PATH/Makefile
unit-tests/test-cases/rpath-DYLD_ROOT_PATH/Makefile [new file with mode: 0644]
unit-tests/test-cases/rpath-DYLD_ROOT_PATH/foo.c [new file with mode: 0644]
unit-tests/test-cases/rpath-DYLD_ROOT_PATH/main.c [new file with mode: 0644]
unit-tests/test-cases/rpath-LD_LIBRARY_PATH/Makefile
unit-tests/test-cases/rpath-basic/Makefile
unit-tests/test-cases/rpath-dlopen-in-dylib/Makefile
unit-tests/test-cases/rpath-dlopen-indirect/Makefile
unit-tests/test-cases/rpath-dlopen-leak/Makefile
unit-tests/test-cases/rpath-dlopen/Makefile
unit-tests/test-cases/rpath-executable_path/Makefile
unit-tests/test-cases/rpath-indirect-suid/Makefile
unit-tests/test-cases/rpath-loader_path-dlopen/Makefile
unit-tests/test-cases/rpath-loader_path/Makefile
unit-tests/test-cases/rpath-nesting/Makefile
unit-tests/test-cases/shared-cache-symlink/Makefile
unit-tests/test-cases/suid-environ/Makefile
unit-tests/test-cases/suid-executable_path/Makefile
unit-tests/test-cases/sym-link-load/Makefile
unit-tests/test-cases/template/Makefile
unit-tests/test-cases/text-relocs/Makefile
unit-tests/test-cases/text-relocs/bar.c
unit-tests/test-cases/text-relocs/foo.s [deleted file]
unit-tests/test-cases/text-relocs/main.c
unit-tests/test-cases/threaded-lazy-bind/Makefile [new file with mode: 0644]
unit-tests/test-cases/threaded-lazy-bind/foo.c [new file with mode: 0644]
unit-tests/test-cases/threaded-lazy-bind/gen.c [new file with mode: 0644]
unit-tests/test-cases/threaded-lazy-bind/main.c [new file with mode: 0644]
unit-tests/test-cases/trie-symbol-overrun/Makefile [new file with mode: 0644]
unit-tests/test-cases/trie-symbol-overrun/foo.c [new file with mode: 0644]
unit-tests/test-cases/trie-symbol-overrun/main.c [new file with mode: 0644]
unit-tests/test-cases/unloadable-library-residue/Makefile
unit-tests/test-cases/weak-coalesce-c++/Makefile
unit-tests/test-cases/weak-coalesce/Makefile
unit-tests/test-cases/weak-external-reloc-flat/Makefile [new file with mode: 0644]
unit-tests/test-cases/weak-external-reloc-flat/bar.c [new file with mode: 0644]
unit-tests/test-cases/weak-external-reloc-flat/baz.c [new file with mode: 0644]
unit-tests/test-cases/weak-external-reloc-flat/foo.c [new file with mode: 0644]
unit-tests/test-cases/weak-external-reloc-flat/main.c [new file with mode: 0644]
unit-tests/test-cases/weak-external-reloc/Makefile [new file with mode: 0644]
unit-tests/test-cases/weak-external-reloc/bar.c [new file with mode: 0644]
unit-tests/test-cases/weak-external-reloc/baz.c [new file with mode: 0644]
unit-tests/test-cases/weak-external-reloc/foo.c [new file with mode: 0644]
unit-tests/test-cases/weak-external-reloc/main.c [new file with mode: 0644]
unit-tests/test-cases/weak-external-reloc/realmain.c [new file with mode: 0644]
unit-tests/test-cases/weak-in-dylib/Makefile [new file with mode: 0644]
unit-tests/test-cases/weak-in-dylib/foo.c [new file with mode: 0644]
unit-tests/test-cases/weak-in-dylib/main.c [new file with mode: 0644]
unit-tests/test-cases/weak-lazy-slidable/Makefile [new file with mode: 0644]
unit-tests/test-cases/weak-lazy-slidable/bar.c [new file with mode: 0644]
unit-tests/test-cases/weak-lazy-slidable/bar3.c [new file with mode: 0644]
unit-tests/test-cases/weak-lazy-slidable/foo.c [new file with mode: 0644]
unit-tests/test-cases/weak-lazy-slidable/main.c [new file with mode: 0644]
unit-tests/test-cases/weak-lazy-slidable/other.c [new file with mode: 0644]
unit-tests/test-cases/weak-library/Makefile
unit-tests/test-cases/weak-non-lazy/Makefile [new file with mode: 0644]
unit-tests/test-cases/weak-non-lazy/bar.c [new file with mode: 0644]
unit-tests/test-cases/weak-non-lazy/baz.c [new file with mode: 0644]
unit-tests/test-cases/weak-non-lazy/foo.c [new file with mode: 0644]
unit-tests/test-cases/weak-non-lazy/main.c [new file with mode: 0644]
unit-tests/test-cases/weak-non-lazy/realmain.c [new file with mode: 0644]
unit-tests/test-cases/weak-override/Makefile
unit-tests/test-cases/weak-override/foo.c
unit-tests/test-cases/weak-override/main.c
unit-tests/test-cases/weak-symbol-flat/Makefile
unit-tests/test-cases/weak-symbol/Makefile
unit-tests/test-cases/weak_import/Makefile [new file with mode: 0644]
unit-tests/test-cases/weak_import/foo.c [new file with mode: 0644]
unit-tests/test-cases/weak_import/foo.h [new file with mode: 0644]
unit-tests/test-cases/weak_import/main.c [new file with mode: 0644]
unit-tests/test-cases/zero-fill-segment/Makefile
unit-tests/test-cases/zero-length-segment/Makefile

index 0ef371a6027e1535a131a8b3093c255cae853752..8570d9aba762930e6b0a8835640eae97a23b1a19 100644 (file)
@@ -1,4 +1,4 @@
-.TH DYLD 1 "March 23, 2007" "Apple Inc."
+.TH DYLD 1 "November 25, 2008" "Apple Inc."
 .SH NAME
 dyld \- the dynamic link editor
 .SH SYNOPSIS
@@ -47,6 +47,12 @@ DYLD_PRINT_SEGMENTS
 DYLD_PRINT_STATISTICS
 .br
 DYLD_PRINT_DOFS
+.br
+DYLD_NO_PIE
+.br
+DYLD_SHARED_CACHE_DIR
+.br
+DYLD_SHARED_CACHE_DONT_VALIDATE
 .SH DESCRIPTION
 The dynamic linker uses the following environment variables.
 They affect any program that uses the dynamic linker.
@@ -121,7 +127,7 @@ This is a colon separated list of directories.  The dynamic linker will prepend
 this directory paths to every image access until a file is found.    
 .TP
 .B DYLD_SHARED_REGION 
-This can be "use" (the default), "avoid", or "private".  Settting it to 
+This can be "use" (the default), "avoid", or "private".  Setting it to 
 "avoid" tells dyld to not use the shared cache.  All OS dylibs are loaded 
 dynamically just like every other dylib.  Setting it to "private" tells
 dyld to remove the shared region from the process address space and mmap()
@@ -209,6 +215,60 @@ Causes dyld to print a line each time a symbolic name is bound.
 .TP
 .B DYLD_PRINT_DOFS 
 Causes dyld to print out information about dtrace static probes registered with the kernel. 
-
+.TP
+.B DYLD_NO_PIE
+Causes dyld to not randomize the load addresses of images in a process where the main 
+executable was built position independent.  This can be helpful when trying to reproduce
+and debug a problem in a PIE.
+.TP
+.B DYLD_SHARED_CACHE_DIR
+This is a directory containing dyld shared cache files.  This variable can be used in
+conjunction with DYLD_SHARED_REGION=private and DYLD_SHARED_CACHE_DONT_VALIDATE
+to run a process with an alternate shared cache.
+.TP
+.B DYLD_SHARED_CACHE_DONT_VALIDATE
+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.
+.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).
+But there are times when a full path is not appropriate; for instance, may want your
+binaries to be installable in anywhere on the disk.
+To support that, there are three @xxx/ variables that can be used as a path prefix.  At runtime dyld
+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.
+.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.
+.TP
+.B @rpath/
+Dyld maintains a current stack of paths called the run path list.  When @rpath is encountered
+it is substituted with each path in the run path list until a loadable dylib if found.  
+The run path stack is built from the LC_RPATH load commands in the depencency chain
+that lead to the current dylib load.
+You can add an LC_RPATH load command to an image with the -rpath option to ld(1).  You can
+even add a LC_RPATH load command path that starts with @loader_path/, and it will push a path
+on the run path stack that relative to the image containing the LC_RPATH.  
+The use of @rpath is most useful when you have a complex directory structure of programs and
+dylibs which can be installed anywhere, but keep their relative positions.  This scenario
+could be implemented using @loader_path, but every client of a dylib could need a different 
+load path because its relative position in the file system is different. The use of @rpath
+introduces a level of indirection that simplies things.  You pick a location in your directory
+structure as an anchor point.  Each dylib then gets an install path that starts with @rpath 
+and is the path to the dylib relative to the anchor point. Each main executable is linked
+with -rpath @loader_path/zzz, where zzz is the path from the executable to the anchor point.
+At runtime dyld sets it run path to be the anchor point, then each dylib is found relative
+to the anchor point.  
 .SH "SEE ALSO"
 libtool(1), ld(1), otool(1)
index a3709623b2e07acf760ecabe66071646a453bf13..f5baa1b6da825e625b1f03320abe3dee591e17d4 100644 (file)
@@ -1,4 +1,4 @@
-.Dd March 23, 2007
+.Dd Oct 10, 2008
 .Dt update_dyld_shared_cache 1
 .Os Darwin
 .Sh NAME
@@ -7,20 +7,26 @@
 .Sh SYNOPSIS
 .Nm
 .Op Fl root Ar directory 
+.Op Fl overlay Ar directory 
 .Op Fl arch Ar arch 
 .Op Fl force 
 .Op Fl debug
 .Op Fl sort_by_name 
 .Op Fl universal_boot 
+.Op Fl verify
+.Op Fl dylib_list Ar file
 .Sh DESCRIPTION
 .Nm update_dyld_shared_cache
-ensures that dyld's shared cache is up-to-date.  Normally, this command 
-never needs to be manually run.  Instead, it is automatically run by launchd
-when dyld notices the shared cache is out of date.  To prevent the cache
-from being regeneated during an install or during development of OS dylibs,
-dyld will not trigger a shared cache rebuild if the environment variable 
-DYLD_NO_FIX_PREBINDING is set, or if the main executable is a setuid binary,
-or alternate dylibs are loaded via one of the DYLD_ environment variables.
+ensures that dyld's shared cache is up-to-date.  This tool is normally
+only run by Apple's Installer and Software Update, as they are the only
+official ways for OS dylibs to be updated.  But if for some reason you
+used another mechanism to alter an OS dylib, you should manually run
+.Nm update_dyld_shared_cache . 
+.Pp
+Note that the new cache does not take effect until the OS is rebooted.  
+.Pp
+If a safe-boot is
+done (booting with shift key held down) the cache is deleted.  
 .Pp
 The dyld shared cache
 is mapped by dyld into a process at launch time. Later, when loading
@@ -34,7 +40,7 @@ scans the directory /var/db/dyld/shared_region_roots for text files containing p
 mach-o executables.  The full dependencies of all dylibs required by those executables is
 used to determine which libraries are commonly used and should be placed in the
 shared cache. If one of the text files contains a path to a dylib, that dylib and its
-depenents will be forced into the cache.
+dependents will be forced into the cache.
 .Pp
 .Nm update_dyld_shared_cache
 builds a separate cache file for each architecture.  The cache files and a readable text
@@ -46,8 +52,18 @@ The options are as follows:
 .Bl -tag
 .It Fl root Ar directory
 This option specifies the root of an OS installation for which dyld's
-shared cache should be updated.  This allosw you to update the
-shared cache on a non-running version of the OS.  The cache files
+shared cache should be updated.  This is used by the Installer to update the
+dyld shared cache in a partition other than the one you into which you are currently 
+booted.  The cache files are created in the var/db/dyld directory of the specified directory.
+Note: if you are manually doing this, be sure to run the update_dyld_shared_cache tool
+that is in the partition being updated.  This assures the cache format created will
+match that expected when booting off that partition. 
+.It Fl overlay Ar directory
+This option specifies the root of a sparse directory tree.  When building
+the dyld shared cache, any corresponding mach-o files in the sparse directory 
+will override those in the boot partition.  This is used by Software
+Update to build a dyld shared cache for the update that is about to be
+installed.  The cache files
 are created in the var/db/dyld directory of the specified directory.
 .It Fl arch Ar arch
 By default 
@@ -64,12 +80,19 @@ This option prints out additional information about the work being done.
 .It Fl sort_by_name
 By default
 .Nm update_dyld_shared_cache
-assignes a random start address to each mach-o image in the cache.
-This option causes the start addresses to be choosen in path order, thus subsequent runs will
+assigns a random start address to each mach-o image in the cache.
+This option causes the start addresses to be chosen in path order, thus subsequent runs will
 produce the same address layout which can help reproduce some bugs.
 .It Fl universal_boot
 This option can only be used running on an machine with an Intel processor.  It builds caches
-that can be used when booting on an Intel or a PowerPC based machine.
+that can be used when booting on both 32-bit and 64-bit machines.
+.It Fl dylib_list Ar file
+Instead of scanning /var/db/dyld/shared_region_roots/, this option provides a file that contains
+a list of the dylibs to use when building the shared cache file.
+.It Fl verify
+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.  
 .El
 .Sh FILES
 .Tp
diff --git a/doc/man/man1/update_prebinding.1 b/doc/man/man1/update_prebinding.1
deleted file mode 100644 (file)
index a441bed..0000000
+++ /dev/null
@@ -1 +0,0 @@
-.so man1/update_dyld_shared_cache.1
index 8f88c472915e29ad569e7d0de00cb721ebde7651..60c2527b8ee9a1628db1046e24a0a328d697e0cd 100644 (file)
@@ -1,4 +1,4 @@
-.Dd Nov 6, 2006
+.Dd Aug 28, 2008
 .Os
 .Dt DLOPEN 3
 .Sh NAME
@@ -143,10 +143,9 @@ contains a slash (i.e. a full path or a partial path)
 searches the following the following until it finds a compatible Mach-O file: 
 $DYLD_LIBRARY_PATH (with leaf name from 
 .Fa path
-), current working directory (for partial paths), $DYLD_FALLBACK_LIBRARY_PATH
-(with leaf name from 
-.Fa path
-).
+), then the supplied 
+.Fa path 
+(using current working directory for partial paths).
 .Pp
 Note: There are no configuration files to control dlopen searching.  
 .Pp
index 0adbe9a0b020c78e657c3ef0749bf43fefa74636..2cd3f441b0b314bd79383de2debd7bd7448c042c 100644 (file)
@@ -1,4 +1,4 @@
-.Dd Jan 16, 2008
+.Dd August 28, 2008
 .Dt DLSYM 3
 .Sh NAME
 .Nm dlsym
@@ -39,10 +39,18 @@ If
 is called with the special
 .Fa handle
 .Dv RTLD_NEXT ,
-then the search for the symbol is limited to the images which were loaded
-by the image issuing the call to
-.Fn dlsym .
-In other words, search the dylib symbols that the calling image linked against when it was built.
+then dyld searches for the symbol in the dylibs the calling image 
+linked against when built. It is usually used when
+you intentionally have multiply defined symbol across images
+and want to find the "next" definition.  It searches other images 
+for the definition that the caller would be using if it did not
+have a definition.  The exact search algorithm depends on whether
+the caller's image was linked -flat_namespace or -twolevel_namespace.
+For flat linked images, the search starts in the load ordered list
+of all images, in the image right after the caller's image.  
+For two-level images, the search simulates how the static linker
+would have searched for the symbol when linking the caller's
+image.  
 .Pp
 If
 .Fn dlsym
@@ -53,6 +61,15 @@ then the search for the symbol starts with the image that called
 .Fn dlsym .
 If it is not found, the search continues as if RTLD_NEXT was used.
 .Pp
+If
+.Fn dlsym
+is called with the special
+.Fa handle
+.Dv RTLD_MAIN_ONLY ,
+then it only searches for 
+.Fa symbol
+in the main executable.
+.Pp
 .Sh RETURN VALUES
 The
 .Fn dlsym
@@ -62,9 +79,13 @@ condition which may be queried with
 .Fn dlerror .
 .Pp
 .Sh NOTES
-Unlike other dyld API's, the symbol name passed to
+The symbol name passed to
 .Fn dlsym
-must NOT be prepended with an underscore.  
+is the name used in C source code.  For example to find the address
+of function foo(), you would pass "foo" as the symbol name.  This
+is unlike the older dyld APIs which required a leading underscore.
+If you looking up a C++ symbol, you need to use the mangled C++ symbol
+name.  
 .Sh SEE ALSO
 .Xr dlopen 3
 .Xr dlsym 3
index 9013b81636e8d76aa7cc6c49ad9c47d062b9ac5e..285a70c88c3306c2abac50a4c12c6322135dcda8 100644 (file)
@@ -1,4 +1,4 @@
-.Dd August 16, 2006
+.Dd February 12, 2009
 .Dt dyld 3
 .Sh NAME
 .Nm _dyld_image_count,
@@ -64,7 +64,7 @@ may be adding or removing images during the iteration.
 .Fn _dyld_get_image_header
 returns a pointer to the mach header of the image indexed by image_index.  If 
 .Fa image_index
-isout of range, NULL is returned.
+is out of range, NULL is returned.
 .Pp
 .Fn _dyld_get_image_vmaddr_slide
 returns the virtural memory address slide amount of the image indexed by
index efbfc38ad0d412b67c10c5f163e286043a62be4b..75cd83f4e06314c98d004fa0b0d21fe45c9ff295 100644 (file)
@@ -3,7 +3,7 @@
        archiveVersion = 1;
        classes = {
        };
-       objectVersion = 42;
+       objectVersion = 46;
        objects = {
 
 /* Begin PBXAggregateTarget section */
 /* End PBXAggregateTarget section */
 
 /* Begin PBXBuildFile section */
-               EF79A010070D293E00F78484 /* dyld.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = EF799FE9070D27BB00F78484 /* dyld.1 */; };
-               EF79A011070D295200F78484 /* dladdr.3 in CopyFiles */ = {isa = PBXBuildFile; fileRef = EF799FEB070D27BB00F78484 /* dladdr.3 */; };
-               EF79A012070D295200F78484 /* dlclose.3 in CopyFiles */ = {isa = PBXBuildFile; fileRef = EF799FEC070D27BB00F78484 /* dlclose.3 */; };
-               EF79A013070D295200F78484 /* dlerror.3 in CopyFiles */ = {isa = PBXBuildFile; fileRef = EF799FED070D27BB00F78484 /* dlerror.3 */; };
-               EF79A014070D295200F78484 /* dlopen.3 in CopyFiles */ = {isa = PBXBuildFile; fileRef = EF799FEE070D27BB00F78484 /* dlopen.3 */; };
-               EF79A015070D295200F78484 /* dlsym.3 in CopyFiles */ = {isa = PBXBuildFile; fileRef = EF799FEF070D27BB00F78484 /* dlsym.3 */; };
-               EF79A016070D295200F78484 /* dyld.3 in CopyFiles */ = {isa = PBXBuildFile; fileRef = EF799FF0070D27BB00F78484 /* dyld.3 */; };
+               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 */; };
                F913FADA0630A8AE00B7AE9D /* dyldAPIsInLibSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F913FAD90630A8AE00B7AE9D /* dyldAPIsInLibSystem.cpp */; };
-               F918691608B16D3500E0F9DB /* dyld-interposing.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = F918691408B16D2500E0F9DB /* dyld-interposing.h */; };
-               F919ECB1090455AB002331E3 /* dyld-update-prebinding.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = F919ECAB09045590002331E3 /* dyld-update-prebinding.h */; };
-               F93075C30BA1FE4D004BCA09 /* dyld_shared_cache_server.c in Sources */ = {isa = PBXBuildFile; fileRef = F93075C10BA1FE4D004BCA09 /* dyld_shared_cache_server.c */; };
-               F932C2520BC32ABB0018B20D /* com.apple.dyld.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = F93075D30BA204FF004BCA09 /* com.apple.dyld.plist */; };
+               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 */; };
-               F939F21B078F1A2C00AC144F /* dyld_debug.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = F939F219078F1A2100AC144F /* dyld_debug.h */; };
-               F93AA9A30630AE1E00301D9F /* dyld_gdb.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = F9ED4CE80630A80600DF4E74 /* dyld_gdb.h */; };
-               F93AA9A40630AE1E00301D9F /* dyld_priv.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = F9ED4CE90630A80600DF4E74 /* dyld_priv.h */; };
-               F93AA9A50630AE1E00301D9F /* dyld.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = F9ED4CEA0630A80600DF4E74 /* dyld.h */; };
-               F93C8C2A0B84EBFC00615A00 /* update_prebinding.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = F93C8C290B84EBFC00615A00 /* update_prebinding.1 */; };
-               F9574CB306C95C1B00142BFA /* dlfcn.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = F99EE6AE06B48D4200BF1992 /* dlfcn.h */; };
-               F98D274D0AA79D7400416316 /* dyld_images.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = F98D274C0AA79D7400416316 /* dyld_images.h */; };
-               F9AB705B0BA73A11002F6068 /* dyld_shared_cache_user.c in Sources */ = {isa = PBXBuildFile; fileRef = F9AB70590BA73A11002F6068 /* dyld_shared_cache_user.c */; settings = {COMPILER_FLAGS = "-fvisibility=hidden"; }; };
+               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 */; };
+               F9A221E70F3A6D7C00D15F73 /* dyldLibSystemGlue.c in Sources */ = {isa = PBXBuildFile; fileRef = F9A221E60F3A6D7C00D15F73 /* dyldLibSystemGlue.c */; };
                F9AC7E940B7BB67700FEB38B /* version.c in Sources */ = {isa = PBXBuildFile; fileRef = F9AC7E930B7BB67700FEB38B /* version.c */; };
-               F9D238DB0A9E2FD0002B55C7 /* update_dyld_shared_cache.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = F9D238D90A9E19A0002B55C7 /* update_dyld_shared_cache.1 */; };
-               F9E572020A66EF4A007D9BE9 /* dlopen_preflight.3 in CopyFiles */ = {isa = PBXBuildFile; fileRef = F9E572000A66EF41007D9BE9 /* dlopen_preflight.3 */; };
+               F9BA514B0ECE4F4200D1D62E /* dyld_stub_binder.s in Sources */ = {isa = PBXBuildFile; fileRef = F99EFC0D0EAD60E8001032B8 /* dyld_stub_binder.s */; };
+               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 */; };
                F9ED4CE30630A7F100DF4E74 /* ImageLoaderMachO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9ED4CD30630A7F100DF4E74 /* ImageLoaderMachO.cpp */; };
                F9ED4CE50630A7F100DF4E74 /* stub_binding_helper.s in Sources */ = {isa = PBXBuildFile; fileRef = F9ED4CD50630A7F100DF4E74 /* stub_binding_helper.s */; };
                F9F256360639DBCC00A7427D /* dyldLock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9ED4CCC0630A7F100DF4E74 /* dyldLock.cpp */; };
+               F9F2A5700F7AEEE300B7C9EB /* dsc_iterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9F2A56E0F7AEEE300B7C9EB /* dsc_iterator.cpp */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXBuildRule section */
                F921D3160703769A000D1056 /* PBXBuildRule */ = {
                        isa = PBXBuildRule;
-                       compilerSpec = com.apple.compilers.gcc.4_0;
+                       compilerSpec = com.apple.compilers.gcc;
                        fileType = sourcecode.cpp;
                        isEditable = 1;
                        outputFiles = (
@@ -73,7 +74,7 @@
                };
                F921D317070376A6000D1056 /* PBXBuildRule */ = {
                        isa = PBXBuildRule;
-                       compilerSpec = com.apple.compilers.gcc.4_0;
+                       compilerSpec = com.apple.compilers.gcc;
                        fileType = sourcecode.c;
                        isEditable = 1;
                        outputFiles = (
@@ -81,7 +82,7 @@
                };
                F921D318070376B0000D1056 /* PBXBuildRule */ = {
                        isa = PBXBuildRule;
-                       compilerSpec = com.apple.compilers.gcc.4_0;
+                       compilerSpec = com.apple.compilers.gcc;
                        fileType = sourcecode.asm;
                        isEditable = 1;
                        outputFiles = (
@@ -89,7 +90,7 @@
                };
                F921D31E070376F1000D1056 /* PBXBuildRule */ = {
                        isa = PBXBuildRule;
-                       compilerSpec = com.apple.compilers.gcc.4_0;
+                       compilerSpec = com.apple.compilers.gcc;
                        fileType = sourcecode.cpp;
                        isEditable = 1;
                        outputFiles = (
@@ -97,7 +98,7 @@
                };
                F9574C4906C94DA700142BFA /* PBXBuildRule */ = {
                        isa = PBXBuildRule;
-                       compilerSpec = com.apple.compilers.gcc.4_0;
+                       compilerSpec = com.apple.compilers.gcc;
                        fileType = sourcecode.c;
                        isEditable = 1;
                        outputFiles = (
                        remoteGlobalIDString = F93937310A94FAF700070A07;
                        remoteInfo = update_dyld_shared_cache;
                };
-               F93937390A94FB6E00070A07 /* PBXContainerItemProxy */ = {
+               F98C78D90F7C017F006257D2 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = F9ED4C8B0630A72300DF4E74 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = F93937310A94FAF700070A07;
-                       remoteInfo = update_dyld_shared_cache;
+                       remoteGlobalIDString = F9F2A5580F7AEE9800B7C9EB;
+                       remoteInfo = dsc;
                };
                F9ED4CA60630A78A00DF4E74 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXCopyFilesBuildPhase section */
-               F932C2560BC32AC30018B20D /* CopyFiles */ = {
+               F90CF2950E71D1FB000BF0F1 /* usr|local|include */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = /System/Library/LaunchDaemons;
+                       dstPath = /usr/local/include;
                        dstSubfolderSpec = 0;
                        files = (
-                               F932C2520BC32ABB0018B20D /* com.apple.dyld.plist in CopyFiles */,
                        );
+                       name = "usr|local|include";
                        runOnlyForDeploymentPostprocessing = 1;
                };
-               F93AA9B30630AE8200301D9F /* CopyFiles */ = {
+               F93AA9B30630AE8200301D9F /* usr|include|mach-o */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                        dstPath = "/usr/include/mach-o";
                        dstSubfolderSpec = 0;
                        files = (
-                               F939F21B078F1A2C00AC144F /* dyld_debug.h in CopyFiles */,
-                               F93AA9A50630AE1E00301D9F /* dyld.h in CopyFiles */,
-                               F98D274D0AA79D7400416316 /* dyld_images.h in CopyFiles */,
+                               F93AA9A50630AE1E00301D9F /* dyld.h in usr|include|mach-o */,
+                               F98D274D0AA79D7400416316 /* dyld_images.h in usr|include|mach-o */,
                        );
+                       name = "usr|include|mach-o";
                        runOnlyForDeploymentPostprocessing = 1;
                };
-               F93AA9B60630AEB100301D9F /* CopyFiles */ = {
+               F93AA9B60630AEB100301D9F /* usr|local|include|mach-o */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                        dstPath = "/usr/local/include/mach-o";
                        dstSubfolderSpec = 0;
                        files = (
-                               F918691608B16D3500E0F9DB /* dyld-interposing.h in CopyFiles */,
-                               F919ECB1090455AB002331E3 /* dyld-update-prebinding.h in CopyFiles */,
-                               F93AA9A30630AE1E00301D9F /* dyld_gdb.h in CopyFiles */,
-                               F93AA9A40630AE1E00301D9F /* dyld_priv.h in CopyFiles */,
+                               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 */,
                        );
+                       name = "usr|local|include|mach-o";
                        runOnlyForDeploymentPostprocessing = 1;
                };
-               F93AA9C20630AF0700301D9F /* CopyFiles */ = {
+               F93AA9C20630AF0700301D9F /* usr|share|man|man1 */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                        dstPath = /usr/share/man/man1;
                        dstSubfolderSpec = 0;
                        files = (
-                               EF79A010070D293E00F78484 /* dyld.1 in CopyFiles */,
+                               EF79A010070D293E00F78484 /* dyld.1 in usr|share|man|man1 */,
                        );
+                       name = "usr|share|man|man1";
                        runOnlyForDeploymentPostprocessing = 1;
                };
-               F93AA9C60630AF1F00301D9F /* CopyFiles */ = {
+               F93AA9C60630AF1F00301D9F /* usr|share|man|man3 */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                        dstPath = /usr/share/man/man3;
                        dstSubfolderSpec = 0;
                        files = (
-                               EF79A011070D295200F78484 /* dladdr.3 in CopyFiles */,
-                               EF79A012070D295200F78484 /* dlclose.3 in CopyFiles */,
-                               EF79A013070D295200F78484 /* dlerror.3 in CopyFiles */,
-                               EF79A014070D295200F78484 /* dlopen.3 in CopyFiles */,
-                               EF79A015070D295200F78484 /* dlsym.3 in CopyFiles */,
-                               EF79A016070D295200F78484 /* dyld.3 in CopyFiles */,
-                               F9E572020A66EF4A007D9BE9 /* dlopen_preflight.3 in CopyFiles */,
-                       );
+                               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 */,
+                       );
+                       name = "usr|share|man|man3";
                        runOnlyForDeploymentPostprocessing = 1;
                };
-               F9574CB206C95C0D00142BFA /* CopyFiles */ = {
+               F9574CB206C95C0D00142BFA /* usr|include */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                        dstPath = /usr/include;
                        dstSubfolderSpec = 0;
                        files = (
-                               F9574CB306C95C1B00142BFA /* dlfcn.h in CopyFiles */,
+                               F9574CB306C95C1B00142BFA /* dlfcn.h in usr|include */,
+                       );
+                       name = "usr|include";
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+               F98C78D10F7C00EA006257D2 /* usr|local|include|mach-o */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = "/usr/local/include/mach-o";
+                       dstSubfolderSpec = 0;
+                       files = (
+                               F98C78F00F7C02E8006257D2 /* dsc_iterator.h in usr|local|include|mach-o */,
                        );
+                       name = "usr|local|include|mach-o";
                        runOnlyForDeploymentPostprocessing = 1;
                };
-               F9D238DD0A9E2FEE002B55C7 /* CopyFiles */ = {
+               F9D238DD0A9E2FEE002B55C7 /* usr|share|man|man1 */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                        dstPath = /usr/share/man/man1;
                        dstSubfolderSpec = 0;
                        files = (
-                               F9D238DB0A9E2FD0002B55C7 /* update_dyld_shared_cache.1 in CopyFiles */,
-                               F93C8C2A0B84EBFC00615A00 /* update_prebinding.1 in CopyFiles */,
+                               F9D238DB0A9E2FD0002B55C7 /* update_dyld_shared_cache.1 in usr|share|man|man1 */,
                        );
+                       name = "usr|share|man|man1";
                        runOnlyForDeploymentPostprocessing = 1;
                };
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
+               834A90AB0E1D85D600555761 /* ObjCLegacyAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ObjCLegacyAbstraction.hpp; sourceTree = "<group>"; };
+               834A90AC0E1D85D600555761 /* ObjCModernAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ObjCModernAbstraction.hpp; sourceTree = "<group>"; };
                EF799FE9070D27BB00F78484 /* dyld.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; name = dyld.1; path = doc/man/man1/dyld.1; sourceTree = SOURCE_ROOT; };
                EF799FEB070D27BB00F78484 /* dladdr.3 */ = {isa = PBXFileReference; explicitFileType = text.man; fileEncoding = 30; name = dladdr.3; path = doc/man/man3/dladdr.3; sourceTree = SOURCE_ROOT; };
                EF799FEC070D27BB00F78484 /* dlclose.3 */ = {isa = PBXFileReference; explicitFileType = text.man; fileEncoding = 30; name = dlclose.3; path = doc/man/man3/dlclose.3; sourceTree = SOURCE_ROOT; };
                F906E2230639E96400B13DB2 /* dyld_debug.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = dyld_debug.c; path = src/dyld_debug.c; sourceTree = "<group>"; };
                F913FAD90630A8AE00B7AE9D /* dyldAPIsInLibSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = dyldAPIsInLibSystem.cpp; path = src/dyldAPIsInLibSystem.cpp; sourceTree = "<group>"; };
                F918691408B16D2500E0F9DB /* dyld-interposing.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = "dyld-interposing.h"; path = "include/mach-o/dyld-interposing.h"; sourceTree = "<group>"; };
-               F918691708B16D5900E0F9DB /* dyld64.exp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.exports; name = dyld64.exp; path = src/dyld64.exp; sourceTree = "<group>"; };
-               F919ECAB09045590002331E3 /* dyld-update-prebinding.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = "dyld-update-prebinding.h"; path = "include/mach-o/dyld-update-prebinding.h"; sourceTree = "<group>"; };
-               F93075C10BA1FE4D004BCA09 /* dyld_shared_cache_server.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = dyld_shared_cache_server.c; path = generated/dyld_shared_cache_server.c; sourceTree = BUILT_PRODUCTS_DIR; };
-               F93075C20BA1FE4D004BCA09 /* dyld_shared_cache_server.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dyld_shared_cache_server.h; path = generated/dyld_shared_cache_server.h; sourceTree = BUILT_PRODUCTS_DIR; };
-               F93075D30BA204FF004BCA09 /* com.apple.dyld.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist.xml; path = com.apple.dyld.plist; sourceTree = "<group>"; };
-               F93075D40BA204FF004BCA09 /* dyld_shared_cache.defs */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.mig; path = dyld_shared_cache.defs; sourceTree = "<group>"; };
                F93937320A94FAF700070A07 /* update_dyld_shared_cache */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = update_dyld_shared_cache; sourceTree = BUILT_PRODUCTS_DIR; };
                F939373E0A94FC4700070A07 /* Architectures.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Architectures.hpp; sourceTree = "<group>"; };
                F939373F0A94FC4700070A07 /* CacheFileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CacheFileAbstraction.hpp; sourceTree = "<group>"; };
                F93937440A94FC4700070A07 /* MachOLayout.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = MachOLayout.hpp; sourceTree = "<group>"; };
                F93937460A94FC4700070A07 /* update_dyld_shared_cache.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = update_dyld_shared_cache.cpp; sourceTree = "<group>"; };
                F939F219078F1A2100AC144F /* dyld_debug.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dyld_debug.h; path = "include/mach-o/dyld_debug.h"; sourceTree = "<group>"; };
-               F93C8C290B84EBFC00615A00 /* update_prebinding.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; path = update_prebinding.1; sourceTree = "<group>"; };
-               F973667C0BD004F200E5E1B4 /* ImageLoaderPE.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ImageLoaderPE.cpp; path = src/ImageLoaderPE.cpp; sourceTree = "<group>"; };
-               F973667D0BD004F200E5E1B4 /* ImageLoaderPE.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ImageLoaderPE.h; path = src/ImageLoaderPE.h; sourceTree = "<group>"; };
+               F94DB9000F0A9B1700323715 /* ImageLoaderMachOClassic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ImageLoaderMachOClassic.cpp; path = src/ImageLoaderMachOClassic.cpp; sourceTree = "<group>"; };
+               F94DB9010F0A9B1700323715 /* ImageLoaderMachOClassic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ImageLoaderMachOClassic.h; path = src/ImageLoaderMachOClassic.h; sourceTree = "<group>"; };
+               F94DB9020F0A9B1700323715 /* ImageLoaderMachOCompressed.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ImageLoaderMachOCompressed.cpp; path = src/ImageLoaderMachOCompressed.cpp; sourceTree = "<group>"; };
+               F94DB9030F0A9B1700323715 /* ImageLoaderMachOCompressed.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ImageLoaderMachOCompressed.h; path = src/ImageLoaderMachOCompressed.h; sourceTree = "<group>"; };
+               F95C95160E994796007B7CB8 /* MachOTrie.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MachOTrie.hpp; sourceTree = "<group>"; };
                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>"; };
                F99EE6AE06B48D4200BF1992 /* dlfcn.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dlfcn.h; path = include/dlfcn.h; sourceTree = "<group>"; };
-               F9AB70590BA73A11002F6068 /* dyld_shared_cache_user.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = dyld_shared_cache_user.c; path = generated/dyld_shared_cache_user.c; sourceTree = BUILT_PRODUCTS_DIR; };
-               F9AB705A0BA73A11002F6068 /* dyld_shared_cache_user.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dyld_shared_cache_user.h; path = generated/dyld_shared_cache_user.h; sourceTree = BUILT_PRODUCTS_DIR; };
+               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>"; };
                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; };
                F9ED4CE80630A80600DF4E74 /* dyld_gdb.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dyld_gdb.h; path = "include/mach-o/dyld_gdb.h"; sourceTree = SOURCE_ROOT; };
                F9ED4CE90630A80600DF4E74 /* dyld_priv.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dyld_priv.h; path = "include/mach-o/dyld_priv.h"; sourceTree = SOURCE_ROOT; };
                F9ED4CEA0630A80600DF4E74 /* dyld.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dyld.h; path = "include/mach-o/dyld.h"; sourceTree = SOURCE_ROOT; };
+               F9F2A5590F7AEE9800B7C9EB /* libdsc.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdsc.a; sourceTree = BUILT_PRODUCTS_DIR; };
+               F9F2A56E0F7AEEE300B7C9EB /* dsc_iterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dsc_iterator.cpp; sourceTree = "<group>"; };
+               F9F2A56F0F7AEEE300B7C9EB /* dsc_iterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dsc_iterator.h; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               F9F2A5570F7AEE9800B7C9EB /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
                        isa = PBXGroup;
                        children = (
                                EF799FE9070D27BB00F78484 /* dyld.1 */,
-                               F93C8C290B84EBFC00615A00 /* update_prebinding.1 */,
                                F9D238D90A9E19A0002B55C7 /* update_dyld_shared_cache.1 */,
                        );
                        name = man1;
                                F93937440A94FC4700070A07 /* MachOLayout.hpp */,
                                F98935BA0A9A412B00FB6228 /* MachORebaser.hpp */,
                                F98935B90A9A412B00FB6228 /* MachOBinder.hpp */,
+                               F95C95160E994796007B7CB8 /* MachOTrie.hpp */,
+                               834A90AB0E1D85D600555761 /* ObjCLegacyAbstraction.hpp */,
+                               834A90AC0E1D85D600555761 /* ObjCModernAbstraction.hpp */,
                                F93937460A94FC4700070A07 /* update_dyld_shared_cache.cpp */,
-                               F93075C10BA1FE4D004BCA09 /* dyld_shared_cache_server.c */,
-                               F93075C20BA1FE4D004BCA09 /* dyld_shared_cache_server.h */,
-                               F93075D30BA204FF004BCA09 /* com.apple.dyld.plist */,
-                               F93075D40BA204FF004BCA09 /* dyld_shared_cache.defs */,
+                               F9F2A56E0F7AEEE300B7C9EB /* dsc_iterator.cpp */,
+                               F9F2A56F0F7AEEE300B7C9EB /* dsc_iterator.h */,
                        );
                        path = "launch-cache";
                        sourceTree = "<group>";
                                F9ED4C980630A76000DF4E74 /* dyld */,
                                F9ED4C9F0630A76B00DF4E74 /* libdyldapis.a */,
                                F93937320A94FAF700070A07 /* update_dyld_shared_cache */,
+                               F9F2A5590F7AEE9800B7C9EB /* libdsc.a */,
                        );
                        name = Products;
                        sourceTree = "<group>";
                                F9ED4CCD0630A7F100DF4E74 /* dyldLock.h */,
                                F9ED4CCE0630A7F100DF4E74 /* dyldNew.cpp */,
                                F9ED4CCF0630A7F100DF4E74 /* dyldStartup.s */,
+                               F99EFC0D0EAD60E8001032B8 /* dyld_stub_binder.s */,
                                F9ED4CD00630A7F100DF4E74 /* glue.c */,
                                F9ED4CD10630A7F100DF4E74 /* ImageLoader.cpp */,
                                F9ED4CD20630A7F100DF4E74 /* ImageLoader.h */,
                                F9ED4CD30630A7F100DF4E74 /* ImageLoaderMachO.cpp */,
                                F9ED4CD40630A7F100DF4E74 /* ImageLoaderMachO.h */,
-                               F973667C0BD004F200E5E1B4 /* ImageLoaderPE.cpp */,
-                               F973667D0BD004F200E5E1B4 /* ImageLoaderPE.h */,
+                               F94DB9000F0A9B1700323715 /* ImageLoaderMachOClassic.cpp */,
+                               F94DB9010F0A9B1700323715 /* ImageLoaderMachOClassic.h */,
+                               F94DB9020F0A9B1700323715 /* ImageLoaderMachOCompressed.cpp */,
+                               F94DB9030F0A9B1700323715 /* ImageLoaderMachOCompressed.h */,
                                F9ED4CD50630A7F100DF4E74 /* stub_binding_helper.s */,
                                F9B01E3D0739ABDE00CF981B /* dyld.exp */,
-                               F918691708B16D5900E0F9DB /* dyld64.exp */,
                                F9AC7E930B7BB67700FEB38B /* version.c */,
-                               F9AB70590BA73A11002F6068 /* dyld_shared_cache_user.c */,
-                               F9AB705A0BA73A11002F6068 /* dyld_shared_cache_user.h */,
                                F918691408B16D2500E0F9DB /* dyld-interposing.h */,
+                               F9A221E60F3A6D7C00D15F73 /* dyldLibSystemGlue.c */,
                                F906E2230639E96400B13DB2 /* dyld_debug.c */,
                        );
                        name = src;
                                F98D274C0AA79D7400416316 /* dyld_images.h */,
                                F9ED4CE80630A80600DF4E74 /* dyld_gdb.h */,
                                F9ED4CE90630A80600DF4E74 /* dyld_priv.h */,
-                               F919ECAB09045590002331E3 /* dyld-update-prebinding.h */,
                                F939F219078F1A2100AC144F /* dyld_debug.h */,
                                F9ED4CEA0630A80600DF4E74 /* dyld.h */,
                                F99EE6AE06B48D4200BF1992 /* dlfcn.h */,
                        isa = PBXNativeTarget;
                        buildConfigurationList = F93937340A94FB2900070A07 /* Build configuration list for PBXNativeTarget "update_dyld_shared_cache" */;
                        buildPhases = (
-                               F93075AF0BA1FC60004BCA09 /* ShellScript */,
                                F939372F0A94FAF700070A07 /* Sources */,
                                F93937300A94FAF700070A07 /* Frameworks */,
-                               F9D238DD0A9E2FEE002B55C7 /* CopyFiles */,
-                               F932C2560BC32AC30018B20D /* CopyFiles */,
-                               F93C8C250B84EB2300615A00 /* ShellScript */,
+                               F9D238DD0A9E2FEE002B55C7 /* usr|share|man|man1 */,
                        );
                        buildRules = (
                        );
                        dependencies = (
+                               F98C78DA0F7C017F006257D2 /* PBXTargetDependency */,
                        );
                        name = update_dyld_shared_cache;
                        productName = update_dyld_shared_cache;
                                F921D3160703769A000D1056 /* PBXBuildRule */,
                        );
                        dependencies = (
-                               F939373A0A94FB6E00070A07 /* PBXTargetDependency */,
                        );
                        name = dyld;
                        productName = dyld;
                        isa = PBXNativeTarget;
                        buildConfigurationList = F9D8C7E1087B087300E93EFB /* Build configuration list for PBXNativeTarget "libdyld" */;
                        buildPhases = (
-                               F9AC7E7E0B7BB3D300FEB38B /* ShellScript */,
-                               F9AB70540BA73985002F6068 /* ShellScript */,
+                               F9AC7E7E0B7BB3D300FEB38B /* create version.c */,
                                F9ED4C9C0630A76B00DF4E74 /* Sources */,
-                               F93AA9B30630AE8200301D9F /* CopyFiles */,
-                               F9574CB206C95C0D00142BFA /* CopyFiles */,
-                               F93AA9B60630AEB100301D9F /* CopyFiles */,
-                               F93AA9C20630AF0700301D9F /* CopyFiles */,
-                               F93AA9C60630AF1F00301D9F /* CopyFiles */,
-                               F918692408B16F6900E0F9DB /* ShellScript */,
+                               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 */,
                        productReference = F9ED4C9F0630A76B00DF4E74 /* libdyldapis.a */;
                        productType = "com.apple.product-type.library.static";
                };
+               F9F2A5580F7AEE9800B7C9EB /* dsc */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = F9F2A56B0F7AEEB100B7C9EB /* Build configuration list for PBXNativeTarget "dsc" */;
+                       buildPhases = (
+                               F9F2A5560F7AEE9800B7C9EB /* Sources */,
+                               F9F2A5570F7AEE9800B7C9EB /* Frameworks */,
+                               F98C78D10F7C00EA006257D2 /* usr|local|include|mach-o */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = dsc;
+                       productName = dsc;
+                       productReference = F9F2A5590F7AEE9800B7C9EB /* libdsc.a */;
+                       productType = "com.apple.product-type.library.static";
+               };
 /* End PBXNativeTarget section */
 
 /* Begin PBXProject section */
                        productRefGroup = F9ED4C990630A76000DF4E74 /* Products */;
                        projectDirPath = "";
                        projectRoot = "";
-                       shouldCheckCompatibility = 1;
                        targets = (
                                F9ED4C920630A73900DF4E74 /* all */,
                                F9ED4C970630A76000DF4E74 /* dyld */,
                                F9ED4C9E0630A76B00DF4E74 /* libdyld */,
                                F93937310A94FAF700070A07 /* update_dyld_shared_cache */,
+                               F9F2A5580F7AEE9800B7C9EB /* dsc */,
                        );
                };
 /* End PBXProject section */
 
 /* Begin PBXShellScriptBuildPhase section */
-               F918692408B16F6900E0F9DB /* ShellScript */ = {
+               F918692408B16F6900E0F9DB /* install symlinks */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 8;
                        files = (
                        );
                        inputPaths = (
                        );
+                       name = "install symlinks";
                        outputPaths = (
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                        shellScript = "cd ${DSTROOT}/usr/local/lib/system\nln -sf libdyldapis.a libdyldapis_profile.a\nln -sf libdyldapis.a libdyldapis_debug.a\n";
                        showEnvVarsInLog = 0;
                };
-               F93075AF0BA1FC60004BCA09 /* ShellScript */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       inputPaths = (
-                               "$(SRCROOT)/launch-cache/dyld_shared_cache.defs",
-                       );
-                       outputPaths = (
-                               "$(BUILT_PRODUCTS_DIR)/generated/dyld_shared_cache_server.h",
-                               "$(BUILT_PRODUCTS_DIR)/generated/dyld_shared_cache_server.c",
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-                       shellPath = /bin/sh;
-                       shellScript = "mkdir -p ${BUILT_PRODUCTS_DIR}/generated\nmig -server ${BUILT_PRODUCTS_DIR}/generated/dyld_shared_cache_server.c -sheader ${BUILT_PRODUCTS_DIR}/generated/dyld_shared_cache_server.h -user /dev/null -header /dev/null ${SRCROOT}/launch-cache/dyld_shared_cache.defs\necho \"mig -server ${BUILT_PRODUCTS_DIR}/generated/dyld_shared_cache_server.c -sheader ${BUILT_PRODUCTS_DIR}/generated/dyld_shared_cache_server.h -user /dev/null -header /dev/null ${SRCROOT}/launch-cache/dyld_shared_cache.defs\"";
-                       showEnvVarsInLog = 0;
-               };
-               F93C8C250B84EB2300615A00 /* ShellScript */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 8;
-                       files = (
-                       );
-                       inputPaths = (
-                       );
-                       outputPaths = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 1;
-                       shellPath = /bin/sh;
-                       shellScript = "mkdir -p ${DSTROOT}/usr/bin\ncd  ${DSTROOT}/usr/bin\nln -sf update_dyld_shared_cache update_prebinding\n\n\n";
-                       showEnvVarsInLog = 0;
-               };
-               F9AB70540BA73985002F6068 /* ShellScript */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       inputPaths = (
-                               "$(SRCROOT)/launch-cache/dyld_shared_cache.defs",
-                       );
-                       outputPaths = (
-                               "$(BUILT_PRODUCTS_DIR)/generated/dyld_shared_cache_user.c",
-                               "$(BUILT_PRODUCTS_DIR)/generated/dyld_shared_cache_user.h",
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-                       shellPath = /bin/sh;
-                       shellScript = "mkdir -p ${BUILT_PRODUCTS_DIR}/generated\nmig -user ${BUILT_PRODUCTS_DIR}/generated/dyld_shared_cache_user.c -header ${BUILT_PRODUCTS_DIR}/generated/dyld_shared_cache_user.h -server /dev/null  ${SRCROOT}/launch-cache/dyld_shared_cache.defs\n";
-                       showEnvVarsInLog = 0;
-               };
-               F9AC7E7E0B7BB3D300FEB38B /* ShellScript */ = {
+               F9AC7E7E0B7BB3D300FEB38B /* create version.c */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
                        );
                        inputPaths = (
                        );
+                       name = "create version.c";
                        outputPaths = (
                                "$(BUILT_PRODUCTS_DIR)/version.c",
                        );
                        buildActionMask = 2147483647;
                        files = (
                                F93937470A94FC4700070A07 /* update_dyld_shared_cache.cpp in Sources */,
-                               F93075C30BA1FE4D004BCA09 /* dyld_shared_cache_server.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                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 */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                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 */,
-                               F9AB705B0BA73A11002F6068 /* dyld_shared_cache_user.c in Sources */,
+                               F9A221E70F3A6D7C00D15F73 /* dyldLibSystemGlue.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               F9F2A5560F7AEE9800B7C9EB /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               F9F2A5700F7AEEE300B7C9EB /* dsc_iterator.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        target = F93937310A94FAF700070A07 /* update_dyld_shared_cache */;
                        targetProxy = F93937370A94FB6A00070A07 /* PBXContainerItemProxy */;
                };
-               F939373A0A94FB6E00070A07 /* PBXTargetDependency */ = {
+               F98C78DA0F7C017F006257D2 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = F93937310A94FAF700070A07 /* update_dyld_shared_cache */;
-                       targetProxy = F93937390A94FB6E00070A07 /* PBXContainerItemProxy */;
+                       target = F9F2A5580F7AEE9800B7C9EB /* dsc */;
+                       targetProxy = F98C78D90F7C017F006257D2 /* PBXContainerItemProxy */;
                };
                F9ED4CA70630A78A00DF4E74 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        buildSettings = {
                                COPY_PHASE_STRIP = NO;
                                DEBUG_INFORMATION_FORMAT = dwarf;
-                               GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_DYNAMIC_NO_PIC = YES;
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_OPTIMIZATION_LEVEL = 0;
                                GCC_THREADSAFE_STATICS = NO;
                F93937360A94FB2900070A07 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               COPY_PHASE_STRIP = YES;
+                               COPY_PHASE_STRIP = NO;
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                GCC_OPTIMIZATION_LEVEL = 3;
                                GCC_THREADSAFE_STATICS = NO;
                                GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
                                INSTALL_PATH = /usr/bin;
-                               MACOSX_DEPLOYMENT_TARGET = 10.5;
                                PREBINDING = NO;
                                PRODUCT_NAME = update_dyld_shared_cache;
-                               VALID_ARCHS = "ppc i386";
+                               STRIP_INSTALLED_PRODUCT = YES;
+                               STRIP_STYLE = debugging;
+                               VALID_ARCHS = "x86_64 i386";
                                VERSIONING_SYSTEM = "apple-generic";
                        };
                        name = Release;
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               BASE_ADDRESS_i386 = 0x8f000000;
-                               BASE_ADDRESS_ppc = 0x8f000000;
-                               BASE_ADDRESS_ppc64 = 0x7fff5fc00000;
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                                       x86_64,
+                               );
+                               BASE_ADDRESS_armv4t = 0x2fe00000;
+                               BASE_ADDRESS_armv5 = 0x2fe00000;
+                               BASE_ADDRESS_armv6 = 0x2fe00000;
+                               BASE_ADDRESS_armv7 = 0x2fe00000;
+                               BASE_ADDRESS_i386 = 0x8fe00000;
+                               BASE_ADDRESS_ppc = 0x8fe00000;
                                BASE_ADDRESS_x86_64 = 0x7fff5fc00000;
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                DEAD_CODE_STRIPPING = YES;
-                               EXPORTED_SYMBOLS_FILE = "$(EXPORTED_SYMBOLS_FILE_$(CURRENT_ARCH))";
-                               EXPORTED_SYMBOLS_FILE_i386 = "$(SRCROOT)/src/dyld.exp";
-                               EXPORTED_SYMBOLS_FILE_ppc = "$(SRCROOT)/src/dyld.exp";
-                               EXPORTED_SYMBOLS_FILE_ppc64 = "$(SRCROOT)/src/dyld64.exp";
-                               EXPORTED_SYMBOLS_FILE_x86_64 = "$(SRCROOT)/src/dyld64.exp";
+                               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;
-                               GCC_MODEL_TUNING = G4;
+                               GCC_ENABLE_BUILTIN_FUNCTIONS = NO;
                                GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_PREPROCESSOR_DEFINITIONS = "DYLD_VERSION=$(RC_ProjectSourceVersion)";
                                GCC_SYMBOLS_PRIVATE_EXTERN = NO;
                                GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
                                GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO;
                                        "./launch-cache",
                                );
                                INSTALL_PATH = /usr/lib;
-                               MACOSX_DEPLOYMENT_TARGET = 10.5;
+                               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))",
                                        "-nostdlib",
                                        /usr/local/lib/system/libc.a,
-                                       "-lgcc_eh",
+                                       /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 = "";
-                               PER_ARCH_CFLAGS_ppc64 = "-msoft-float";
                                PREBINDING = NO;
                                PRODUCT_NAME = dyld;
                                STRIPFLAGS = "-S";
                                UNSTRIPPED_PRODUCT = NO;
-                               VALID_ARCHS = "ppc ppc64 i386 x86_64";
                                VERSIONING_SYSTEM = "apple-generic";
                                WARNING_CFLAGS = (
                                        "-Wmost",
                F9D8C7E0087B087300E93EFB /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+                               BASE_ADDRESS_armv4t = 0x2fe00000;
+                               BASE_ADDRESS_armv5 = 0x2fe00000;
+                               BASE_ADDRESS_armv6 = 0x2fe00000;
+                               BASE_ADDRESS_armv7 = 0x2fe00000;
                                BASE_ADDRESS_i386 = 0x8fe00000;
                                BASE_ADDRESS_ppc = 0x8fe00000;
-                               BASE_ADDRESS_ppc64 = 0x7fff5fc00000;
                                BASE_ADDRESS_x86_64 = 0x7fff5fc00000;
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                DEAD_CODE_STRIPPING = YES;
-                               EXPORTED_SYMBOLS_FILE = "$(EXPORTED_SYMBOLS_FILE_$(CURRENT_ARCH))";
-                               EXPORTED_SYMBOLS_FILE_i386 = "$(SRCROOT)/src/dyld.exp";
-                               EXPORTED_SYMBOLS_FILE_ppc = "$(SRCROOT)/src/dyld.exp";
-                               EXPORTED_SYMBOLS_FILE_ppc64 = "$(SRCROOT)/src/dyld64.exp";
-                               EXPORTED_SYMBOLS_FILE_x86_64 = "$(SRCROOT)/src/dyld64.exp";
+                               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;
                                GCC_ENABLE_CPP_RTTI = NO;
-                               GCC_MODEL_TUNING = G4;
-                               GCC_OPTIMIZATION_LEVEL = 3;
+                               GCC_OPTIMIZATION_LEVEL = s;
+                               GCC_PREPROCESSOR_DEFINITIONS = "DYLD_VERSION=$(RC_ProjectSourceVersion)";
                                GCC_SYMBOLS_PRIVATE_EXTERN = NO;
                                GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
                                GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
                                        "./launch-cache",
                                );
                                INSTALL_PATH = /usr/lib;
-                               MACOSX_DEPLOYMENT_TARGET = 10.5;
+                               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))",
                                        "-nostdlib",
                                        /usr/local/lib/system/libc.a,
-                                       "-lgcc_eh",
+                                       /usr/local/lib/libCoreSymbolicationSharedWithDyld.a,
+                                       "$(EXCEPTION_LIB_$(CURRENT_ARCH))",
                                        "-lgcc",
                                        "-Wl,-e,__dyld_start",
                                        "-Wl,-dylinker",
                                        "-Wl,-dylinker_install_name,/usr/lib/dyld",
-                                       "-Wl,-non_global_symbols_strip_list,$(SRCROOT)/src/strip.exp",
                                );
                                PER_ARCH_CFLAGS_ppc = "";
-                               PER_ARCH_CFLAGS_ppc64 = "-msoft-float";
                                PREBINDING = NO;
                                PRODUCT_NAME = dyld;
                                STRIPFLAGS = "-S";
                                UNSTRIPPED_PRODUCT = NO;
-                               VALID_ARCHS = "ppc ppc64 i386 x86_64";
                                VERSIONING_SYSTEM = "apple-generic";
                                WARNING_CFLAGS = (
                                        "-Wmost",
                                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;
-                               VALID_ARCHS = "ppc ppc64 i386 x86_64";
                                WARNING_CFLAGS = (
                                        "-Wmost",
                                        "-Wno-four-char-constants",
                                GCC_ENABLE_CPP_EXCEPTIONS = NO;
                                GCC_ENABLE_CPP_RTTI = NO;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
                                HEADER_SEARCH_PATHS = ./include;
                                INSTALL_PATH = /usr/local/lib/system;
                                LIBRARY_STYLE = STATIC;
                                PRODUCT_NAME = dyldapis;
-                               VALID_ARCHS = "ppc ppc64 i386 x86_64";
                                WARNING_CFLAGS = (
                                        "-Wmost",
                                        "-Wno-four-char-constants",
                        };
                        name = Release;
                };
+               F9F2A55A0F7AEE9900B7C9EB /* 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 = dsc;
+                       };
+                       name = Debug;
+               };
+               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";
+                               GCC_ENABLE_CPP_EXCEPTIONS = NO;
+                               GCC_ENABLE_CPP_RTTI = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               GCC_ENABLE_OBJC_EXCEPTIONS = NO;
+                               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_SIGN_COMPARE = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               INSTALL_PATH = /usr/local/lib;
+                               PREBINDING = NO;
+                               PRODUCT_NAME = dsc;
+                               ZERO_LINK = NO;
+                       };
+                       name = Release;
+               };
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
+               F9F2A56B0F7AEEB100B7C9EB /* Build configuration list for PBXNativeTarget "dsc" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               F9F2A55A0F7AEE9900B7C9EB /* Debug */,
+                               F9F2A55B0F7AEE9900B7C9EB /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
 /* End XCConfigurationList section */
        };
        rootObject = F9ED4C8B0630A72300DF4E74 /* Project object */;
index 2e502c554f560d13111328433d0dba1f963e9a4e..7e4ae35cfa2c0d46c09b0b0d84e2f8abd813b6e3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2004-2008 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -75,9 +75,10 @@ extern bool dlopen_preflight(const char* __path) AVAILABLE_MAC_OS_X_VERSION_10_5
 /*
  * Special handle arguments for dlsym().
  */
-#define        RTLD_NEXT               ((void *) -1)   /* Search subsequent objects. */
+#define        RTLD_NEXT       ((void *) -1)   /* Search subsequent objects. */
 #define        RTLD_DEFAULT    ((void *) -2)   /* Use default search algorithm. */
-#define        RTLD_SELF               ((void *) -3)   /* Search this and subsequent objects (Mac OS X 10.5 and later) */
+#define        RTLD_SELF       ((void *) -3)   /* Search this and subsequent objects (Mac OS X 10.5 and later) */
+#define        RTLD_MAIN_ONLY  ((void *) -5)   /* Search main executable only (Mac OS X 10.5 and later) */
 #endif /* not POSIX */
 
 #ifdef __cplusplus
index 8584eb936887ac2a95cc3c475bf978e6c3ce2270..1621a5265071ba090f2639a15cadc244574bde1d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2008 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -40,8 +40,8 @@
  *  DYLD_INTERPOSE(my_open, open)
  */
 
-#define DYLD_INTERPOSE(_replacment,_replacee) \
-   __attribute__((used)) static struct{ const void* replacment; const void* replacee; } _interpose_##_replacee \
-            __attribute__ ((section ("__DATA,__interpose"))) = { (const void*)(unsigned long)&_replacment, (const void*)(unsigned long)&_replacee };
+#define DYLD_INTERPOSE(_replacement,_replacee) \
+   __attribute__((used)) static struct{ const void* replacement; const void* replacee; } _interpose_##_replacee \
+            __attribute__ ((section ("__DATA,__interpose"))) = { (const void*)(unsigned long)&_replacement, (const void*)(unsigned long)&_replacee };
 
 #endif
diff --git a/include/mach-o/dyld-update-prebinding.h b/include/mach-o/dyld-update-prebinding.h
deleted file mode 100644 (file)
index 9e09413..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-
-#ifndef _DYLD_UPDATE_PREBINDING_H_
-#define _DYLD_UPDATE_PREBINDING_H_
-
-#define UPDATE_PREBINDING_DRY_RUN              0x00000001
-#define UPDATE_PREBINDING_PROGRESS             0x00000002
-#define UPDATE_PREBINDING_DEBUG                        0x00000004
-#define UPDATE_PREBINDING_FORCE                        0x00000008
-#define UPDATE_PREBINDING_XBUILD_LOG   0x00000010
-#define UPDATE_PREBINDING_SORT                 0x00000020
-
-
-
-typedef void (*update_prebinding_ptr)(int pathCount, const char* paths[], uint32_t flags) __attribute__((noreturn));
-
-
-
-
-#endif
index 10b7099169fe02ee5e2293bc7ccf008f9268995d..0f9828d00f567864d99a26c6f176aba5fd9f7cb4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2008 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -29,7 +29,7 @@
 #include <stdbool.h>
 
 #include <mach-o/loader.h>
-#include <AvailabilityMacros.h>
+#include <Availability.h>
 
 #if __cplusplus
 extern "C" {
@@ -44,10 +44,10 @@ extern "C" {
  * will return the mach_header and name of an image, given an address in 
  * the image. dladdr() is thread safe.
  */
-extern uint32_t                    _dyld_image_count(void)                              AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER;
-extern const struct mach_header*   _dyld_get_image_header(uint32_t image_index)         AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER;
-extern intptr_t                    _dyld_get_image_vmaddr_slide(uint32_t image_index)   AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER;
-extern const char*                 _dyld_get_image_name(uint32_t image_index)           AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER;
+extern uint32_t                    _dyld_image_count(void)                              __OSX_AVAILABLE_STARTING(__MAC_10_1, __IPHONE_2_0);
+extern const struct mach_header*   _dyld_get_image_header(uint32_t image_index)         __OSX_AVAILABLE_STARTING(__MAC_10_1, __IPHONE_2_0);
+extern intptr_t                    _dyld_get_image_vmaddr_slide(uint32_t image_index)   __OSX_AVAILABLE_STARTING(__MAC_10_1, __IPHONE_2_0);
+extern const char*                 _dyld_get_image_name(uint32_t image_index)           __OSX_AVAILABLE_STARTING(__MAC_10_1, __IPHONE_2_0);
 
 
 /*
@@ -58,8 +58,8 @@ extern const char*                 _dyld_get_image_name(uint32_t image_index)
  * _dyld_register_func_for_remove_image() is called after any terminators in an image are run
  * and before the image is un-memory-mapped.
  */
-extern void _dyld_register_func_for_add_image(void (*func)(const struct mach_header* mh, intptr_t vmaddr_slide))    AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER;
-extern void _dyld_register_func_for_remove_image(void (*func)(const struct mach_header* mh, intptr_t vmaddr_slide)) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER;
+extern void _dyld_register_func_for_add_image(void (*func)(const struct mach_header* mh, intptr_t vmaddr_slide))    __OSX_AVAILABLE_STARTING(__MAC_10_1, __IPHONE_2_0);
+extern void _dyld_register_func_for_remove_image(void (*func)(const struct mach_header* mh, intptr_t vmaddr_slide)) __OSX_AVAILABLE_STARTING(__MAC_10_1, __IPHONE_2_0);
 
 
 /*
@@ -67,7 +67,7 @@ extern void _dyld_register_func_for_remove_image(void (*func)(const struct mach_
  * specifed by the libraryName.  The libraryName parameter would be "bar" for /path/libbar.3.dylib and
  * "Foo" for /path/Foo.framework/Versions/A/Foo.  It returns -1 if no such library is loaded.
  */
-extern int32_t NSVersionOfRunTimeLibrary(const char* libraryName)            AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER;
+extern int32_t NSVersionOfRunTimeLibrary(const char* libraryName)            __OSX_AVAILABLE_STARTING(__MAC_10_1, __IPHONE_2_0);
 
 
 /*
@@ -76,7 +76,7 @@ extern int32_t NSVersionOfRunTimeLibrary(const char* libraryName)            AVA
  * "Foo" for /path/Foo.framework/Versions/A/Foo.  It returns -1 if the main executable did not link
  * against the specified library.
  */
-extern int32_t NSVersionOfLinkTimeLibrary(const char* libraryName)           AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER;
+extern int32_t NSVersionOfLinkTimeLibrary(const char* libraryName)           __OSX_AVAILABLE_STARTING(__MAC_10_1, __IPHONE_2_0);
 
 
 /*
@@ -88,7 +88,7 @@ extern int32_t NSVersionOfLinkTimeLibrary(const char* libraryName)           AVA
  * That is the path may be a symbolic link and not the real file. With deep directories the total bufsize 
  * needed could be more than MAXPATHLEN.
  */
-extern int _NSGetExecutablePath(char* buf, uint32_t* bufsize)                AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER;
+extern int _NSGetExecutablePath(char* buf, uint32_t* bufsize)                 __OSX_AVAILABLE_STARTING(__MAC_10_2, __IPHONE_2_0);
 
 
 
@@ -96,8 +96,8 @@ extern int _NSGetExecutablePath(char* buf, uint32_t* bufsize)                AVA
  * _dyld_moninit() and _dyld_func_lookup() are private interface between 
  * dyld and libSystem.
 */
-extern void _dyld_moninit(void (*monaddition)(char *lowpc, char *highpc))    AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER;
-extern int _dyld_func_lookup(const char* dyld_func_name, void **address)     AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER;
+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);
 
 
 
@@ -142,23 +142,23 @@ typedef enum {
 typedef struct __NSObjectFileImage*  NSObjectFileImage;
 
 /* NSObjectFileImage can only be used with MH_BUNDLE files */
-extern NSObjectFileImageReturnCode NSCreateObjectFileImageFromFile(const char* pathName, NSObjectFileImage *objectFileImage)               AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
-extern NSObjectFileImageReturnCode NSCreateObjectFileImageFromMemory(const void *address, size_t size, NSObjectFileImage *objectFileImage) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
-extern bool                        NSDestroyObjectFileImage(NSObjectFileImage objectFileImage)                                             AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
-
-extern uint32_t     NSSymbolDefinitionCountInObjectFileImage(NSObjectFileImage objectFileImage)                   AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
-extern const char*  NSSymbolDefinitionNameInObjectFileImage(NSObjectFileImage objectFileImage, uint32_t ordinal)  AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
-extern uint32_t     NSSymbolReferenceCountInObjectFileImage(NSObjectFileImage objectFileImage)                    AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
-extern const char*  NSSymbolReferenceNameInObjectFileImage(NSObjectFileImage objectFileImage, uint32_t ordinal, bool *tentative_definition) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
-extern bool         NSIsSymbolDefinedInObjectFileImage(NSObjectFileImage objectFileImage, const char* symbolName) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4;
-extern void*        NSGetSectionDataInObjectFileImage(NSObjectFileImage objectFileImage, const char* segmentName, const char* sectionName, size_t *size) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
-extern bool         NSHasModInitObjectFileImage(NSObjectFileImage objectFileImage)                                AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
+extern NSObjectFileImageReturnCode NSCreateObjectFileImageFromFile(const char* pathName, NSObjectFileImage *objectFileImage)               __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
+extern NSObjectFileImageReturnCode NSCreateObjectFileImageFromMemory(const void *address, size_t size, NSObjectFileImage *objectFileImage) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
+extern bool                        NSDestroyObjectFileImage(NSObjectFileImage objectFileImage)                                             __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
+
+extern uint32_t     NSSymbolDefinitionCountInObjectFileImage(NSObjectFileImage objectFileImage)                   __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
+extern const char*  NSSymbolDefinitionNameInObjectFileImage(NSObjectFileImage objectFileImage, uint32_t ordinal)  __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
+extern uint32_t     NSSymbolReferenceCountInObjectFileImage(NSObjectFileImage objectFileImage)                    __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
+extern const char*  NSSymbolReferenceNameInObjectFileImage(NSObjectFileImage objectFileImage, uint32_t ordinal, bool *tentative_definition) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
+extern bool         NSIsSymbolDefinedInObjectFileImage(NSObjectFileImage objectFileImage, const char* symbolName) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_4,__IPHONE_NA,__IPHONE_NA);
+extern void*        NSGetSectionDataInObjectFileImage(NSObjectFileImage objectFileImage, const char* segmentName, const char* sectionName, size_t *size) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
+extern bool         NSHasModInitObjectFileImage(NSObjectFileImage objectFileImage)                                __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
 
 typedef struct __NSModule* NSModule;
-extern const char*  NSNameOfModule(NSModule m)         AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
-extern const char*  NSLibraryNameForModule(NSModule m) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
+extern const char*  NSNameOfModule(NSModule m)         __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
+extern const char*  NSLibraryNameForModule(NSModule m) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
 
-extern NSModule NSLinkModule(NSObjectFileImage objectFileImage, const char* moduleName, uint32_t options) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
+extern NSModule NSLinkModule(NSObjectFileImage objectFileImage, const char* moduleName, uint32_t options) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
 #define NSLINKMODULE_OPTION_NONE                         0x0
 #define NSLINKMODULE_OPTION_BINDNOW                      0x1
 #define NSLINKMODULE_OPTION_PRIVATE                      0x2
@@ -166,27 +166,27 @@ extern NSModule NSLinkModule(NSObjectFileImage objectFileImage, const char* modu
 #define NSLINKMODULE_OPTION_DONT_CALL_MOD_INIT_ROUTINES  0x8
 #define NSLINKMODULE_OPTION_TRAILING_PHYS_NAME          0x10
 
-extern bool NSUnLinkModule(NSModule module, uint32_t options) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
+extern bool NSUnLinkModule(NSModule module, uint32_t options) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
 #define NSUNLINKMODULE_OPTION_NONE                  0x0
 #define NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED    0x1
 #define NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES    0x2
 
 /* symbol API */
 typedef struct __NSSymbol* NSSymbol;
-extern bool     NSIsSymbolNameDefined(const char* symbolName)                                                    AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4;
-extern bool     NSIsSymbolNameDefinedWithHint(const char* symbolName, const char* libraryNameHint)               AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4;
-extern bool     NSIsSymbolNameDefinedInImage(const struct mach_header* image, const char* symbolName)            AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4;
-extern NSSymbol NSLookupAndBindSymbol(const char* symbolName)                                                    AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4;
-extern NSSymbol NSLookupAndBindSymbolWithHint(const char* symbolName, const char* libraryNameHint)               AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4;
-extern NSSymbol NSLookupSymbolInModule(NSModule module, const char* symbolName)                                  AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
-extern NSSymbol NSLookupSymbolInImage(const struct mach_header* image, const char* symbolName, uint32_t options) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
+extern bool     NSIsSymbolNameDefined(const char* symbolName)                                                    __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_4,__IPHONE_NA,__IPHONE_NA);
+extern bool     NSIsSymbolNameDefinedWithHint(const char* symbolName, const char* libraryNameHint)               __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_4,__IPHONE_NA,__IPHONE_NA);
+extern bool     NSIsSymbolNameDefinedInImage(const struct mach_header* image, const char* symbolName)            __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_4,__IPHONE_NA,__IPHONE_NA);
+extern NSSymbol NSLookupAndBindSymbol(const char* symbolName)                                                    __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_4,__IPHONE_NA,__IPHONE_NA);
+extern NSSymbol NSLookupAndBindSymbolWithHint(const char* symbolName, const char* libraryNameHint)               __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_4,__IPHONE_NA,__IPHONE_NA);
+extern NSSymbol NSLookupSymbolInModule(NSModule module, const char* symbolName)                                  __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
+extern NSSymbol NSLookupSymbolInImage(const struct mach_header* image, const char* symbolName, uint32_t options) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
 #define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND            0x0
 #define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW        0x1
 #define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY      0x2
 #define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4
-extern const char*  NSNameOfSymbol(NSSymbol symbol)    AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
-extern void *       NSAddressOfSymbol(NSSymbol symbol) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
-extern NSModule     NSModuleForSymbol(NSSymbol symbol) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
+extern const char*  NSNameOfSymbol(NSSymbol symbol)    __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
+extern void *       NSAddressOfSymbol(NSSymbol symbol) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
+extern NSModule     NSModuleForSymbol(NSSymbol symbol) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
 
 /* error handling API */
 typedef enum {
@@ -214,7 +214,7 @@ typedef enum {
     NSOtherErrorInvalidArgs
 } NSOtherErrorNumbers;
 
-extern void NSLinkEditError(NSLinkEditErrors *c, int *errorNumber, const char** fileName, const char** errorString) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
+extern void NSLinkEditError(NSLinkEditErrors *c, int *errorNumber, const char** fileName, const char** errorString) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
 
 typedef struct {
      void     (*undefined)(const char* symbolName);
@@ -223,28 +223,28 @@ typedef struct {
                           const char* fileName, const char* errorString);
 } NSLinkEditErrorHandlers;
 
-extern void NSInstallLinkEditErrorHandlers(const NSLinkEditErrorHandlers *handlers) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
+extern void NSInstallLinkEditErrorHandlers(const NSLinkEditErrorHandlers *handlers) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
 
-extern bool                      NSAddLibrary(const char* pathName)                   AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4;
-extern bool                      NSAddLibraryWithSearching(const char* pathName)      AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4;
-extern const struct mach_header* NSAddImage(const char* image_name, uint32_t options) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
+extern bool                      NSAddLibrary(const char* pathName)                   __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_4,__IPHONE_NA,__IPHONE_NA);
+extern bool                      NSAddLibraryWithSearching(const char* pathName)      __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_4,__IPHONE_NA,__IPHONE_NA);
+extern const struct mach_header* NSAddImage(const char* image_name, uint32_t options) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
 #define NSADDIMAGE_OPTION_NONE                         0x0
 #define NSADDIMAGE_OPTION_RETURN_ON_ERROR              0x1
 #define NSADDIMAGE_OPTION_WITH_SEARCHING               0x2
 #define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED        0x4
 #define NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME        0x8
 
-extern bool _dyld_present(void)                                                              AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
-extern bool _dyld_launched_prebound(void)                                                    AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
-extern bool _dyld_all_twolevel_modules_prebound(void)                                        AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
-extern void _dyld_bind_objc_module(const void* objc_module)                                  AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
-extern bool _dyld_bind_fully_image_containing_address(const void* address)                   AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
-extern bool _dyld_image_containing_address(const void* address)                              AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
-extern void _dyld_lookup_and_bind(const char* symbol_name, void **address, NSModule* module) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4;
-extern void _dyld_lookup_and_bind_with_hint(const char* symbol_name, const char* library_name_hint, void** address, NSModule* module) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4;
-extern void _dyld_lookup_and_bind_fully(const char* symbol_name, void** address, NSModule* module) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
-
-extern const struct mach_header*  _dyld_get_image_header_containing_address(const void* address) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
+extern bool _dyld_present(void)                                                              __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
+extern bool _dyld_launched_prebound(void)                                                    __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
+extern bool _dyld_all_twolevel_modules_prebound(void)                                        __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
+extern void _dyld_bind_objc_module(const void* objc_module)                                  __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
+extern bool _dyld_bind_fully_image_containing_address(const void* address)                   __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
+extern bool _dyld_image_containing_address(const void* address)                              __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
+extern void _dyld_lookup_and_bind(const char* symbol_name, void **address, NSModule* module) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_4,__IPHONE_NA,__IPHONE_NA);
+extern void _dyld_lookup_and_bind_with_hint(const char* symbol_name, const char* library_name_hint, void** address, NSModule* module) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_4,__IPHONE_NA,__IPHONE_NA);
+extern void _dyld_lookup_and_bind_fully(const char* symbol_name, void** address, NSModule* module) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
+
+extern const struct mach_header*  _dyld_get_image_header_containing_address(const void* address) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3,__MAC_10_5,__IPHONE_NA,__IPHONE_NA);
 
 
 #if __cplusplus
index 1f7b96b87a0e830781e9439954988bceececa51e..8423f2f97075cab2c6a375ed3be18382e7ad4124 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@
  * 
@@ -23,6 +23,9 @@
 #ifndef _DYLD_IMAGES_
 #define _DYLD_IMAGES_
 
+#include <stdbool.h>
+#include <mach/mach.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -43,6 +46,15 @@ extern "C" {
  * The notification is called after infoArray is updated.  This means that if gdb attaches to a process
  * and infoArray is NULL, gdb can set a break point on notification and let the proccess continue to
  * run until the break point.  Then gdb can inspect the full infoArray.
+ *
+ * The dyldVersion field always points to a C string that contains the dyld version.  For instance,
+ * in dyld-127.3, dyldVersion would contain a pointer to "127.3".
+ *
+ * The errorMessage and terminationFlags fields are normally zero.  If dyld terminates a process
+ * (for instance because a required dylib or symbol is missing), then the errorMessage field will
+ * 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.
  */
 
 enum dyld_image_mode { dyld_image_adding=0, dyld_image_removing=1 };
@@ -58,15 +70,36 @@ struct dyld_image_info {
 typedef void (*dyld_image_notifier)(enum dyld_image_mode mode, uint32_t infoCount, const struct dyld_image_info info[]);
 
 struct dyld_all_image_infos {
-       uint32_t                                                version;                /* == 1 in Mac OS X 10.4 */
+       uint32_t                                                version;                /* 1 in Mac OS X 10.4 and 10.5 */
        uint32_t                                                infoArrayCount;
        const struct dyld_image_info*   infoArray;
        dyld_image_notifier                             notification;           
        bool                                                    processDetachedFromSharedRegion;
+       /* 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 */
+       void*                                                   jitInfo;
+       /* the following fields are only in version 5 (Mac OS X 10.6) 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 */
+       void*                                                   coreSymbolicationShmPage;
+       /* the following field is only in version 7 (Mac OS X 10.6) and later */
+       uintptr_t                                               systemOrderFlag;
 };
 extern struct dyld_all_image_infos  dyld_all_image_infos;
 
 
+/*
+ * Beginning in Mac OS X 10.6, rather than looking up the symbol "_dyld_all_image_infos"
+ * in dyld's symbol table, you can add DYLD_ALL_IMAGE_INFOS_OFFSET_OFFSET to the mach_header
+ * for dyld and read the 32-bit unsigned int at that location.  Adding that value to dyld's
+ * mach_header address gets you the address of dyld_all_image_infos in dyld.
+ */
+#define DYLD_ALL_IMAGE_INFOS_OFFSET_OFFSET 0x1010
+
 
 
 /*
index 8d327f4cb6b049fcabf01da4c3df2aa09cb7a604..07ef16135dc382f0cafb4e6d3a7d0f215bb0334b 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2003-2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -33,26 +33,6 @@ extern "C" {
 #endif /* __cplusplus */
 
 
-/*
- * Given an imageOffset into an ObjectFileImage, returns 
- * the segment/section name and offset into that section of
- * that imageOffset.  Returns FALSE if the imageOffset is not 
- * in any section.  You can used the resulting sectionOffset to
- * index into the data returned by NSGetSectionDataInObjectFileImage.
- * 
- * First appeared in Mac OS X 10.3 
- *
- * SPI: currently only used by ZeroLink to detect +load methods
- */
-bool 
-NSFindSectionAndOffsetInObjectFileImage(
-    NSObjectFileImage objectFileImage, 
-    unsigned long imageOffset,
-    const char** segmentName,  /* can be NULL */
-    const char** sectionName,  /* can be NULL */
-    unsigned long* sectionOffset);     /* can be NULL */
-
-
 //
 // Possible state changes for which you can register to be notified
 //
@@ -64,7 +44,7 @@ enum dyld_image_states
        dyld_image_state_bound                                  = 40,
        dyld_image_state_dependents_initialized = 45,           // Only single notification for this
        dyld_image_state_initialized                    = 50,
-       dyld_image_state_terminated                             = 60            // FIX ME - only called if image has termination routine
+       dyld_image_state_terminated                             = 60            // Only single notification for this
 };
 
 // 
@@ -89,15 +69,51 @@ dyld_register_image_state_change_handler(enum dyld_image_states state, bool batc
 
 
 //
+// get slide for a given loaded mach_header  
+// Mac OS X 10.6 and later
 //
+extern intptr_t _dyld_get_image_slide(const struct mach_header* mh);
+
+
 //
-extern void
-_dyld_library_locator(const char* (*handler)(const char*));
+// get pointer to this process's dyld_all_image_infos
+// Exists in Mac OS X 10.4 and later through _dyld_func_lookup()
+// Exists in Mac OS X 10.6 and later through libSystem.dylib
+//
+const struct dyld_all_image_infos* _dyld_get_all_image_infos();
+
+
+
+struct dyld_unwind_sections
+{
+       const struct mach_header*               mh;
+       const void*                                             dwarf_section;
+       uintptr_t                                               dwarf_section_length;
+       const void*                                             compact_unwind_section;
+       uintptr_t                                               compact_unwind_section_length;
+};
+
+
+//
+// Returns true iff some loaded mach-o image contains "addr".
+//     info->mh                                                        mach header of image containing addr
+//  info->dwarf_section                                        pointer to start of __TEXT/__eh_frame section
+//  info->dwarf_section_length                 length of __TEXT/__eh_frame section
+//  info->compact_unwind_section               pointer to start of __TEXT/__unwind_info section
+//  info->compact_unwind_section_length        length of __TEXT/__unwind_info section
+//
+// Exists in Mac OS X 10.6 and later 
+extern bool _dyld_find_unwind_sections(void* addr, struct dyld_unwind_sections* info);
+
+
+//
+// This is an optimized form of dladdr() that only returns the dli_fname field.
+//
+// Exists in Mac OS X 10.6 and later 
+extern const char* dyld_image_path_containing_address(const void* addr);
 
-extern void* dlord(void* handle, uint32_t ordinal); /* Mac OS X 10.5 and later */
 
 
-#define        RTLD_MAIN_ONLY          ((void *) -5)   /* Search main executable only (Mac OS X 10.5 and later) */
 
 
 
index e735f9e2ed0927d4ebb3fa06f8fa621ce1d83429..05d64306f8a7fe3a033fb4ec7b5665dd9084b1dc 100644 (file)
@@ -35,41 +35,24 @@ struct ppc
 {
        typedef Pointer32<BigEndian>            P;
        
-       enum ReferenceKinds {  kNoFixUp, kFollowOn, kPointer, kPointerWeakImport, kPointerDiff32, kPointerDiff64,
-                                                       kBranch24, kBranch24WeakImport, kBranch14,
-                                                       kPICBaseLow16, kPICBaseLow14, kPICBaseHigh16, 
-                                                       kAbsLow16, kAbsLow14, kAbsHigh16, kAbsHigh16AddLow };
-};
-
-struct ppc64
-{
-       typedef Pointer64<BigEndian>            P;
-       
-       enum ReferenceKinds {  kNoFixUp, kFollowOn, kPointer, kPointerWeakImport, kPointerDiff32, kPointerDiff64,
-                                                       kBranch24, kBranch24WeakImport, kBranch14,
-                                                       kPICBaseLow16, kPICBaseLow14, kPICBaseHigh16, 
-                                                       kAbsLow16, kAbsLow14, kAbsHigh16, kAbsHigh16AddLow };
 };
 
 struct x86
 {
        typedef Pointer32<LittleEndian>         P;
        
-       enum ReferenceKinds {  kNoFixUp, kFollowOn, kPointer, kPointerWeakImport, kPointerDiff, 
-                                                       kPCRel32, kPCRel32WeakImport, kAbsolute32 };
 };
 
 struct x86_64
 {
        typedef Pointer64<LittleEndian>         P;
-       
-       enum ReferenceKinds {  kNoFixUp, kFollowOn, kPointer, kPointerWeakImport, kPointerDiff, kPointerDiff32, 
-                                                       kPCRel32, kPCRel32_1, kPCRel32_2, kPCRel32_4,
-                                                       kBranchPCRel32, kBranchPCRel32WeakImport,
-                                                       kPCRel32GOTLoad, kPCRel32GOTLoadWeakImport,
-                                                       kPCRel32GOT, kPCRel32GOTWeakImport };
 };
 
+struct arm
+{
+       typedef Pointer32<LittleEndian>         P;
+       
+};
 
 
 
index 1f7a6295e19b002bc3c34ed14805a5bc9c564708..8d75311c16d56e01b400c1dffb10a1759cc1f3f4 100644 (file)
@@ -63,6 +63,9 @@ public:
        
        static uint32_t get32(const uint32_t& from)                             INLINE { return OSReadBigInt32(&from, 0); }
        static void             set32(uint32_t& into, uint32_t value)   INLINE { OSWriteBigInt32(&into, 0, value); }
+
+       static int32_t  get32(const int32_t& from)                              INLINE { return OSReadBigInt32(&from, 0); }
+       static void             set32(int32_t& into, int32_t value)             INLINE { OSWriteBigInt32(&into, 0, value); }
        
        static uint64_t get64(const uint64_t& from)                             INLINE { return OSReadBigInt64(&from, 0); }
        static void             set64(uint64_t& into, uint64_t value)   INLINE { OSWriteBigInt64(&into, 0, value); }
@@ -93,6 +96,9 @@ public:
        static uint32_t get32(const uint32_t& from)                             INLINE { return OSReadLittleInt32(&from, 0); }
        static void             set32(uint32_t& into, uint32_t value)   INLINE { OSWriteLittleInt32(&into, 0, value); }
        
+       static int32_t  get32(const int32_t& from)                              INLINE { return OSReadLittleInt32(&from, 0); }
+       static void             set32(int32_t& into, int32_t value)             INLINE { OSWriteLittleInt32(&into, 0, value); }
+       
        static uint64_t get64(const uint64_t& from)                             INLINE { return OSReadLittleInt64(&from, 0); }
        static void             set64(uint64_t& into, uint64_t value)   INLINE { OSWriteLittleInt64(&into, 0, value); }
 
index 6bde8cd8f6b0c6525825497061c98c64ad6d8edf..5b99dbf7827eeb368d14d809640c57cf9346b8ea 100644 (file)
@@ -45,6 +45,7 @@
 #include "Architectures.hpp"
 #include "MachOLayout.hpp"
 #include "MachORebaser.hpp"
+#include "MachOTrie.hpp"
 
 
 
@@ -71,14 +72,18 @@ private:
        typedef typename A::P::E                                E;
        typedef typename A::P::uint_t                   pint_t;
        struct BinderAndReExportFlag { Binder<A>* binder; bool reExport; };
-       typedef __gnu_cxx::hash_map<const char*, const macho_nlist<P>*, __gnu_cxx::hash<const char*>, CStringEquals> NameToSymbolMap;
+       typedef __gnu_cxx::hash_map<const char*, pint_t, __gnu_cxx::hash<const char*>, CStringEquals> NameToAddrMap;
        
        void                                                                            doBindExternalRelocations();
        void                                                                            doBindIndirectSymbols();
        void                                                                            doSetUpDyldSection();
        void                                                                            doSetPreboundUndefines();
+       void                                                                            doBindDyldInfo();
+       void                                                                            doBindDyldLazyInfo();
+       void                                                                            bindDyldInfoAt(uint8_t segmentIndex, uint64_t segmentOffset, uint8_t type, 
+                                                                                                                               int libraryOrdinal, int64_t addend, const char* symbolName);
        pint_t                                                                          resolveUndefined(const macho_nlist<P>* undefinedSymbol);
-       const macho_nlist<P>*                                           findExportedSymbol(const char* name);
+       bool                                                                            findExportedSymbolAddress(const char* name, pint_t* result);
        void                                                                            bindStub(uint8_t elementSize, uint8_t* location, pint_t vmlocation, pint_t value);
        const char*                                                                     parentUmbrella();
 
@@ -86,7 +91,7 @@ private:
        static uint8_t                                                          pointerRelocType();
        
        std::vector<BinderAndReExportFlag>                      fDependentDylibs;
-       NameToSymbolMap                                                         fHashTable;
+       NameToAddrMap                                                           fHashTable;
        uint64_t                                                                        fDyldBaseAddress;
        const macho_nlist<P>*                                           fSymbolTable;
        const char*                                                                     fStrings;
@@ -94,6 +99,7 @@ private:
        const macho_segment_command<P>*                         fFristWritableSegment;
        const macho_dylib_command<P>*                           fDylibID;
        const macho_dylib_command<P>*                           fParentUmbrella;
+       const macho_dyld_info_command<P>*                       fDyldInfo;
        bool                                                                            fOriginallyPrebound;
 };
 
@@ -102,7 +108,7 @@ 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),
+         fFristWritableSegment(NULL), fDylibID(NULL), fDyldInfo(NULL),
          fParentUmbrella(NULL)
 {
        fOriginallyPrebound = ((this->fHeader->flags() & MH_PREBOUND) != 0);
@@ -136,9 +142,16 @@ Binder<A>::Binder(const MachOLayoutAbstraction& layout, uint64_t dyldBaseAddress
                        case LC_SUB_FRAMEWORK:
                                fParentUmbrella = (macho_dylib_command<P>*)cmd;
                                break;
+                       case LC_DYLD_INFO:
+                       case LC_DYLD_INFO_ONLY:
+                               fDyldInfo = (macho_dyld_info_command<P>*)cmd;
+                               break;
+                       case LC_RPATH:
+                               throwf("LC_RPATH not supported in dylibs in dyld shared cache");
+                               break;
                        default:
                                if ( cmd->cmd() & LC_REQ_DYLD )
-                                       throwf("unknown required load command %d", cmd->cmd());
+                                       throwf("unknown required load command 0x%08X", cmd->cmd());
                }
                cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
        }       
@@ -147,38 +160,53 @@ Binder<A>::Binder(const MachOLayoutAbstraction& layout, uint64_t dyldBaseAddress
        if ( fSymbolTable == NULL )     
                throw "no LC_SYMTAB";
        // build hash table
-       if ( fDynamicInfo->tocoff() == 0 ) {
-               const macho_nlist<P>* start = &fSymbolTable[fDynamicInfo->iextdefsym()];
-               const macho_nlist<P>* end = &start[fDynamicInfo->nextdefsym()];
-               fHashTable.resize(fDynamicInfo->nextdefsym()); // set initial bucket count
-               for (const macho_nlist<P>* sym=start; sym < end; ++sym) {
-                       const char* name = &fStrings[sym->n_strx()];
-                       fHashTable[name] = sym;
+//     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* 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;
+                       //fprintf(stderr, "0x%08llX %s\n", it->address + baseAddress, it->name);
                }
        }
        else {
-               int32_t count = fDynamicInfo->ntoc();
-               fHashTable.resize(count); // set initial bucket count
-               const struct dylib_table_of_contents* toc = (dylib_table_of_contents*)&this->fLinkEditBase[fDynamicInfo->tocoff()];
-               for (int32_t i = 0; i < count; ++i) {
-                       const uint32_t index = E::get32(toc[i].symbol_index);
-                       const macho_nlist<P>* sym = &fSymbolTable[index];
-                       const char* name = &fStrings[sym->n_strx()];
-                       fHashTable[name] = sym;
+               if ( fDynamicInfo->tocoff() == 0 ) {
+                       const macho_nlist<P>* start = &fSymbolTable[fDynamicInfo->iextdefsym()];
+                       const macho_nlist<P>* end = &start[fDynamicInfo->nextdefsym()];
+                       fHashTable.resize(fDynamicInfo->nextdefsym()); // set initial bucket count
+                       for (const macho_nlist<P>* sym=start; sym < end; ++sym) {
+                               const char* name = &fStrings[sym->n_strx()];
+                               fHashTable[name] = sym->n_value();
+                               //fprintf(stderr, " 0x%08llX %s\n", sym->n_value(), name);
+                       }
+               }
+               else {
+                       int32_t count = fDynamicInfo->ntoc();
+                       fHashTable.resize(count); // set initial bucket count
+                       const struct dylib_table_of_contents* toc = (dylib_table_of_contents*)&this->fLinkEditBase[fDynamicInfo->tocoff()];
+                       for (int32_t i = 0; i < count; ++i) {
+                               const uint32_t index = E::get32(toc[i].symbol_index);
+                               const macho_nlist<P>* sym = &fSymbolTable[index];
+                               const char* name = &fStrings[sym->n_strx()];
+                               fHashTable[name] = sym->n_value();
+                               //fprintf(stderr, "- 0x%08llX %s\n", sym->n_value(), name);
+                       }
                }
        }
-
 }
 
 template <> uint8_t    Binder<ppc>::pointerRelocSize()    { return 2; }
-template <> uint8_t    Binder<ppc64>::pointerRelocSize()  { return 3; }
 template <> uint8_t    Binder<x86>::pointerRelocSize()   { return 2; }
 template <> uint8_t    Binder<x86_64>::pointerRelocSize() { return 3; }
+template <> uint8_t    Binder<arm>::pointerRelocSize() { return 2; }
 
 template <> uint8_t    Binder<ppc>::pointerRelocType()    { return GENERIC_RELOC_VANILLA; }
-template <> uint8_t    Binder<ppc64>::pointerRelocType()  { return GENERIC_RELOC_VANILLA; }
 template <> uint8_t    Binder<x86>::pointerRelocType()   { return GENERIC_RELOC_VANILLA; }
 template <> uint8_t    Binder<x86_64>::pointerRelocType() { return X86_64_RELOC_UNSIGNED; }
+template <> uint8_t    Binder<arm>::pointerRelocType() { return ARM_RELOC_VANILLA; }
 
 
 template <typename A>
@@ -312,9 +340,16 @@ template <typename A>
 void Binder<A>::bind()
 {
        this->doSetUpDyldSection();
-       this->doBindExternalRelocations();
-       this->doBindIndirectSymbols();
-       this->doSetPreboundUndefines();
+       if ( fDyldInfo != NULL ) {
+               this->doBindDyldInfo();
+               this->doBindDyldLazyInfo();
+               // weak bind info is processed at launch time
+       }
+       else {
+               this->doBindExternalRelocations();
+               this->doBindIndirectSymbols();
+               this->doSetPreboundUndefines();
+       }
 }
 
 
@@ -346,6 +381,213 @@ 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)
+{
+       //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();
+       if ( segmentIndex > segments.size() )
+               throw "bad segment index in rebase info";
+               
+       if ( libraryOrdinal == BIND_SPECIAL_DYLIB_FLAT_LOOKUP ) 
+               throw "flat_namespace linkage not allowed in dyld shared cache";
+       
+       if ( libraryOrdinal == BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE ) 
+               throw "linkage to main executable not allowed in dyld shared cache";
+       
+       if ( libraryOrdinal < 0 ) 
+               throw "bad mach-o binary, special library ordinal not allowd in dyld shared cache";
+       
+       if ( (unsigned)libraryOrdinal > fDependentDylibs.size() ) 
+               throw "bad mach-o binary, library ordinal too big";
+       
+       Binder<A>* binder;
+       if ( libraryOrdinal == BIND_SPECIAL_DYLIB_SELF ) 
+               binder = this;
+       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());
+
+       // do actual update
+       const MachOLayoutAbstraction::Segment& seg = segments[segmentIndex];
+       uint8_t*  mappedAddr = (uint8_t*)seg.mappedAddress() + segmentOffset;
+       pint_t*   mappedAddrP = (pint_t*)mappedAddr;
+       uint32_t* mappedAddr32 = (uint32_t*)mappedAddr;
+       int32_t svalue32new;
+       switch ( type ) {
+               case BIND_TYPE_POINTER:
+                       P::setP(*mappedAddrP, targetSymbolAddress + addend);
+                       break;
+               
+               case BIND_TYPE_TEXT_ABSOLUTE32:
+                       E::set32(*mappedAddr32, targetSymbolAddress + addend);
+                       break;
+                       
+               case BIND_TYPE_TEXT_PCREL32:
+                       svalue32new = seg.address() + segmentOffset + 4 - (targetSymbolAddress + addend);
+                       E::set32(*mappedAddr32, svalue32new);
+                       break;
+               
+               default:
+                       throw "bad bind type";
+       }
+}
+
+
+
+template <typename A>
+void Binder<A>::doBindDyldLazyInfo()
+{
+       const uint8_t* p = &this->fLinkEditBase[fDyldInfo->lazy_bind_off()];
+       const uint8_t* end = &p[fDyldInfo->lazy_bind_size()];
+       
+       uint8_t type = BIND_TYPE_POINTER;
+       uint64_t segmentOffset = 0;
+       uint8_t segmentIndex = 0;
+       const char* symbolName = NULL;
+       int libraryOrdinal = 0;
+       int64_t addend = 0;
+       while ( p < end ) {
+               uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
+               uint8_t opcode = *p & BIND_OPCODE_MASK;
+               ++p;
+               switch (opcode) {
+                       case BIND_OPCODE_DONE:
+                               // this opcode marks the end of each lazy pointer binding
+                               break;
+                       case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+                               libraryOrdinal = immediate;
+                               break;
+                       case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+                               libraryOrdinal = read_uleb128(p, end);
+                               break;
+                       case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+                               // the special ordinals are negative numbers
+                               if ( immediate == 0 )
+                                       libraryOrdinal = 0;
+                               else {
+                                       int8_t signExtended = BIND_OPCODE_MASK | immediate;
+                                       libraryOrdinal = signExtended;
+                               }
+                               break;
+                       case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+                               symbolName = (char*)p;
+                               while (*p != '\0')
+                                       ++p;
+                               ++p;
+                               break;
+                       case BIND_OPCODE_SET_ADDEND_SLEB:
+                               addend = read_sleb128(p, end);
+                               break;
+                       case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+                               segmentIndex = immediate;
+                               segmentOffset = read_uleb128(p, end);
+                               break;
+                       case BIND_OPCODE_DO_BIND:
+                               bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName);
+                               segmentOffset += sizeof(pint_t);
+                               break;
+                       case BIND_OPCODE_SET_TYPE_IMM:
+                       case BIND_OPCODE_ADD_ADDR_ULEB:
+                       case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+                       case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+                       case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
+                       default:
+                               throwf("bad lazy bind opcode %d", *p);
+               }
+       }       
+       
+
+}
+
+template <typename A>
+void Binder<A>::doBindDyldInfo()
+{
+       const uint8_t* p = &this->fLinkEditBase[fDyldInfo->bind_off()];
+       const uint8_t* end = &p[fDyldInfo->bind_size()];
+       
+       uint8_t type = 0;
+       uint64_t segmentOffset = 0;
+       uint8_t segmentIndex = 0;
+       const char* symbolName = NULL;
+       int libraryOrdinal = 0;
+       int64_t addend = 0;
+       uint32_t count;
+       uint32_t skip;
+       bool done = false;
+       while ( !done && (p < end) ) {
+               uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
+               uint8_t opcode = *p & BIND_OPCODE_MASK;
+               ++p;
+               switch (opcode) {
+                       case BIND_OPCODE_DONE:
+                               done = true;
+                               break;
+                       case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+                               libraryOrdinal = immediate;
+                               break;
+                       case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+                               libraryOrdinal = read_uleb128(p, end);
+                               break;
+                       case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+                               // the special ordinals are negative numbers
+                               if ( immediate == 0 )
+                                       libraryOrdinal = 0;
+                               else {
+                                       int8_t signExtended = BIND_OPCODE_MASK | immediate;
+                                       libraryOrdinal = signExtended;
+                               }
+                               break;
+                       case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+                               symbolName = (char*)p;
+                               while (*p != '\0')
+                                       ++p;
+                               ++p;
+                               break;
+                       case BIND_OPCODE_SET_TYPE_IMM:
+                               type = immediate;
+                               break;
+                       case BIND_OPCODE_SET_ADDEND_SLEB:
+                               addend = read_sleb128(p, end);
+                               break;
+                       case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+                               segmentIndex = immediate;
+                               segmentOffset = read_uleb128(p, end);
+                               break;
+                       case BIND_OPCODE_ADD_ADDR_ULEB:
+                               segmentOffset += read_uleb128(p, end);
+                               break;
+                       case BIND_OPCODE_DO_BIND:
+                               bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName);
+                               segmentOffset += sizeof(pint_t);
+                               break;
+                       case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+                               bindDyldInfoAt(segmentIndex, segmentOffset, type, libraryOrdinal, addend, symbolName);
+                               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);
+                               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);
+                                       segmentOffset += skip + sizeof(pint_t);
+                               }
+                               break;
+                       default:
+                               throwf("bad bind opcode %d", *p);
+               }
+       }       
+
+       
+
+}
+
 
 template <typename A>
 void Binder<A>::doSetPreboundUndefines()
@@ -376,9 +618,9 @@ void Binder<A>::doSetPreboundUndefines()
        macho_nlist<P>* const lastUndefine = &symbolTable[dysymtab->iundefsym()+dysymtab->nundefsym()];
        for (macho_nlist<P>* entry = &symbolTable[dysymtab->iundefsym()]; entry < lastUndefine; ++entry) {
                if ( entry->n_type() & N_EXT ) {
-                       pint_t pbaddr = this->resolveUndefined(entry);
                        //fprintf(stderr, "doSetPreboundUndefines: r_sym=%s, pbaddr=0x%08X, in %s\n", 
                        //      &fStrings[entry->n_strx()], pbaddr, this->getDylibID());
+                       pint_t pbaddr = this->resolveUndefined(entry);
                        entry->set_n_value(pbaddr);
                }
        }
@@ -469,6 +711,7 @@ void Binder<A>::doBindIndirectSymbols()
        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;
+       //fprintf(stderr, "doBindIndirectSymbols() %s\n", this->fLayout.getFilePath());
        for (uint32_t i = 0; i < cmd_count; ++i) {
                if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
                        const macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
@@ -501,6 +744,7 @@ void Binder<A>::doBindIndirectSymbols()
                                                                break;
                                                        default:
                                                                const macho_nlist<P>* undefinedSymbol = &fSymbolTable[symbolIndex];
+                                                               //fprintf(stderr, " sect=%s, index=%d, symbolIndex=%d, sym=%s\n", sect->sectname(), j, symbolIndex, &fStrings[undefinedSymbol->n_strx()]);
                                                                pint_t symbolAddr = this->resolveUndefined(undefinedSymbol);
                                                                switch ( sectionType ) {
                                                                        case S_NON_LAZY_SYMBOL_POINTERS:
@@ -557,31 +801,32 @@ typename A::P::uint_t Binder<A>::resolveUndefined(const macho_nlist<P>* undefine
                                        throw "two-level ordinal out of range";
                                binder = fDependentDylibs[ordinal-1].binder;
                }       
-               const macho_nlist<P>* sym = binder->findExportedSymbol(symbolName);
-               if ( sym == NULL ) 
-                       throwf("could not resolve %s from %s", symbolName, this->getDylibID());
-               return sym->n_value();
+               pint_t addr;
+               if ( ! binder->findExportedSymbolAddress(symbolName, &addr) )
+                       throwf("could not resolve %s expected in %s", symbolName, binder->getDylibID());
+               return addr;
        }
 }
 
 template <typename A>
-const macho_nlist<typename A::P>* Binder<A>::findExportedSymbol(const char* name)
+bool Binder<A>::findExportedSymbolAddress(const char* name, pint_t* result)
 {
-       //fprintf(stderr, "findExportedSymbol(%s) in %s\n", name, this->getDylibID());
-       const macho_nlist<P>* sym = NULL;
-       typename NameToSymbolMap::iterator pos = fHashTable.find(name);
-       if ( pos != fHashTable.end() ) 
-               return pos->second;
+       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());
+               return true;
+       }
 
        // search re-exports
        for (typename std::vector<BinderAndReExportFlag>::iterator it = fDependentDylibs.begin(); it != fDependentDylibs.end(); ++it) {
                if ( it->reExport ) {
-                       sym = it->binder->findExportedSymbol(name);
-                       if ( sym != NULL )
-                               return sym;
+                       if ( it->binder->findExportedSymbolAddress(name, result) )
+                               return true;
                }
        }
-       return NULL;
+       //fprintf(stderr, "findExportedSymbolAddress(%s) => not found in %s\n", name, this->getDylibID());
+       return false;
 }
 
 
index dadec7b716543c437db8971f33ee97c84662cfbf..cba7f8a591a8c99254d70379c6f9c7ca29451a43 100644 (file)
@@ -43,59 +43,30 @@ struct uuid_command {
        #define S_16BYTE_LITERALS 0xE
 #endif
 
+
 #include "FileAbstraction.hpp"
 #include "Architectures.hpp"
 
+// utility to pair together a cpu-type and cpu-sub-type
+struct ArchPair
+{
+       uint32_t        arch;
+       uint32_t        subtype;
+       
+       ArchPair(uint32_t cputype, uint32_t cpusubtype) : arch(cputype), subtype(cpusubtype) {}
+       
+       bool operator<(const ArchPair& other) const { 
+               if ( this->arch != other.arch )
+                       return (this->arch < other.arch);
+               return (this->subtype < other.subtype);
+       }
+};
 
 
 //
 // This abstraction layer makes every mach-o file look like a 64-bit mach-o file with native endianness
 //
 
-
-
-//
-// mach-o file header
-//
-template <typename P> struct macho_header_content {};
-template <> struct macho_header_content<Pointer32<BigEndian> >    { mach_header                fields; };
-template <> struct macho_header_content<Pointer64<BigEndian> >   { mach_header_64      fields; };
-template <> struct macho_header_content<Pointer32<LittleEndian> > { mach_header                fields; };
-template <> struct macho_header_content<Pointer64<LittleEndian> > { mach_header_64     fields; };
-
-template <typename P>
-class macho_header {
-public:
-       uint32_t                magic() const                                   INLINE { return E::get32(header.fields.magic); }
-       void                    set_magic(uint32_t value)               INLINE { E::set32(header.fields.magic, value); }
-
-       uint32_t                cputype() const                                 INLINE { return E::get32(header.fields.cputype); }
-       void                    set_cputype(uint32_t value)             INLINE { E::set32((uint32_t&)header.fields.cputype, value); }
-
-       uint32_t                cpusubtype() const                              INLINE { return E::get32(header.fields.cpusubtype); }
-       void                    set_cpusubtype(uint32_t value)  INLINE { E::set32((uint32_t&)header.fields.cpusubtype, value); }
-
-       uint32_t                filetype() const                                INLINE { return E::get32(header.fields.filetype); }
-       void                    set_filetype(uint32_t value)    INLINE { E::set32(header.fields.filetype, value); }
-
-       uint32_t                ncmds() const                                   INLINE { return E::get32(header.fields.ncmds); }
-       void                    set_ncmds(uint32_t value)               INLINE { E::set32(header.fields.ncmds, value); }
-
-       uint32_t                sizeofcmds() const                              INLINE { return E::get32(header.fields.sizeofcmds); }
-       void                    set_sizeofcmds(uint32_t value)  INLINE { E::set32(header.fields.sizeofcmds, value); }
-
-       uint32_t                flags() const                                   INLINE { return E::get32(header.fields.flags); }
-       void                    set_flags(uint32_t value)               INLINE { E::set32(header.fields.flags, value); }
-
-       uint32_t                reserved() const                                INLINE { return E::get32(header.fields.reserved); }
-       void                    set_reserved(uint32_t value)    INLINE { E::set32(header.fields.reserved, value); }
-
-       typedef typename P::E           E;
-private:
-       macho_header_content<P> header;
-};
-
-
 //
 // mach-o load command
 //
@@ -729,10 +700,174 @@ private:
 };
 
 
+//
+// mach-o file header
+//
+template <typename P> struct macho_header_content {};
+template <> struct macho_header_content<Pointer32<BigEndian> >    { mach_header                fields; };
+template <> struct macho_header_content<Pointer64<BigEndian> >   { mach_header_64      fields; };
+template <> struct macho_header_content<Pointer32<LittleEndian> > { mach_header                fields; };
+template <> struct macho_header_content<Pointer64<LittleEndian> > { mach_header_64     fields; };
 
+template <typename P>
+class macho_header {
+public:
+       uint32_t                magic() const                                   INLINE { return E::get32(header.fields.magic); }
+       void                    set_magic(uint32_t value)               INLINE { E::set32(header.fields.magic, value); }
+
+       uint32_t                cputype() const                                 INLINE { return E::get32(header.fields.cputype); }
+       void                    set_cputype(uint32_t value)             INLINE { E::set32((uint32_t&)header.fields.cputype, value); }
+
+       uint32_t                cpusubtype() const                              INLINE { return E::get32(header.fields.cpusubtype); }
+       void                    set_cpusubtype(uint32_t value)  INLINE { E::set32((uint32_t&)header.fields.cpusubtype, value); }
+
+       uint32_t                filetype() const                                INLINE { return E::get32(header.fields.filetype); }
+       void                    set_filetype(uint32_t value)    INLINE { E::set32(header.fields.filetype, value); }
+
+       uint32_t                ncmds() const                                   INLINE { return E::get32(header.fields.ncmds); }
+       void                    set_ncmds(uint32_t value)               INLINE { E::set32(header.fields.ncmds, value); }
+
+       uint32_t                sizeofcmds() const                              INLINE { return E::get32(header.fields.sizeofcmds); }
+       void                    set_sizeofcmds(uint32_t value)  INLINE { E::set32(header.fields.sizeofcmds, value); }
+
+       uint32_t                flags() const                                   INLINE { return E::get32(header.fields.flags); }
+       void                    set_flags(uint32_t value)               INLINE { E::set32(header.fields.flags, value); }
+
+       uint32_t                reserved() const                                INLINE { return E::get32(header.fields.reserved); }
+       void                    set_reserved(uint32_t value)    INLINE { E::set32(header.fields.reserved, value); }
+
+    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>* 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;
+                if (0 == strncmp(segname, segcmd->segname(), 16)) {
+                    return segcmd;
+                }
+            }
+            cmd = (const 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);
+        if (!segcmd) return NULL;
+
+        const macho_section<P>* sectcmd = (macho_section<P>*)(segcmd+1);
+        const 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;
+            }
+        }
+
+        return NULL;
+    }
+
+       typedef typename P::E           E;
+private:
+       macho_header_content<P> header;
+};
 
 
 
+//
+// compressed dyld info load command
+//
+template <typename P>
+class macho_dyld_info_command {
+public:
+       uint32_t                cmd() const                                     INLINE { return E::get32(fields.cmd); }
+       void                    set_cmd(uint32_t value)         INLINE { E::set32(fields.cmd, value); }
+
+       uint32_t                cmdsize() const                         INLINE { return E::get32(fields.cmdsize); }
+       void                    set_cmdsize(uint32_t value)     INLINE { E::set32(fields.cmdsize, value); }
+
+       uint32_t                rebase_off() const                              INLINE { return E::get32(fields.rebase_off); }
+       void                    set_rebase_off(uint32_t value)  INLINE { E::set32(fields.rebase_off, value);  }
+       
+       uint32_t                rebase_size() const                             INLINE { return E::get32(fields.rebase_size); }
+       void                    set_rebase_size(uint32_t value) INLINE { E::set32(fields.rebase_size, value);  }
+       
+       uint32_t                bind_off() const                                INLINE { return E::get32(fields.bind_off); }
+       void                    set_bind_off(uint32_t value)    INLINE { E::set32(fields.bind_off, value);  }
+       
+       uint32_t                bind_size() const                               INLINE { return E::get32(fields.bind_size); }
+       void                    set_bind_size(uint32_t value)   INLINE { E::set32(fields.bind_size, value);  }
+       
+       uint32_t                weak_bind_off() const                           INLINE { return E::get32(fields.weak_bind_off); }
+       void                    set_weak_bind_off(uint32_t value)       INLINE { E::set32(fields.weak_bind_off, value);  }
+       
+       uint32_t                weak_bind_size() const                          INLINE { return E::get32(fields.weak_bind_size); }
+       void                    set_weak_bind_size(uint32_t value)      INLINE { E::set32(fields.weak_bind_size, value);  }
+       
+       uint32_t                lazy_bind_off() const                           INLINE { return E::get32(fields.lazy_bind_off); }
+       void                    set_lazy_bind_off(uint32_t value)       INLINE { E::set32(fields.lazy_bind_off, value);  }
+       
+       uint32_t                lazy_bind_size() const                          INLINE { return E::get32(fields.lazy_bind_size); }
+       void                    set_lazy_bind_size(uint32_t value)      INLINE { E::set32(fields.lazy_bind_size, value);  }
+       
+       uint32_t                export_off() const                              INLINE { return E::get32(fields.export_off); }
+       void                    set_export_off(uint32_t value)  INLINE { E::set32(fields.export_off, value);  }
+       
+       uint32_t                export_size() const                             INLINE { return E::get32(fields.export_size); }
+       void                    set_export_size(uint32_t value) INLINE { E::set32(fields.export_size, value);  }
+       
+       
+       typedef typename P::E           E;
+private:
+       dyld_info_command       fields;
+};
+
+#ifndef NO_ULEB 
+inline uint64_t read_uleb128(const uint8_t*& p, const uint8_t* end) {
+       uint64_t result = 0;
+       int              bit = 0;
+       do {
+               if (p == end)
+                       throw "malformed uleb128 extends beyond trie";
+
+               uint64_t slice = *p & 0x7f;
+
+               if (bit >= 64 || slice << bit >> bit != slice)
+                       throw "uleb128 too big for 64-bits";
+               else {
+                       result |= (slice << bit);
+                       bit += 7;
+               }
+       } 
+       while (*p++ & 0x80);
+       return result;
+}
+       
+
+static int64_t read_sleb128(const uint8_t*& p, const uint8_t* end)
+{
+       int64_t result = 0;
+       int bit = 0;
+       uint8_t byte;
+       do {
+               if (p == end)
+                       throw "malformed sleb128";
+               byte = *p++;
+               result |= ((byte & 0x7f) << bit);
+               bit += 7;
+       } while (byte & 0x80);
+       // sign extend negative numbers
+       if ( (byte & 0x40) != 0 )
+               result |= (-1LL) << bit;
+       return result;
+}
+
+#endif
+
+
 #endif // __MACH_O_FILE_ABSTRACTION__
 
 
index d5baede0b3b5d40f8d75bd5f2be897915206a3a4..945227b727b55054012fbd9994e4d36fcb63b3c9 100644 (file)
@@ -69,13 +69,14 @@ public:
        {
        public:
                                        Segment(uint64_t addr, uint64_t vmsize, uint64_t offset, uint64_t file_size, 
-                                                       uint32_t prot, const char* segName) : fAddress(addr), fSize(vmsize),
-                                                       fFileOffset(offset), fFileSize(file_size), fPermissions(prot),
+                                                       uint32_t prot, const char* segName) : fOrigAddress(addr), fOrigSize(vmsize),
+                                                       fOrigFileOffset(offset),  fOrigFileSize(file_size), fOrigPermissions(prot), 
+                                                       fSize(vmsize), fFileOffset(offset), fFileSize(file_size), fPermissions(prot),
                                                        fNewAddress(0), fMappedAddress(NULL) {
-                                                               strlcpy(fName, segName, 16);
+                                                               strlcpy(fOrigName, segName, 16);
                                                        }
                                                        
-               uint64_t        address() const         { return fAddress; }
+               uint64_t        address() const         { return fOrigAddress; }
                uint64_t        size() const            { return fSize; }
                uint64_t        fileOffset() const      { return fFileOffset; }
                uint64_t        fileSize() const        { return fFileSize; }
@@ -83,7 +84,7 @@ public:
                bool            readable() const        { return fPermissions & VM_PROT_READ; }
                bool            writable() const        { return fPermissions & VM_PROT_WRITE; }
                bool            executable() const      { return fPermissions & VM_PROT_EXECUTE; }
-               const char* name() const                { return fName; }
+               const char* name() const                { return fOrigName; }
                uint64_t        newAddress() const      { return fNewAddress; }
                void*           mappedAddress() const                   { return fMappedAddress; }
                void            setNewAddress(uint64_t addr)    { fNewAddress = addr; }
@@ -91,16 +92,21 @@ public:
                void            setSize(uint64_t new_size)              { fSize = new_size; }
                void            setFileOffset(uint64_t new_off) { fFileOffset = new_off; }
                void            setFileSize(uint64_t new_size)  { fFileSize = new_size; }
-               void            setWritable(bool w)             { if (w) fPermissions |= VM_PROT_WRITE; else fPermissions &= ~VM_PROT_WRITE; }
+               void            setWritable(bool w)                             { if (w) fPermissions |= VM_PROT_WRITE; else fPermissions &= ~VM_PROT_WRITE; }
+               void            reset()                                                 { fSize=fOrigSize; fFileOffset=fOrigFileOffset; fFileSize=fOrigFileSize; fPermissions=fOrigPermissions; }
        private:
-               uint64_t        fAddress;
-               uint64_t        fSize;
-               uint64_t        fFileOffset;
-               uint64_t        fFileSize;
-               uint64_t        fNewAddress;
-               void*           fMappedAddress;
-               uint32_t        fPermissions;
-               char            fName[16];
+               uint64_t                fOrigAddress;
+               uint64_t                fOrigSize;
+               uint64_t                fOrigFileOffset;
+               uint64_t                fOrigFileSize;
+               uint32_t                fOrigPermissions;
+               char                    fOrigName[16];
+               uint64_t                fSize;
+               uint64_t                fFileOffset;
+               uint64_t                fFileSize;
+               uint32_t                fPermissions;
+               uint64_t                fNewAddress;
+               void*                   fMappedAddress;
        };
 
        struct Library
@@ -108,10 +114,11 @@ public:
                const char*     name;
                uint32_t        currentVersion;
                uint32_t        compatibilityVersion;
+               bool            weakImport;
        };
        
        
-       virtual cpu_type_t                                                      getArchitecture() const = 0;
+       virtual ArchPair                                                        getArchPair() const = 0;
        virtual const char*                                                     getFilePath() const = 0;
        virtual uint64_t                                                        getOffsetInUniversalFile() const        = 0;
        virtual uint32_t                                                        getFileType() const     = 0;
@@ -119,6 +126,8 @@ public:
        virtual Library                                                         getID() const = 0;
        virtual bool                                                            isSplitSeg() const = 0;
        virtual bool                                                            hasSplitSegInfo() const = 0;
+       virtual bool                                                            isRootOwned() const = 0;
+       virtual bool                                                            inSharableLocation() const = 0;
        virtual uint32_t                                                        getNameFileOffset() const = 0;
        virtual time_t                                                          getLastModTime() const = 0;
        virtual ino_t                                                           getInode() const = 0;
@@ -142,10 +151,11 @@ template <typename A>
 class MachOLayout : public MachOLayoutAbstraction
 {
 public:
-                                                                                               MachOLayout(const void* machHeader, uint64_t offset, const char* path, ino_t inode, time_t modTime);
+                                                                                               MachOLayout(const void* machHeader, uint64_t offset, const char* path,
+                                                                                                                                       ino_t inode, time_t modTime, uid_t uid);
        virtual                                                                         ~MachOLayout() {}
 
-       virtual cpu_type_t                                                      getArchitecture() const;
+       virtual ArchPair                                                        getArchPair() const             { return fArchPair; }
        virtual const char*                                                     getFilePath() const             { return fPath; }
        virtual uint64_t                                                        getOffsetInUniversalFile() const { return fOffset; }
        virtual uint32_t                                                        getFileType() const             { return fFileType; }
@@ -153,6 +163,8 @@ public:
        virtual Library                                                         getID() const                   { return fDylibID; }
        virtual bool                                                            isSplitSeg() const;
        virtual bool                                                            hasSplitSegInfo() const { return fHasSplitSegInfo; }
+       virtual bool                                                            isRootOwned() const             { return fRootOwned; }
+       virtual bool                                                            inSharableLocation() const { return fShareableLocation; }
        virtual uint32_t                                                        getNameFileOffset() const{ return fNameFileOffset; }
        virtual time_t                                                          getLastModTime() const  { return fMTime; }
        virtual ino_t                                                           getInode() const                { return fInode; }
@@ -167,15 +179,18 @@ public:
        virtual uint64_t                                                        getExecutableVMSize() const             { return fVMExecutableSize; }
        virtual uint64_t                                                        getWritableVMSize() const               { return fVMWritablSize; }
        virtual uint64_t                                                        getReadOnlyVMSize() const               { return fVMReadOnlySize; }
-
+       
 private:
        typedef typename A::P                                   P;
        typedef typename A::P::E                                E;
        typedef typename A::P::uint_t                   pint_t;
        
+       static cpu_type_t                                                       arch();
+
        const char*                                                                     fPath;
        uint64_t                                                                        fOffset;
        uint32_t                                                                        fFileType;
+       ArchPair                                                                        fArchPair;
        uint32_t                                                                        fFlags;
        std::vector<Segment>                                            fSegments;
        std::vector<Library>                                            fLibraries;
@@ -192,6 +207,8 @@ private:
        uint64_t                                                                        fVMWritablSize;
        uint64_t                                                                        fVMReadOnlySize;
        bool                                                                            fHasSplitSegInfo;
+       bool                                                                            fRootOwned;
+       bool                                                                            fShareableLocation;
 };
 
 
@@ -199,12 +216,12 @@ private:
 class UniversalMachOLayout
 {
 public:
-                                                                                               UniversalMachOLayout(const char* path, const std::set<cpu_type_t>* onlyArchs=NULL);
+                                                                                               UniversalMachOLayout(const char* path, const std::set<ArchPair>* onlyArchs=NULL);
                                                                                                ~UniversalMachOLayout() {}
 
-       static const UniversalMachOLayout*                      find(const char* path, const std::set<cpu_type_t>* onlyArchs=NULL);
-       const MachOLayoutAbstraction*                           getArch(cpu_type_t) const;
-       const std::vector<MachOLayoutAbstraction*>&     getArchs() const { return fLayouts; }
+       static const UniversalMachOLayout&                      find(const char* path, const std::set<ArchPair>* onlyArchs=NULL);
+       const MachOLayoutAbstraction*                           getSlice(ArchPair ap) const;
+       const std::vector<MachOLayoutAbstraction*>&     allLayouts() const { return fLayouts; }
 
 private:
        struct CStringEquals {
@@ -212,6 +229,10 @@ 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 PathToNode                                                       fgLayoutCache;
        const char*                                                                     fPath;
        std::vector<MachOLayoutAbstraction*>            fLayouts;
@@ -220,23 +241,91 @@ private:
 UniversalMachOLayout::PathToNode UniversalMachOLayout::fgLayoutCache;
 
 
-const MachOLayoutAbstraction* UniversalMachOLayout::getArch(cpu_type_t arch) const
+
+
+// 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)
 {
-       for(std::vector<MachOLayoutAbstraction*>::const_iterator it=fLayouts.begin(); it != fLayouts.end(); ++it) {
-               const MachOLayoutAbstraction* layout = *it;
-               if ( layout->getArchitecture() == arch ) 
-                       return layout;
+       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 UniversalMachOLayout* UniversalMachOLayout::find(const char* path, const std::set<cpu_type_t>* onlyArchs)
+
+
+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;
+                               }
+                       }
+       }
+       throwf("no compatible slice found in %s", fPath);
+}
+
+
+const UniversalMachOLayout& UniversalMachOLayout::find(const char* path, const std::set<ArchPair>* onlyArchs)
 {
        // look in cache
        PathToNode::iterator pos = fgLayoutCache.find(path);
        if ( pos != fgLayoutCache.end() )
-               return pos->second;
+               return *pos->second;
                
        // create UniversalMachOLayout
        const UniversalMachOLayout* result = new UniversalMachOLayout(path, onlyArchs);
@@ -244,11 +333,83 @@ const UniversalMachOLayout* UniversalMachOLayout::find(const char* path, const s
        // add it to cache
        fgLayoutCache[result->fPath] = result;
        
-       return result;
+       return *result;
+}
+
+bool UniversalMachOLayout::bestSliceForArch(uint32_t sliceCount, const struct fat_arch* slices, ArchPair ap, uint32_t& bestSliceIndex)
+{
+       switch ( ap.arch ) {
+               case CPU_TYPE_POWERPC:
+               case CPU_TYPE_I386:
+               case CPU_TYPE_X86_64:
+                       // use first matching cputype
+                       for (uint32_t i=0; i < sliceCount; ++i) {
+                               if ( OSSwapBigToHostInt32(slices[i].cputype) == ap.arch ) {
+                                       bestSliceIndex = i;
+                                       return true;
+                               }
+                       }
+                       return false;
+               case CPU_TYPE_ARM:
+                       // find best matching arch
+                       const cpu_subtype_t* list = getArmSubtypeList(ap.subtype);
+                       if ( list != NULL ) {
+                               for(const cpu_subtype_t* s=list; *s != 0; ++s) {
+                                       for (uint32_t i=0; i < sliceCount; ++i) {
+                                               if ( (OSSwapBigToHostInt32(slices[i].cputype) == ap.arch) && (OSSwapBigToHostInt32(slices[i].cpusubtype) == *s) ) {
+                                                       bestSliceIndex = i;
+                                                       return true;
+                                               }
+                                       }
+                               }
+                               return false;
+                       }
+                       // unknown arm sub-type, must have exact match
+                       for (uint32_t i=0; i < sliceCount; ++i) {
+                               if ( (OSSwapBigToHostInt32(slices[i].cputype) == ap.arch) && (OSSwapBigToHostInt32(slices[i].cpusubtype) == ap.subtype) ) {
+                                       bestSliceIndex = i;
+                                       return true;
+                               }
+                       }
+                       return false;
+       }
+       throw "unknown architecture";
+}
+
+bool UniversalMachOLayout::compatibleSubtype(const std::set<ArchPair>* onlyArchs, cpu_type_t cpuType, cpu_subtype_t cpuSubType)
+{
+       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;
+                                       }
+                               }
+                       }
+               }
+       }
+       return false;
 }
 
 
-UniversalMachOLayout::UniversalMachOLayout(const char* path, const std::set<cpu_type_t>* onlyArchs)
+UniversalMachOLayout::UniversalMachOLayout(const char* path, const std::set<ArchPair>* onlyArchs)
  : fPath(strdup(path))
 {
        // map in whole file
@@ -271,54 +432,76 @@ UniversalMachOLayout::UniversalMachOLayout(const char* path, const std::set<cpu_
                const mach_header* mh = (mach_header*)p;
                if ( fh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
                        // Fat header is always big-endian
-                       const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
-                       for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
-                               uint32_t fileOffset = OSSwapBigToHostInt32(archs[i].offset);
-                               cpu_type_t curArch =  OSSwapBigToHostInt32(archs[i].cputype);
-                               if ( fileOffset > stat_buf.st_size )
-                                       throwf("malformed universal file, slice for architecture 0x%08X is beyond end of file: %s", curArch, path);
-                               try {
-                                       if ( (onlyArchs == NULL) || (onlyArchs->count(curArch) != 0) ) {
-                                               switch ( curArch ) {
+                       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) ) {
+                                       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);
+                                       }
+                                       try {
+                                               switch ( OSSwapBigToHostInt32(slices[i].cputype) ) {
                                                        case CPU_TYPE_POWERPC:
-                                                               fLayouts.push_back(new MachOLayout<ppc>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime));
-                                                               break;
-                                                       case CPU_TYPE_POWERPC64:
-                                                               fLayouts.push_back(new MachOLayout<ppc64>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime));
+                                                               fLayouts.push_back(new MachOLayout<ppc>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
                                                                break;
                                                        case CPU_TYPE_I386:
-                                                               fLayouts.push_back(new MachOLayout<x86>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime));
+                                                               fLayouts.push_back(new MachOLayout<x86>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
                                                                break;
                                                        case CPU_TYPE_X86_64:
-                                                               fLayouts.push_back(new MachOLayout<x86_64>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime));
+                                                               fLayouts.push_back(new MachOLayout<x86_64>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
+                                                               break;
+                                                       case CPU_TYPE_ARM:
+                                                               fLayouts.push_back(new MachOLayout<arm>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
+                                                               break;
+                                                       case CPU_TYPE_POWERPC64:
+                                                               // ignore ppc64 slices
                                                                break;
                                                        default:
-                                                               throw "unknown file format";
+                                                               throw "unknown slice in fat file";
                                                }
                                        }
-                               }
-                               catch (const char* msg) {
-                                       fprintf(stderr, "warning: %s for %s\n", msg, path);
+                                       catch (const char* msg) {
+                                               fprintf(stderr, "warning: %s for %s\n", msg, path);
+                                       }
                                }
                        }
                }
                else {
                        try {
                                if ( (OSSwapBigToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapBigToHostInt32(mh->cputype) == CPU_TYPE_POWERPC)) {
-                                       if ( (onlyArchs == NULL) || (onlyArchs->count(CPU_TYPE_POWERPC) != 0) ) 
-                                               fLayouts.push_back(new MachOLayout<ppc>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime));
-                               }
-                               else if ( (OSSwapBigToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapBigToHostInt32(mh->cputype) == CPU_TYPE_POWERPC64)) {
-                                       if ( (onlyArchs == NULL) || (onlyArchs->count(CPU_TYPE_POWERPC64) != 0) ) 
-                                               fLayouts.push_back(new MachOLayout<ppc64>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime));
+                                       if ( (onlyArchs == NULL) || compatibleSubtype(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(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) || (onlyArchs->count(CPU_TYPE_I386) != 0) ) 
-                                               fLayouts.push_back(new MachOLayout<x86>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime));
+                                       if ( (onlyArchs == NULL) || compatibleSubtype(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) || (onlyArchs->count(CPU_TYPE_X86_64) != 0) ) 
-                                               fLayouts.push_back(new MachOLayout<x86_64>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime));
+                                       if ( (onlyArchs == NULL) || compatibleSubtype(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)) ) 
+                                               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)) {
+                                       // ignore ppc64 slices
                                }
                                else {
                                        throw "unknown file format";
@@ -336,18 +519,18 @@ UniversalMachOLayout::UniversalMachOLayout(const char* path, const std::set<cpu_
 }
 
 
-
 template <typename A>
-MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char* path, ino_t inode, time_t modTime)
- : fPath(path), fOffset(offset), fMTime(modTime), fInode(inode), fHasSplitSegInfo(false)
+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)
 {
        fDylibID.name = NULL;
        fDylibID.currentVersion = 0;
        fDylibID.compatibilityVersion = 0;
-       
+
        const macho_header<P>* mh = (const macho_header<P>*)machHeader;
-       if ( mh->cputype() != getArchitecture() )
-               throw "wrong architecture";
+       if ( mh->cputype() != arch() )
+               throw "Layout object is wrong architecture";
        switch ( mh->filetype() ) {
                case MH_DYLIB:
                case MH_BUNDLE:
@@ -360,6 +543,8 @@ MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char*
        }
        fFlags = mh->flags();
        fFileType = mh->filetype();
+       fArchPair.arch = mh->cputype();
+       fArchPair.subtype = mh->cpusubtype();
        
        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();
@@ -373,6 +558,7 @@ MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char*
                                        fDylibID.currentVersion = dylib->current_version();
                                        fDylibID.compatibilityVersion = dylib->compatibility_version();
                                        fNameFileOffset = dylib->name() - (char*)machHeader;
+                                       fShareableLocation = ( (strncmp(fDylibID.name, "/usr/lib/", 9) == 0) || (strncmp(fDylibID.name, "/System/Library/", 16) == 0) );
                                }
                                break;
                        case LC_LOAD_DYLIB:
@@ -384,6 +570,7 @@ MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char*
                                        lib.name = strdup(dylib->name());
                                        lib.currentVersion = dylib->current_version();
                                        lib.compatibilityVersion = dylib->compatibility_version();
+                                       lib.weakImport = ( cmd->cmd() == LC_LOAD_WEAK_DYLIB );
                                        fLibraries.push_back(lib);
                                }
                                break;
@@ -436,10 +623,11 @@ MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char*
                fVMSize = (highSegment->address() + highSegment->size() - fLowSegment->address() + 4095) & (-4096);                     
 }
 
-template <> cpu_type_t MachOLayout<ppc>::getArchitecture()    const { return CPU_TYPE_POWERPC; }
-template <> cpu_type_t MachOLayout<ppc64>::getArchitecture()  const { return CPU_TYPE_POWERPC64; }
-template <> cpu_type_t MachOLayout<x86>::getArchitecture()    const { return CPU_TYPE_I386; }
-template <> cpu_type_t MachOLayout<x86_64>::getArchitecture() const { return CPU_TYPE_X86_64; }
+template <> cpu_type_t MachOLayout<ppc>::arch()     { return CPU_TYPE_POWERPC; }
+template <> cpu_type_t MachOLayout<x86>::arch()     { return CPU_TYPE_I386; }
+template <> cpu_type_t MachOLayout<x86_64>::arch()  { return CPU_TYPE_X86_64; }
+template <> cpu_type_t MachOLayout<arm>::arch()                { return CPU_TYPE_ARM; }
+
 
 template <>
 bool MachOLayout<ppc>::isSplitSeg() const
@@ -453,6 +641,12 @@ bool MachOLayout<x86>::isSplitSeg() const
        return ( (this->getFlags() & MH_SPLIT_SEGS) != 0 );
 }
 
+template <>
+bool MachOLayout<arm>::isSplitSeg() const
+{
+       return ( (this->getFlags() & MH_SPLIT_SEGS) != 0 );
+}
+
 template <typename A>
 bool MachOLayout<A>::isSplitSeg() const
 {
index e3c187fefcc3751775c494dc45189c779c0b7290..9dcfc6babd0d4113e7aab01902a879b009cee23a 100644 (file)
 #include <mach-o/reloc.h>
 #include <mach-o/ppc/reloc.h>
 #include <mach-o/x86_64/reloc.h>
+#include <mach-o/arm/reloc.h>
 #include <vector>
 #include <set>
 
 #include "MachOFileAbstraction.hpp"
 #include "Architectures.hpp"
 #include "MachOLayout.hpp"
+#include "MachOTrie.hpp"
 
 
 
@@ -80,11 +82,14 @@ protected:
        pint_t                                                                          getSlideForNewAddress(pint_t newAddress);
        
 private:
-       pint_t                                                                          calculateRelocBase();
+       void                                                                            calculateRelocBase();
        void                                                                            adjustLoadCommands();
        void                                                                            adjustSymbolTable();
        void                                                                            adjustDATA();
        void                                                                            adjustCode();
+       void                                                                            applyRebaseInfo();
+       void                                                                            adjustExportInfo();
+       void                                                                            doRebase(int segIndex, uint64_t segOffset, uint8_t type);
        void                                                                            adjustSegmentLoadCommand(macho_segment_command<P>* seg);
        pint_t                                                                          getSlideForVMAddress(pint_t vmaddress);
        pint_t*                                                                         mappedAddressForVMAddress(pint_t vmaddress);
@@ -101,14 +106,19 @@ protected:
        const MachOLayoutAbstraction&                           fLayout;
 private:
        pint_t                                                                          fOrignalVMRelocBaseAddress; // add reloc address to this to get original address reloc referred to
+       const macho_symtab_command<P>*                          fSymbolTable;
+       const macho_dysymtab_command<P>*                        fDynamicSymbolTable;
+       const macho_dyld_info_command<P>*                       fDyldInfo;
        bool                                                                            fSplittingSegments;
+       bool                                                                            fOrignalVMRelocBaseAddressValid;
 };
 
 
 
 template <typename A>
 Rebaser<A>::Rebaser(const MachOLayoutAbstraction& layout)
- :     fLayout(layout), fOrignalVMRelocBaseAddress(NULL), fLinkEditBase(NULL), fSplittingSegments(false)
+ :     fLayout(layout), fOrignalVMRelocBaseAddress(NULL), fLinkEditBase(NULL), 
+       fSymbolTable(NULL), fDynamicSymbolTable(NULL), fDyldInfo(NULL), fSplittingSegments(false), fOrignalVMRelocBaseAddressValid(false)
 {
        fHeader = (const macho_header<P>*)fLayout.getSegments()[0].mappedAddress();
        switch ( fHeader->filetype() ) {
@@ -130,15 +140,35 @@ Rebaser<A>::Rebaser(const MachOLayoutAbstraction& layout)
        if ( fLinkEditBase == NULL )    
                throw "no __LINKEDIT segment";
                
-       fOrignalVMRelocBaseAddress = calculateRelocBase();
+       // get symbol table info
+       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) {
+               switch (cmd->cmd()) {
+                       case LC_SYMTAB:
+                               fSymbolTable = (macho_symtab_command<P>*)cmd;
+                               break;
+                       case LC_DYSYMTAB:
+                               fDynamicSymbolTable = (macho_dysymtab_command<P>*)cmd;
+                               break;
+                       case LC_DYLD_INFO:
+                       case LC_DYLD_INFO_ONLY:
+                               fDyldInfo = (macho_dyld_info_command<P>*)cmd;
+                               break;
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }       
+
+       calculateRelocBase();
        
        fSplittingSegments = layout.hasSplitSegInfo() && this->unequalSlides();
 }
 
 template <> cpu_type_t Rebaser<ppc>::getArchitecture()    const { return CPU_TYPE_POWERPC; }
-template <> cpu_type_t Rebaser<ppc64>::getArchitecture()  const { return CPU_TYPE_POWERPC64; }
 template <> cpu_type_t Rebaser<x86>::getArchitecture()    const { return CPU_TYPE_I386; }
 template <> cpu_type_t Rebaser<x86_64>::getArchitecture() const { return CPU_TYPE_X86_64; }
+template <> cpu_type_t Rebaser<arm>::getArchitecture() const { return CPU_TYPE_ARM; }
 
 template <typename A>
 bool Rebaser<A>::unequalSlides() const
@@ -178,7 +208,10 @@ template <typename A>
 void Rebaser<A>::rebase()
 {              
        // update writable segments that have internal pointers
-       this->adjustDATA();
+       if ( fDyldInfo != NULL )
+               this->applyRebaseInfo();
+       else
+               this->adjustDATA();
 
        // if splitting segments, update code-to-data references
        this->adjustCode();
@@ -191,6 +224,10 @@ void Rebaser<A>::rebase()
        
        // update symbol table  
        this->adjustSymbolTable();
+       
+       // update export info
+       if ( fDyldInfo != NULL )
+               this->adjustExportInfo();
 }
 
 template <>
@@ -315,50 +352,103 @@ typename A::P::uint_t Rebaser<A>::getSlideForNewAddress(pint_t newAddress)
 template <typename A>
 typename A::P::uint_t* Rebaser<A>::mappedAddressForRelocAddress(pint_t r_address)
 {
-       return this->mappedAddressForVMAddress(r_address + fOrignalVMRelocBaseAddress);
+       if ( fOrignalVMRelocBaseAddressValid )
+               return this->mappedAddressForVMAddress(r_address + fOrignalVMRelocBaseAddress);
+       else
+               throw "can't apply relocation.  Relocation base not known";
 }
 
 
 template <typename A>
 void Rebaser<A>::adjustSymbolTable()
 {
-       const macho_dysymtab_command<P>* dysymtab = NULL;
-       macho_nlist<P>* symbolTable = NULL;
-
-       // get symbol table info
-       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) {
-               switch (cmd->cmd()) {
-                       case LC_SYMTAB:
-                               {
-                                       const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
-                                       symbolTable = (macho_nlist<P>*)(&fLinkEditBase[symtab->symoff()]);
-                               }
-                               break;
-                       case LC_DYSYMTAB:
-                               dysymtab = (macho_dysymtab_command<P>*)cmd;
-                               break;
-               }
-               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
-       }       
+       macho_nlist<P>* symbolTable = (macho_nlist<P>*)(&fLinkEditBase[fSymbolTable->symoff()]);
 
        // walk all exports and slide their n_value
-       macho_nlist<P>* lastExport = &symbolTable[dysymtab->iextdefsym()+dysymtab->nextdefsym()];
-       for (macho_nlist<P>* entry = &symbolTable[dysymtab->iextdefsym()]; entry < lastExport; ++entry) {
+       macho_nlist<P>* lastExport = &symbolTable[fDynamicSymbolTable->iextdefsym()+fDynamicSymbolTable->nextdefsym()];
+       for (macho_nlist<P>* entry = &symbolTable[fDynamicSymbolTable->iextdefsym()]; entry < lastExport; ++entry) {
                if ( (entry->n_type() & N_TYPE) == N_SECT )
                        entry->set_n_value(entry->n_value() + this->getSlideForVMAddress(entry->n_value()));
        }
 
-       // walk all local symbols and slide their n_value (don't adjust and stabs)
-       macho_nlist<P>*  lastLocal = &symbolTable[dysymtab->ilocalsym()+dysymtab->nlocalsym()];
-       for (macho_nlist<P>* entry = &symbolTable[dysymtab->ilocalsym()]; entry < lastLocal; ++entry) {
+       // walk all local symbols and slide their n_value (don't adjust any stabs)
+       macho_nlist<P>*  lastLocal = &symbolTable[fDynamicSymbolTable->ilocalsym()+fDynamicSymbolTable->nlocalsym()];
+       for (macho_nlist<P>* entry = &symbolTable[fDynamicSymbolTable->ilocalsym()]; entry < lastLocal; ++entry) {
                if ( (entry->n_sect() != NO_SECT) && ((entry->n_type() & N_STAB) == 0) )
                        entry->set_n_value(entry->n_value() + this->getSlideForVMAddress(entry->n_value()));
        }
 }
 
+template <typename A>
+void Rebaser<A>::adjustExportInfo()
+{
+       // if no export info, nothing to adjust
+       if ( fDyldInfo->export_size() == 0 )
+               return;
+
+       // 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* end = &start[fDyldInfo->export_size()];
+       std::vector<mach_o::trie::Entry> originalExports;
+       try {
+               parseTrie(start, end, originalExports);
+       }
+       catch (const char* msg) {
+               throwf("%s in %s", msg, fLayout.getFilePath());
+       }
+       
+       std::vector<mach_o::trie::Entry> newExports;
+       newExports.reserve(originalExports.size());
+       pint_t baseAddress = this->getBaseAddress();
+       pint_t baseAddressSlide = this->getSlideForVMAddress(baseAddress);
+       for (std::vector<mach_o::trie::Entry>::iterator it=originalExports.begin(); it != originalExports.end(); ++it) {
+               // remove symbols used by the static linker only
+               if (       (strncmp(it->name, "$ld$", 4) == 0) 
+                               || (strncmp(it->name, ".objc_class_name",16) == 0) 
+                               || (strncmp(it->name, ".objc_category_name",19) == 0) ) {
+                       //fprintf(stderr, "ignoring symbol %s\n", it->name);
+                       continue;
+               }
+               // adjust symbols in slid segments
+               //uint32_t oldOffset = it->address;
+               it->address += (this->getSlideForVMAddress(it->address + baseAddress) - baseAddressSlide);
+               //fprintf(stderr, "orig=0x%08X, new=0x%08llX, sym=%s\n", oldOffset, it->address, it->name);
+               newExports.push_back(*it);
+       }
+       
+       // rebuild export trie
+       std::vector<uint8_t> newExportTrieBytes;
+       newExportTrieBytes.reserve(fDyldInfo->export_size());
+       mach_o::trie::makeTrie(newExports, newExportTrieBytes);
+       // align
+       while ( (newExportTrieBytes.size() % sizeof(pint_t)) != 0 )
+               newExportTrieBytes.push_back(0);
+       
+       // copy into place, zero pad
+       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);
+       }
+}
 
 
 
@@ -383,7 +473,7 @@ void Rebaser<A>::doCodeUpdate(uint8_t kind, uint64_t address, int64_t codeToData
                        value64 += codeToDataDelta;
                         A::P::E::set64(*(uint64_t*)p, value64);
                        break;
-               case 3: // used only for ppc/ppc64, an instruction that sets the hi16 of a register
+               case 3: // used only for ppc, an instruction that sets the hi16 of a register
                        // adjust low 16 bits of instruction which contain hi16 of distance to something in DATA
                        if ( (codeToDataDelta & 0xFFFF) != 0 )
                                throwf("codeToDataDelta=0x%0llX is not a multiple of 64K", codeToDataDelta);
@@ -476,41 +566,130 @@ void Rebaser<A>::adjustCode()
        }
 }
 
-
 template <typename A>
-void Rebaser<A>::adjustDATA()
+void Rebaser<A>::doRebase(int segIndex, uint64_t segOffset, uint8_t type)
 {
-       const macho_dysymtab_command<P>* dysymtab = NULL;
+       const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
+       if ( segIndex > segments.size() )
+               throw "bad segment index in rebase info";
+       const MachOLayoutAbstraction::Segment& seg = segments[segIndex];
+       uint8_t*  mappedAddr = (uint8_t*)seg.mappedAddress() + segOffset;
+       pint_t*   mappedAddrP = (pint_t*)mappedAddr;
+       uint32_t* mappedAddr32 = (uint32_t*)mappedAddr;
+       pint_t valueP;
+       pint_t valuePnew;
+       uint32_t value32;
+       int32_t svalue32;
+       int32_t svalue32new;
+       switch ( type ) {
+               case REBASE_TYPE_POINTER:
+                       valueP= P::getP(*mappedAddrP);
+                       P::setP(*mappedAddrP, valueP + this->getSlideForVMAddress(valueP));
+                       break;
+               
+               case REBASE_TYPE_TEXT_ABSOLUTE32:
+                       value32 = E::get32(*mappedAddr32);
+                       E::set32(*mappedAddr32, value32 + this->getSlideForVMAddress(value32));
+                       break;
+                       
+               case REBASE_TYPE_TEXT_PCREL32:
+                       svalue32 = E::get32(*mappedAddr32);
+                       valueP = seg.address() + segOffset + 4 + svalue32;
+                       valuePnew = valueP + this->getSlideForVMAddress(valueP);
+                       svalue32new = seg.address() + segOffset + 4 - valuePnew;
+                       E::set32(*mappedAddr32, svalue32new);
+                       break;
+               
+               default:
+                       throw "bad rebase type";
+       }
+}
 
-       // get symbol table info
-       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) {
-               switch (cmd->cmd()) {
-                       case LC_DYSYMTAB:
-                               dysymtab = (macho_dysymtab_command<P>*)cmd;
+
+template <typename A>
+void Rebaser<A>::applyRebaseInfo()
+{
+       const uint8_t* p = &fLinkEditBase[fDyldInfo->rebase_off()];
+       const uint8_t* end = &p[fDyldInfo->rebase_size()];
+       
+       uint8_t type = 0;
+       int segIndex;
+       uint64_t segOffset = 0;
+       uint32_t count;
+       uint32_t skip;
+       bool done = false;
+       while ( !done && (p < end) ) {
+               uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
+               uint8_t opcode = *p & REBASE_OPCODE_MASK;
+               ++p;
+               switch (opcode) {
+                       case REBASE_OPCODE_DONE:
+                               done = true;
+                               break;
+                       case REBASE_OPCODE_SET_TYPE_IMM:
+                               type = immediate;
                                break;
+                       case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+                               segIndex = immediate;
+                               segOffset = read_uleb128(p, end);
+                               break;
+                       case REBASE_OPCODE_ADD_ADDR_ULEB:
+                               segOffset += read_uleb128(p, end);
+                               break;
+                       case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
+                               segOffset += immediate*sizeof(pint_t);
+                               break;
+                       case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
+                               for (int i=0; i < immediate; ++i) {
+                                       doRebase(segIndex, segOffset, type);
+                                       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);
+                                       segOffset += sizeof(pint_t);
+                               }
+                               break;
+                       case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
+                               doRebase(segIndex, segOffset, type);
+                               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);
+                                       segOffset += skip + sizeof(pint_t);
+                               }
+                               break;
+                       default:
+                               throwf("bad rebase opcode %d", *p);
                }
-               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
        }       
+}
 
-
+template <typename A>
+void Rebaser<A>::adjustDATA()
+{
        // walk all local relocations and slide every pointer
-       const macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(&fLinkEditBase[dysymtab->locreloff()]);
-       const macho_relocation_info<P>* const relocsEnd = &relocsStart[dysymtab->nlocrel()];
+       const macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(&fLinkEditBase[fDynamicSymbolTable->locreloff()]);
+       const macho_relocation_info<P>* const relocsEnd = &relocsStart[fDynamicSymbolTable->nlocrel()];
        for (const macho_relocation_info<P>* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
                this->doLocalRelocation(reloc);
        }
        
        // walk non-lazy-pointers and slide the ones that are LOCAL
-       cmd = cmds;
+       const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+       const uint32_t cmd_count = fHeader->ncmds();
+       const macho_load_command<P>* cmd = cmds;
        for (uint32_t i = 0; i < cmd_count; ++i) {
                if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
                        const macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
                        const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)seg + sizeof(macho_segment_command<P>));
                        const macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
-                       const uint32_t* const indirectTable = (uint32_t*)(&fLinkEditBase[dysymtab->indirectsymoff()]);
+                       const uint32_t* const indirectTable = (uint32_t*)(&fLinkEditBase[fDynamicSymbolTable->indirectsymoff()]);
                        for(const macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
                                if ( (sect->flags() & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ) {
                                        const uint32_t indirectTableOffset = sect->reserved1();
@@ -533,23 +712,8 @@ void Rebaser<A>::adjustDATA()
 template <typename A>
 void Rebaser<A>::adjustRelocBaseAddresses()
 {
-       // split seg file alreday have reloc base of first writable segment
-       // only non-split-segs that are being split need this adjusted
-       if ( (fHeader->flags() & MH_SPLIT_SEGS) == 0  ) {
-
-               // get symbol table to find relocation records
-               const macho_dysymtab_command<P>* dysymtab = NULL;
-               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) {
-                       switch (cmd->cmd()) {
-                               case LC_DYSYMTAB:
-                                       dysymtab = (macho_dysymtab_command<P>*)cmd;
-                                       break;
-                       }
-                       cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
-               }       
+       // split seg file need reloc base to be first writable segment
+       if ( fSplittingSegments && ((fHeader->flags() & MH_SPLIT_SEGS) == 0) ) {
 
                // get amount to adjust reloc address
                int32_t relocAddressAdjust = 0;
@@ -563,15 +727,15 @@ void Rebaser<A>::adjustRelocBaseAddresses()
                }
 
                // walk all local relocations and adjust every address 
-               macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(&fLinkEditBase[dysymtab->locreloff()]);
-               macho_relocation_info<P>* const relocsEnd = &relocsStart[dysymtab->nlocrel()];
+               macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(&fLinkEditBase[fDynamicSymbolTable->locreloff()]);
+               macho_relocation_info<P>* const relocsEnd = &relocsStart[fDynamicSymbolTable->nlocrel()];
                for (macho_relocation_info<P>* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
                        reloc->set_r_address(reloc->r_address()-relocAddressAdjust);
                }
                
                // walk all external relocations and adjust every address 
-               macho_relocation_info<P>* const externRelocsStart = (macho_relocation_info<P>*)(&fLinkEditBase[dysymtab->extreloff()]);
-               macho_relocation_info<P>* const externRelocsEnd = &externRelocsStart[dysymtab->nextrel()];
+               macho_relocation_info<P>* const externRelocsStart = (macho_relocation_info<P>*)(&fLinkEditBase[fDynamicSymbolTable->extreloff()]);
+               macho_relocation_info<P>* const externRelocsEnd = &externRelocsStart[fDynamicSymbolTable->nextrel()];
                for (macho_relocation_info<P>* reloc=externRelocsStart; reloc < externRelocsEnd; ++reloc) {
                        reloc->set_r_address(reloc->r_address()-relocAddressAdjust);
                }
@@ -657,7 +821,7 @@ void Rebaser<A>::doLocalRelocation(const macho_relocation_info<P>* reloc)
 
 
 template <typename A>
-typename A::P::uint_t Rebaser<A>::calculateRelocBase()
+void Rebaser<A>::calculateRelocBase()
 {
        const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
        if ( fHeader->flags() & MH_SPLIT_SEGS ) {
@@ -666,38 +830,21 @@ typename A::P::uint_t Rebaser<A>::calculateRelocBase()
                        const MachOLayoutAbstraction::Segment& seg = *it;
                        if ( seg.writable() ) {
                                // found first writable segment
-                               return seg.address();
+                               fOrignalVMRelocBaseAddress = seg.address();
+                               fOrignalVMRelocBaseAddressValid = true;
                        }
                }
-               throw "no writable segment";
        }
        else {
                // reloc addresses are from the start of the mapped file (base address)
-               return segments[0].address();
+               fOrignalVMRelocBaseAddress = segments[0].address();
+               fOrignalVMRelocBaseAddressValid = true;
        }
 }
 
-template <>
-ppc64::P::uint_t Rebaser<ppc64>::calculateRelocBase()
-{
-       // reloc addresses either:
-       // 1) from the first segment vmaddr if no writable segment is > 4GB from first segment vmaddr
-       // 2) from start of first writable segment
-       const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
-       uint64_t threshold = segments[0].address() + 0x100000000ULL;
-       for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator it = segments.begin(); it != segments.end(); ++it) {
-               const MachOLayoutAbstraction::Segment& seg = *it;
-               if ( seg.writable() && (seg.address()+seg.size()) > threshold ) {
-                       // found writable segment with address > 4GB past base address
-                       return seg.address();
-               }
-       }
-       // just use base address
-       return segments[0].address();
-}
 
 template <>
-x86_64::P::uint_t Rebaser<x86_64>::calculateRelocBase()
+void Rebaser<x86_64>::calculateRelocBase()
 {
        // reloc addresses are always based from the start of the first writable segment
        const std::vector<MachOLayoutAbstraction::Segment>& segments = fLayout.getSegments();
@@ -705,10 +852,10 @@ x86_64::P::uint_t Rebaser<x86_64>::calculateRelocBase()
                const MachOLayoutAbstraction::Segment& seg = *it;
                if ( seg.writable() ) {
                        // found first writable segment
-                       return seg.address();
+                       fOrignalVMRelocBaseAddress = seg.address();
+                       fOrignalVMRelocBaseAddressValid = true;
                }
        }
-       throw "no writable segment";
 }
 
 
@@ -748,15 +895,15 @@ public:
                                                        case CPU_TYPE_POWERPC:
                                                                fRebasers.push_back(new Rebaser<ppc>(&p[fileOffset]));
                                                                break;
-                                                       case CPU_TYPE_POWERPC64:
-                                                               fRebasers.push_back(new Rebaser<ppc64>(&p[fileOffset]));
-                                                               break;
                                                        case CPU_TYPE_I386:
                                                                fRebasers.push_back(new Rebaser<x86>(&p[fileOffset]));
                                                                break;
                                                        case CPU_TYPE_X86_64:
                                                                fRebasers.push_back(new Rebaser<x86_64>(&p[fileOffset]));
                                                                break;
+                                                       case CPU_TYPE_ARM:
+                                                               fRebasers.push_back(new Rebaser<arm>(&p[fileOffset]));
+                                                               break;
                                                        default:
                                                                throw "unknown file format";
                                                }
@@ -771,15 +918,15 @@ public:
                                        if ( (OSSwapBigToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapBigToHostInt32(mh->cputype) == CPU_TYPE_POWERPC)) {
                                                fRebasers.push_back(new Rebaser<ppc>(mh));
                                        }
-                                       else if ( (OSSwapBigToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapBigToHostInt32(mh->cputype) == CPU_TYPE_POWERPC64)) {
-                                               fRebasers.push_back(new Rebaser<ppc64>(mh));
-                                       }
                                        else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_I386)) {
                                                fRebasers.push_back(new Rebaser<x86>(mh));
                                        }
                                        else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_X86_64)) {
                                                fRebasers.push_back(new Rebaser<x86_64>(mh));
                                        }
+                                       else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_ARM)) {
+                                               fRebasers.push_back(new Rebaser<arm>(mh));
+                                       }
                                        else {
                                                throw "unknown file format";
                                        }
diff --git a/launch-cache/MachOTrie.hpp b/launch-cache/MachOTrie.hpp
new file mode 100644 (file)
index 0000000..7c5d4a7
--- /dev/null
@@ -0,0 +1,320 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2008 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 __MACH_O_TRIE__
+#define __MACH_O_TRIE__
+
+
+#include "MachOFileAbstraction.hpp"
+
+namespace mach_o {
+namespace trie {
+
+struct Edge
+{
+                                       Edge(const char* s, struct Node* n) : fSubString(s), fChild(n) { }
+                                       ~Edge() {  }
+       const char*             fSubString;
+       struct Node*    fChild;
+       
+};
+
+struct Node
+{
+                                               Node(const char* s) : fCummulativeString(s), fAddress(0), fFlags(0), fOrdered(false), 
+                                                                                       fHaveExportInfo(false), fTrieOffset(0) {}
+                                               ~Node() { }
+       const char*                     fCummulativeString;
+       std::vector<Edge>       fChildren;
+       uint64_t                        fAddress;
+       uint32_t                        fFlags;
+       bool                            fOrdered;
+       bool                            fHaveExportInfo;
+       uint32_t                        fTrieOffset;
+       
+       void addSymbol(const char* fullStr, uint64_t address, uint32_t flags) {
+               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);
+                               return;
+                       }
+                       else {
+                               for (int i=subStringLen-1; i > 0; --i) {
+                                       if ( strncmp(e.fSubString, partialStr, i) == 0 ) {
+                                               // found a common substring, splice in new node
+                                               //  was A -> C,  now A -> B -> C
+                                               char* bNodeCummStr = strdup(e.fChild->fCummulativeString);
+                                               bNodeCummStr[strlen(bNodeCummStr)+i-subStringLen] = '\0';
+                                               //node* aNode = this;
+                                               Node* bNode = new Node(bNodeCummStr);
+                                               Node* cNode = e.fChild;
+                                               char* abEdgeStr = strdup(e.fSubString);
+                                               abEdgeStr[i] = '\0';
+                                               char* bcEdgeStr = strdup(&e.fSubString[i]);
+                                               Edge& abEdge = e;
+                                               abEdge.fSubString = abEdgeStr;
+                                               abEdge.fChild = bNode;
+                                               Edge bcEdge(bcEdgeStr, cNode);
+                                               bNode->fChildren.push_back(bcEdge);
+                                               bNode->addSymbol(fullStr, address, flags);
+                                               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->fHaveExportInfo = true;
+       }
+       
+       void addOrderedNodes(const char* name, std::vector<Node*>& orderedNodes) {
+               if ( !fOrdered ) {
+                       orderedNodes.push_back(this);
+                       //fprintf(stderr, "ordered %p %s\n", this, fCummulativeString);
+                       fOrdered = true;
+               }
+               const char* partialStr = &name[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->addOrderedNodes(name, orderedNodes);
+                               return;
+                       }
+               }
+       }
+
+       // byte for terminal node size in bytes, or 0x00 if not terminal node
+       // teminal node (uleb128 flags, uleb128 addr)
+       // 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);
+
+               // add children
+               ++nodeSize; // byte for count of chidren
+               for (std::vector<Edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
+                       Edge& e = *it;
+                       nodeSize += strlen(e.fSubString) + 1 + uleb128_size(e.fChild->fTrieOffset);
+               }
+               bool result = (fTrieOffset != offset);
+               fTrieOffset = offset;
+               //fprintf(stderr, "updateOffset %p %05d %s\n", this, fTrieOffset, fCummulativeString);
+               offset += nodeSize;
+               // return true if fTrieOffset was changed
+               return result;
+       }
+
+       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);
+               }
+               else {
+                       // no export info
+                       out.push_back(0);
+               }
+               // write number of children
+               out.push_back(fChildren.size());
+               // write each child
+               for (std::vector<Edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
+                       Edge& e = *it;
+                       append_string(e.fSubString, out);
+                       append_uleb128(e.fChild->fTrieOffset, out);
+               }
+       }
+       
+private:
+       static void append_uleb128(uint64_t value, std::vector<uint8_t>& out) {
+               uint8_t byte;
+               do {
+                       byte = value & 0x7F;
+                       value &= ~0x7F;
+                       if ( value != 0 )
+                               byte |= 0x80;
+                       out.push_back(byte);
+                       value = value >> 7;
+               } while( byte >= 0x80 );
+       }
+       
+       static void append_string(const char* str, std::vector<uint8_t>& out) {
+               for (const char* s = str; *s != '\0'; ++s)
+                       out.push_back(*s);
+               out.push_back('\0');
+       }
+       
+       static unsigned int     uleb128_size(uint64_t value) {
+               uint32_t result = 0;
+               do {
+                       value = value >> 7;
+                       ++result;
+               } while ( value != 0 );
+               return result;
+       }
+       
+
+};
+
+inline uint64_t read_uleb128(const uint8_t*& p, const uint8_t* end) {
+       uint64_t result = 0;
+       int              bit = 0;
+       do {
+               if (p == end)
+                       throw "malformed uleb128 extends beyond trie";
+
+               uint64_t slice = *p & 0x7f;
+
+               if (bit >= 64 || slice << bit >> bit != slice)
+                       throw "uleb128 too big for 64-bits";
+               else {
+                       result |= (slice << bit);
+                       bit += 7;
+               }
+       } 
+       while (*p++ & 0x80);
+       return result;
+}
+       
+
+
+struct Entry
+{
+       const char*             name;
+       uint64_t                address;
+       uint64_t                flags;
+};
+
+
+inline void makeTrie(const std::vector<Entry>& input, 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);
+       }
+
+       // 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) {
+               start.addOrderedNodes(it->name, orderedNodes);
+       }
+       
+       // assign each node in the vector an offset in the trie stream, iterating until all uleb128 sizes have stabilized
+       bool more;
+       do {
+               uint32_t offset = 0;
+               more = false;
+               for (std::vector<Node*>::iterator it = orderedNodes.begin(); it != orderedNodes.end(); ++it) {
+                       if ( (*it)->updateOffset(offset) )
+                               more = true;
+               }
+       } while ( more );
+       
+       // create trie stream
+       for (std::vector<Node*>::iterator it = orderedNodes.begin(); it != orderedNodes.end(); ++it) {
+               (*it)->appendToStream(output);
+       }
+}
+
+struct EntryWithOffset
+{
+       uintptr_t               nodeOffset;
+       Entry                   entry;
+       
+       bool operator<(const EntryWithOffset& other) const { return ( nodeOffset < other.nodeOffset ); }
+};
+
+
+
+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) 
+{
+       if ( p >= end )
+               throwf("malformed trie, node %p outside trie (%p -> %p)", p, start, end);
+       const uint8_t terminalSize = *p++;
+       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); 
+               output.push_back(e);
+       }
+       const uint8_t childrenCount = *children++;
+       const uint8_t* s = children;
+       for (uint8_t i=0; i < childrenCount; ++i) {
+               int edgeStrLen = 0;
+               while (*s != '\0') {
+                       cummulativeString[curStrOffset+edgeStrLen] = *s++;
+                       ++edgeStrLen;
+               }
+               cummulativeString[curStrOffset+edgeStrLen] = *s++;
+               uint32_t childNodeOffet = read_uleb128(s, end);
+               processExportNode(start, start+childNodeOffet, end, cummulativeString, curStrOffset+edgeStrLen, output);        
+       }
+}
+
+
+inline void parseTrie(const uint8_t* start, const uint8_t* end, std::vector<Entry>& output)
+{
+       // empty trie has no entries
+       if ( start == end )
+               return;
+       
+       char cummulativeString[4000];
+       std::vector<EntryWithOffset> entries;
+       processExportNode(start, start, end, cummulativeString, 0, entries);
+       // to preserve tie layout order, sort by node offset
+       std::sort(entries.begin(), entries.end());
+       // copy to output
+       output.reserve(entries.size());
+       for (std::vector<EntryWithOffset>::iterator it=entries.begin(); it != entries.end(); ++it)
+               output.push_back(it->entry);
+}
+
+
+
+
+}; // namespace trie
+}; // namespace mach_o
+
+
+#endif // __MACH_O_TRIE__
+
+
diff --git a/launch-cache/ObjCLegacyAbstraction.hpp b/launch-cache/ObjCLegacyAbstraction.hpp
new file mode 100644 (file)
index 0000000..ea0329b
--- /dev/null
@@ -0,0 +1,234 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2008 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@
+ */
+
+template <typename A>
+struct objc_image_info {
+    uint32_t version;
+    uint32_t flags;
+
+    void setFlag(uint32_t bits) INLINE { uint32_t old = A::P::E::get32(flags); A::P::E::set32(flags, old | bits); }
+    void setSelectorsPrebound() INLINE { setFlag(1<<3); }
+};
+
+template <typename A>
+struct objc_method {
+    uint32_t method_name;   // SEL
+    uint32_t method_types;  // char *
+    uint32_t method_imp;    // IMP     
+    
+    uint32_t getName() const INLINE { return A::P::E::get32(method_name); }
+    void setName(uint32_t newName) INLINE { A::P::E::set32(method_name, newName); }
+};
+
+template <typename A>
+struct objc_method_list {
+    enum { OBJC_FIXED_UP = 1771 };
+    uint32_t obsolete;      // struct objc_method_list *
+    uint32_t method_count;  // int
+    struct objc_method<A> method_list[0];
+    
+    uint32_t getCount() const INLINE { return A::P::E::get32(method_count); }
+    void setFixedUp(bool fixed) INLINE { A::P::E::set32(obsolete, fixed ? OBJC_FIXED_UP : 0); }
+};
+
+template <typename A>
+struct objc_class {
+    uint32_t isa;            // struct objc_class *
+    uint32_t super_class;    // struct objc_class *
+    uint32_t name;           // const char *
+    uint32_t version;        // long
+    uint32_t info;           // long
+    uint32_t instance_size;  // long
+    uint32_t ivars;          // struct objc_ivar_list *
+    uint32_t methodList;     // struct objc_method_list *
+    uint32_t method_cache;   // struct objc_cache *
+    uint32_t protocols;      // objc_protocol_list *
+    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)); }
+};
+
+template <typename A>
+struct objc_category {
+    uint32_t category_name;        // char *
+    uint32_t class_name;           // char *
+    uint32_t instance_methods;     // struct objc_method_list *
+    uint32_t class_methods;        // struct objc_method_list *
+    uint32_t protocols;            // objc_protocol_list *
+    uint32_t size;                 // uint32_t
+    uint32_t instance_properties;  // struct objc_property_list *
+    
+    struct objc_method_list<A> *getInstanceMethods(SharedCache<A> *cache) const INLINE { return (struct objc_method_list<A> *)cache->mappedCacheAddressForAddress(A::P::E::get32(instance_methods)); }
+    struct objc_method_list<A> *getClassMethods(SharedCache<A> *cache) const INLINE { return (struct objc_method_list<A> *)cache->mappedCacheAddressForAddress(A::P::E::get32(class_methods)); }
+};
+
+template <typename A>
+struct objc_symtab {
+    uint32_t sel_ref_cnt;  // unsigned long
+    uint32_t refs;         // SEL *
+    uint16_t cls_def_cnt;  // unsigned short
+    uint16_t cat_def_cnt;  // unsigned short
+    uint32_t defs[0];      // void *
+    
+    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])); }
+};
+
+template <typename A>
+struct objc_module {
+    uint32_t version;  // unsigned long
+    uint32_t size;     // unsigned long
+    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)); }
+};
+
+template <typename A>
+struct objc_method_description {
+    uint32_t name;   // SEL
+    uint32_t types;  // char *
+    
+    uint32_t getName() const INLINE { return A::P::E::get32(name); }
+    void setName(uint32_t newName) INLINE { A::P::E::set32(name, newName); }
+};
+
+template <typename A>
+struct objc_method_description_list {
+    uint32_t count;  // int
+    struct objc_method_description<A> list[0];
+    
+    uint32_t getCount() const INLINE { return A::P::E::get32(count); }
+};
+
+template <typename A>
+struct objc_protocol {
+    uint32_t isa;               // danger! contains strange values!
+    uint32_t protocol_name;     // const char *
+    uint32_t protocol_list;     // struct objc_protocol_list
+    uint32_t instance_methods;  // struct objc_method_description_list *
+    uint32_t class_methods;     // struct objc_method_description_list *
+    
+    struct objc_method_description_list<A> *getInstanceMethodDescriptions(SharedCache<A> *cache) const INLINE { return (struct objc_method_description_list<A> *)cache->mappedCacheAddressForAddress(A::P::E::get32(instance_methods)); }
+    struct objc_method_description_list<A> *getClassMethodDescriptions(SharedCache<A> *cache) const INLINE { return (struct objc_method_description_list<A> *)cache->mappedCacheAddressForAddress(A::P::E::get32(class_methods)); }
+};
+
+
+template <typename A, typename V>
+class LegacySelectorUpdater {
+
+    typedef typename A::P P;
+
+    static void visitMethodList(objc_method_list<A> *mlist, V& visitor)
+    {
+        for (uint32_t m = 0; m < mlist->getCount(); m++) {
+            uint64_t oldValue = mlist->method_list[m].getName();
+            uint64_t newValue = visitor.visit(oldValue);
+            mlist->method_list[m].setName(newValue);
+        }
+        mlist->setFixedUp(true);
+    }
+
+    static void visitMethodDescriptionList(objc_method_description_list<A> *mlist, V& visitor)
+    {
+        for (uint32_t m = 0; m < mlist->getCount(); m++) {
+            uint64_t oldValue = mlist->list[m].getName();
+            uint64_t newValue = visitor.visit(oldValue);
+            mlist->list[m].setName(newValue);
+        }
+    }
+
+public:
+
+    static void update(SharedCache<A>* cache, const macho_header<P>* header, 
+                       V& visitor)
+    {
+        ArraySection<A, objc_module<A> > 
+            modules(cache, header, "__OBJC", "__module_info");
+        for (uint64_t m = 0; m < modules.count(); m++) {
+            objc_symtab<A> *symtab = modules.get(m).getSymtab(cache);
+            if (!symtab) continue;
+
+            // Method lists in classes
+            for (uint64_t c = 0; c < symtab->getClassCount(); c++) {
+                objc_class<A> *cls = symtab->getClass(cache, c);
+                objc_class<A> *isa = cls->getIsa(cache);
+                objc_method_list<A> *mlist;
+                if ((mlist = cls->getMethodList(cache))) {
+                    visitMethodList(mlist, visitor);
+                }
+                if ((mlist = isa->getMethodList(cache))) {
+                    visitMethodList(mlist, visitor);
+                }
+            }
+            
+            // Method lists from categories
+            for (uint64_t c = 0; c < symtab->getCategoryCount(); c++) {
+                objc_category<A> *cat = symtab->getCategory(cache, c);
+                objc_method_list<A> *mlist;
+                if ((mlist = cat->getInstanceMethods(cache))) {
+                    visitMethodList(mlist, visitor);
+                }
+                if ((mlist = cat->getClassMethods(cache))) {
+                    visitMethodList(mlist, visitor);
+                }
+            }
+        }
+
+        // Method description lists from protocols        
+        ArraySection<A, objc_protocol<A> > 
+            protocols(cache, header, "__OBJC", "__protocol");
+        for (uint64_t p = 0; p < protocols.count(); p++) {
+            objc_protocol<A>& protocol = protocols.get(p);
+            objc_method_description_list<A> *mlist;
+            if ((mlist = protocol.getInstanceMethodDescriptions(cache))) {
+                visitMethodDescriptionList(mlist, visitor);
+            }
+            if ((mlist = protocol.getClassMethodDescriptions(cache))) {
+                visitMethodDescriptionList(mlist, visitor);
+            }
+        }
+
+        // Message refs
+        PointerSection<A, const char *> selrefs(cache, header, "__OBJC", "__message_refs");
+        for (uint64_t s = 0; s < selrefs.count(); s++) {
+            uint64_t oldValue = selrefs.getUnmapped(s);
+            uint64_t newValue = visitor.visit(oldValue);
+            selrefs.set(s, newValue);
+        }
+
+        // Mark image_info
+        const macho_section<P> *imageInfoSection = 
+            header->getSection("__OBJC", "__image_info");
+        if (imageInfoSection) {
+            objc_image_info<A> *info = (objc_image_info<A> *)
+                cache->mappedCacheAddressForAddress(imageInfoSection->addr());
+            info->setSelectorsPrebound();
+        }
+    }
+};
diff --git a/launch-cache/ObjCModernAbstraction.hpp b/launch-cache/ObjCModernAbstraction.hpp
new file mode 100644 (file)
index 0000000..ef200a5
--- /dev/null
@@ -0,0 +1,265 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2008 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@
+ */
+
+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
+
+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); }
+};
+
+template <typename A>
+class objc_method_list_t {
+    uint32_t entsize;
+    uint32_t count;
+    objc_method_t<A> first;
+
+       uint32_t getEntsize() const { return A::P::E::get32(entsize) & ~(uint32_t)3; }
+
+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()); }
+
+    void setFixedUp() { A::P::E::set32(entsize, getEntsize() | 3); }
+};
+
+template <typename A>
+class objc_ivar_t {
+    typename A::P::uint_t offset;  // A::P *
+    typename A::P::uint_t name;    // const char *
+    typename A::P::uint_t type;    // const char *
+    uint32_t alignment; 
+    uint32_t size;
+};
+
+template <typename A>
+class objc_ivar_list_t {
+    uint32_t entsize;
+    uint32_t count;
+    objc_ivar_t<A> first;
+
+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)); }
+};
+
+template <typename A>
+class objc_protocol_t {
+    typename A::P::uint_t isa;
+    typename A::P::uint_t name;
+    typename A::P::uint_t protocols;
+    typename A::P::uint_t instanceMethods;
+    typename A::P::uint_t classMethods;
+    typename A::P::uint_t optionalInstanceMethods;
+    typename A::P::uint_t optionalClassMethods;
+    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)); }
+
+    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> *getOptionalClassMethods(SharedCache<A>* cache) const { return (objc_method_list_t<A> *)cache->mappedCacheAddressForAddress(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];
+};
+
+template < typename P, typename E > 
+struct pad { };
+
+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
+
+    typename A::P::uint_t ivarLayout;
+    typename A::P::uint_t name;
+    typename A::P::uint_t baseMethods;
+    typename A::P::uint_t baseProtocols;
+    typename A::P::uint_t ivars;
+    typename A::P::uint_t weakIvarLayout;
+    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)); }
+};
+
+template <typename A>
+class objc_class_t {
+    typename A::P::uint_t isa;
+    typename A::P::uint_t superclass;
+    typename A::P::uint_t method_cache;
+    typename A::P::uint_t vtable;
+    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_data_t<A> *getData(SharedCache<A>* cache) const { return (objc_class_data_t<A> *)cache->mappedCacheAddressForAddress(A::P::getP(data)); }
+
+    objc_method_list_t<A> *getMethodList(SharedCache<A>* cache) const { return getData(cache)->getMethodList(cache); }
+};
+
+
+
+template <typename A>
+class objc_category_t {
+    typename A::P::uint_t name;
+    typename A::P::uint_t cls;
+    typename A::P::uint_t instanceMethods;
+    typename A::P::uint_t classMethods;
+    typename A::P::uint_t protocols;
+    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)); }
+};
+
+template <typename A>
+class objc_message_ref_t {
+    typename A::P::uint_t imp;
+    typename A::P::uint_t sel;
+
+public:
+    typename A::P::uint_t getName() const { return A::P::getP(sel); }
+
+    void setName(typename A::P::uint_t newName) { A::P::setP(sel, newName); }
+};
+
+template <typename A, typename V>
+class SelectorUpdater {
+
+    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();
+    }
+
+public:
+
+    static void update(SharedCache<A>* cache, const macho_header<P>* header, 
+                       V& visitor)
+    {
+        // 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);
+            }
+            if ((mlist = cls->getIsa(cache)->getMethodList(cache))) {
+                visitMethodList(mlist, visitor);
+            }
+        }
+        
+        // Method lists from categories
+        PointerSection<A, objc_category_t<A> *> 
+            cats(cache, header, "__DATA", "__objc_catlist");
+        for (pint_t i = 0; i < cats.count(); i++) {
+            objc_category_t<A> *cat = cats.get(i);
+            objc_method_list_t<A> *mlist;
+            if ((mlist = cat->getInstanceMethods(cache))) {
+                visitMethodList(mlist, visitor);
+            }
+            if ((mlist = cat->getClassMethods(cache))) {
+                visitMethodList(mlist, visitor);
+            }
+        }
+
+        // Method description lists from protocols
+        PointerSection<A, objc_protocol_t<A> *> 
+            protocols(cache, header, "__DATA", "__objc_protolist");
+        for (pint_t i = 0; i < protocols.count(); i++) {
+            objc_protocol_t<A> *proto = protocols.get(i);
+            objc_method_list_t<A> *mlist;
+            if ((mlist = proto->getInstanceMethods(cache))) {
+                visitMethodList(mlist, visitor);
+            }
+            if ((mlist = proto->getClassMethods(cache))) {
+                visitMethodList(mlist, visitor);
+            }
+            if ((mlist = proto->getOptionalInstanceMethods(cache))) {
+                visitMethodList(mlist, visitor);
+            }
+            if ((mlist = proto->getOptionalClassMethods(cache))) {
+                visitMethodList(mlist, visitor);
+            }
+        }
+
+        // @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);
+            selrefs.set(i, newValue);
+        }
+
+        // message references
+        ArraySection<A, objc_message_ref_t<A> > 
+            msgrefs(cache, header, "__DATA", "__objc_msgrefs");
+        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);
+            msg.setName(newValue);
+        }
+
+        // Mark image_info
+        const macho_section<P> *imageInfoSection = 
+            header->getSection("__DATA", "__objc_imageinfo");
+        if (imageInfoSection) {
+            objc_image_info<A> *info = (objc_image_info<A> *)
+                cache->mappedCacheAddressForAddress(imageInfoSection->addr());
+            info->setSelectorsPrebound();
+        }
+    }
+};
diff --git a/launch-cache/com.apple.dyld.plist b/launch-cache/com.apple.dyld.plist
deleted file mode 100644 (file)
index c059670..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>Label</key>                
-       <string>com.apple.dyld</string>
-       <key>Program</key>              
-       <string>/usr/bin/update_dyld_shared_cache</string>
-       <key>MachServices</key>
-       <dict>
-               <key>com.apple.dyld</key>
-               <true/>
-       </dict>
-       <key>Nice</key>
-       <integer>10</integer>
-       <key>LowPriorityIO</key>
-       <true/>
-       <key>EnvironmentVariables</key>
-       <dict>
-               <key>DYLD_NO_FIX_PREBINDING</key>
-               <string>1</string>
-       </dict>
-</dict>
-</plist>
diff --git a/launch-cache/dsc_iterator.cpp b/launch-cache/dsc_iterator.cpp
new file mode 100644 (file)
index 0000000..5110cbc
--- /dev/null
@@ -0,0 +1,107 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * 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>
+
+#include "dsc_iterator.h"
+#include "dyld_cache_format.h"
+#define NO_ULEB
+#include "Architectures.hpp"
+#include "MachOFileAbstraction.hpp"
+#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)
+       {
+               const dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)cache;
+               const dyldCacheFileMapping<E>* mappings = (dyldCacheFileMapping<E>*)&cache[header->mappingOffset()];
+               for (uint32_t i=0; i < header->mappingCount(); ++i) {
+                       if ( (mappings[i].address() <= addr) &&  (addr < (mappings[i].address() + mappings[i].size())) ) {
+                               return &cache[mappings[i].file_offset() + addr - mappings[i].address()];
+                       }
+               }
+               return NULL;
+       }
+
+       // call the callback block on each segment in this image                                                          
+       template <typename A>
+       void walkSegments(const uint8_t* cache, const char* dylibPath, const uint8_t* machHeader, dyld_shared_cache_iterator_t callback) 
+       {
+               typedef typename A::P           P;      
+               typedef typename A::P::E        E;      
+               const macho_header<P>* mh = (const macho_header<P>*)machHeader;
+               const macho_load_command<P>* const cmds = (macho_load_command<P>*)(machHeader + sizeof(macho_header<P>));
+               const uint32_t cmd_count = mh->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>* 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());
+                       }
+                       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) 
+       {
+               typedef typename A::P::E   E;   
+               const dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)cache;
+               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);
+               }
+               return 0;
+       }
+
+}
+
+
+// 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.
+int dyld_shared_cache_iterate_segments(const void* shared_cache_file, dyld_shared_cache_iterator_t callback)
+{
+       const uint8_t* cache = (uint8_t*)shared_cache_file;
+                if ( strcmp((char*)cache, "dyld_v1    i386") == 0 ) 
+                       return dyld::walkImages<x86>(cache, callback);
+       else if ( strcmp((char*)cache, "dyld_v1  x86_64") == 0 ) 
+                       return dyld::walkImages<x86_64>(cache, callback);
+       else if ( strcmp((char*)cache, "dyld_v1     ppc") == 0 ) 
+                       return dyld::walkImages<ppc>(cache, callback);
+       else
+               return -1;
+}
+
diff --git a/launch-cache/dsc_iterator.h b/launch-cache/dsc_iterator.h
new file mode 100644 (file)
index 0000000..418eece
--- /dev/null
@@ -0,0 +1,42 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * 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 <stdint.h>
+
+#ifdef __cplusplus
+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);
+
+       
+#ifdef __cplusplus
+}
+#endif 
index c13ff7fedd9ab1de80bb30ed606c08a482c5a371..748fff56bdd24b1c51280052fce00002a0914bab 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
- * Copyright (c) 2006-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2006-2008 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -26,7 +26,7 @@
 
 #include <sys/types.h>
 #include <stdint.h>
-#include <mach/shared_memory_server.h>
+#include <mach/shared_region.h>
 
 
  struct dyld_cache_header
diff --git a/launch-cache/dyld_shared_cache.defs b/launch-cache/dyld_shared_cache.defs
deleted file mode 100644 (file)
index 4914364..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#include <mach/std_types.defs>
-#include <mach/mach_types.defs>
-
-type cpu_type_t = int;
-
-subsystem dyld_server 10000;
-serverprefix do_;
-
-simpleroutine dyld_shared_cache_missing(
-                               dyld_port       : mach_port_t;
-                               arch            : cpu_type_t;
-       SendTime    sendTimeout : natural_t);
-
-
-simpleroutine dyld_shared_cache_out_of_date(
-                               dyld_port       : mach_port_t;
-                               arch            : cpu_type_t;
-       SendTime    sendTimeout : natural_t);
-
index b0060d440121f05abda3c281ce311a15c7c91918..704aa81c133c9168b5ce72ac1d92e7139ae2ee9b 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
- * Copyright (c) 2006-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2006-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -26,6 +26,7 @@
 #include <sys/stat.h>
 #include <sys/mman.h>
 #include <mach/mach.h>
+#include <mach/mach_time.h>
 #include <limits.h>
 #include <stdarg.h>
 #include <stdio.h>
@@ -43,6 +44,8 @@
 #include <servers/bootstrap.h>
 #include <mach-o/loader.h>
 #include <mach-o/fat.h>
+#include <vproc.h>
+#include <vproc_priv.h>
 
 #include "dyld_cache_format.h"
 
 #include "MachOBinder.hpp"
 #include "CacheFileAbstraction.hpp"
 
-extern "C" { 
-       #include "dyld_shared_cache_server.h"
-}
+#define SELOPT_WRITE
+#include <objc/objc-selopt.h>
 
 
 static bool                                                    verbose = false;
+static bool                                                    progress = false;
 static std::vector<const char*>                warnings;
 
 
+static void warn(const char *arch, const char *format, ...)
+{
+    char *msg;
+
+    va_list args;
+    va_start(args, format);
+    ::vasprintf(&msg, format, args);
+    va_end(args);
+    
+    warnings.push_back(msg);
+    
+    if ( verbose ) {
+        ::fprintf(::stderr, "update_dyld_shared_cache: warning: %s%s%s%s\n", 
+                  arch ? "for arch " : "", 
+                  arch ? arch : "", 
+                  arch ? ", " : "", 
+                  msg);
+    }
+}
+
+
 static uint64_t pageAlign(uint64_t addr) { return ( (addr + 4095) & (-4096) ); }
 
 class ArchGraph
 {
 public:
-       static void                     addArch(cpu_type_t arch);
-       static void                     addRoot(const char* vpath, const std::set<cpu_type_t>& archs);
-       static void                     findSharedDylibs(cpu_type_t arch);
-       static ArchGraph*       getArch(cpu_type_t arch) { return fgPerArchGraph[arch]; }
-       static void                     setFileSystemRoot(const char* root) { fgFileSystemRoot = root; }
-       static const char*      archName(cpu_type_t arch);
+       static void                     addArchPair(ArchPair ap);
+       static void                     addRoot(const char* vpath, const std::set<ArchPair>& archs);
+       static void                     findSharedDylibs(ArchPair ap);
+       static ArchGraph*       graphForArchPair(ArchPair ap) { return fgPerArchGraph[ap]; }
+       static void                     setFileSystemRoot(const char* root, bool usesOverlay) { fgFileSystemRoot = root; fgUsesOverlay = usesOverlay; }
+       static const char*      archName(ArchPair ap);
        
-       cpu_type_t                                                                                      getArch() { return fArch; }
+       ArchPair                                                                                        getArchPair() { return fArchPair; }
        std::set<const class MachOLayoutAbstraction*>&          getSharedDylibs() { return fSharedDylibs; }
+       const char*                                                                                     archName() { return archName(fArchPair); }
        
 private:
        
@@ -109,62 +134,74 @@ private:
        typedef __gnu_cxx::hash_map<const char*, class DependencyNode*, __gnu_cxx::hash<const char*>, CStringEquals> PathToNode;
 
 
-                                                               ArchGraph(cpu_type_t arch) : fArch(arch) {}
-       static void                                     addRootForArch(const char* path, const MachOLayoutAbstraction*);
+                                                               ArchGraph(ArchPair ap) : fArchPair(ap) {}
        void                                            addRoot(const char* path, const MachOLayoutAbstraction*);
        DependencyNode*                         getNode(const char* path);
        DependencyNode*                         getNodeForVirtualPath(const char* vpath);
-       static bool                                     canBeShared(const MachOLayoutAbstraction* layout, cpu_type_t arch, const std::set<const MachOLayoutAbstraction*>& possibleLibs, std::map<const MachOLayoutAbstraction*, bool>& shareableMap);
+       static bool                                     canBeShared(const MachOLayoutAbstraction* layout, ArchPair ap, const std::set<const MachOLayoutAbstraction*>& possibleLibs, std::map<const MachOLayoutAbstraction*, bool>& shareableMap);
 
-       static std::map<cpu_type_t, ArchGraph*> fgPerArchGraph;
+       static std::map<ArchPair, ArchGraph*>   fgPerArchGraph;
        static const char*                                              fgFileSystemRoot;
+       static bool                                                             fgUsesOverlay;
        
-       cpu_type_t                                                                      fArch;
+       ArchPair                                                                        fArchPair;
        std::set<DependencyNode*>                                       fRoots;
        PathToNode                                                                      fNodes;
        std::set<const MachOLayoutAbstraction*>         fSharedDylibs;  // use set to avoid duplicates when installname!=realpath
 };
-std::map<cpu_type_t, ArchGraph*>       ArchGraph::fgPerArchGraph;
+std::map<ArchPair, ArchGraph*>         ArchGraph::fgPerArchGraph;
 const char*                                                    ArchGraph::fgFileSystemRoot = "";
+bool                                                           ArchGraph::fgUsesOverlay = false;
 
-void ArchGraph::addArch(cpu_type_t arch)
+void ArchGraph::addArchPair(ArchPair ap)
 {
-       //fprintf(stderr, "adding arch 0x%08X\n", arch);
-       fgPerArchGraph[arch] = new ArchGraph(arch);
+       //fprintf(stderr, "adding ArchPair 0x%08X,0x%08X\n", ap.arch, ap.subtype);
+       fgPerArchGraph[ap] = new ArchGraph(ap);
 }
 
-void ArchGraph::addRoot(const char* vpath, const std::set<cpu_type_t>& archs)
+void ArchGraph::addRoot(const char* vpath, const std::set<ArchPair>& onlyArchs)
 {
        char completePath[strlen(fgFileSystemRoot)+strlen(vpath)+2];
-       const char* path;
+       const char* path = NULL;
        if ( strlen(fgFileSystemRoot) == 0 ) {
                path = vpath;
        }
        else {
                strcpy(completePath, fgFileSystemRoot);
                strcat(completePath, vpath);    // assumes vpath starts with '/'
-               path = completePath;
+               if ( fgUsesOverlay ) {
+                       // using -overlay means if /overlay/usr/lib exists use it, otherwise use original path
+                       struct stat stat_buf;
+                       if ( stat(completePath, &stat_buf) == 0 )
+                               path = completePath;
+                       else
+                               path = vpath;
+               }
+               else {
+                       // using -root means alway redirect /usr/lib to /rootpath/usr/lib
+                       path = completePath;
+               }
        }
        try {
-               const UniversalMachOLayout* uni = UniversalMachOLayout::find(path, &archs);
-               const std::vector<MachOLayoutAbstraction*>& layouts = uni->getArchs();
-               for(std::vector<MachOLayoutAbstraction*>::const_iterator it = layouts.begin(); it != layouts.end(); ++it) {
-                       const MachOLayoutAbstraction* layout = *it;
-                       if ( archs.count(layout->getArchitecture()) > 0 )
-                               ArchGraph::addRootForArch(path, layout);
+               const UniversalMachOLayout& uni = UniversalMachOLayout::find(path, &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);
+                       }
+                       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);
+                       }
+                       
                }
-               // don't delete uni, it is owned by UniversalMachOLayout cache
        }
        catch (const char* msg) {
                fprintf(stderr, "update_dyld_shared_cache: warning can't use root %s: %s\n", path, msg);
        }
 }
 
-void ArchGraph::addRootForArch(const char* path, const MachOLayoutAbstraction* layout)
-{
-       ArchGraph* graph = fgPerArchGraph[layout->getArchitecture()];
-       graph->addRoot(path, layout);
-}
+
 
 void ArchGraph::addRoot(const char* path, const MachOLayoutAbstraction* layout)
 {
@@ -191,7 +228,18 @@ ArchGraph::DependencyNode* ArchGraph::getNodeForVirtualPath(const char* vpath)
                char completePath[strlen(fgFileSystemRoot)+strlen(vpath)+2];
                strcpy(completePath, fgFileSystemRoot);
                strcat(completePath, vpath);    // assumes vpath starts with '/'
-               return this->getNode(completePath);
+               if ( fgUsesOverlay ) {
+                       // using -overlay means if /overlay/usr/lib exists use it, otherwise use original path
+                       struct stat stat_buf;
+                       if ( stat(completePath, &stat_buf) == 0 )
+                               return this->getNode(completePath);
+                       else
+                               return this->getNode(vpath);
+               }
+               else {
+                       // using -root means always use /rootpath/usr/lib
+                       return this->getNode(completePath);
+               }
        }
 }
 
@@ -213,10 +261,10 @@ ArchGraph::DependencyNode* ArchGraph::getNode(const char* path)
                return pos->second;
        
        // still does not exist, so create a new node
-       const UniversalMachOLayout* uni = UniversalMachOLayout::find(realPath);
-       DependencyNode* node = new DependencyNode(this, realPath, uni->getArch(fArch));
+       const UniversalMachOLayout& uni = UniversalMachOLayout::find(realPath);
+       DependencyNode* node = new DependencyNode(this, realPath, uni.getSlice(fArchPair));
        if ( node->getLayout() == NULL ) {
-               throwf("%s is missing arch %s", realPath, archName(fArch));
+               throwf("%s is missing arch %s", realPath, archName(fArchPair));
        }
        // add realpath to node map
        fNodes[node->getPath()] = node;
@@ -269,8 +317,14 @@ void ArchGraph::DependencyNode::loadDependencies(const MachOLayoutAbstraction* m
                                fDependsOn.insert(fGraph->getNodeForVirtualPath(dependentPath));
                        }
                        catch (const char* msg) {
-                               fprintf(stderr, "warning, could not bind %s because %s\n", fPath, msg);
-                               fDependentMissing = true;
+                               if ( it->weakImport && ! fLayout->hasSplitSegInfo() ) {
+                                       // ok to ignore missing weak imported dylibs from things that are
+                                       // not going to be in the dyld shared cache
+                               }
+                               else {
+                                       fprintf(stderr, "warning, could not bind %s because %s\n", fPath, msg);
+                                       fDependentMissing = true;
+                               }
                        }
                }
                // recurse
@@ -297,46 +351,61 @@ ArchGraph::DependencyNode::DependencyNode(ArchGraph* graph, const char* path, co
        //fprintf(stderr, "new DependencyNode(0x%08X, %s)\n", graph->fArch, path);
 }
 
-void ArchGraph::findSharedDylibs(cpu_type_t arch)
+void ArchGraph::findSharedDylibs(ArchPair ap)
 {
-       const PathToNode& nodes = fgPerArchGraph[arch]->fNodes;
+       const PathToNode& nodes = fgPerArchGraph[ap]->fNodes;
        std::set<const MachOLayoutAbstraction*> possibleLibs;
        //fprintf(stderr, "shared for arch 0x%08X\n", arch);
        for(PathToNode::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
                DependencyNode* node = it->second;
-               if ( node->allDependentsFound() && (node->useCount() > 1) ) {
-                       if ( node->getLayout()->hasSplitSegInfo() ) 
-                               possibleLibs.insert(node->getLayout());
+               // <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);
                }
        }
        
        // prune so that all shareable libs depend only on other shareable libs
-       std::set<const MachOLayoutAbstraction*>& sharedLibs = fgPerArchGraph[arch]->fSharedDylibs;
+       std::set<const MachOLayoutAbstraction*>& sharedLibs = fgPerArchGraph[ap]->fSharedDylibs;
        std::map<const MachOLayoutAbstraction*,bool> shareableMap;
        for (std::set<const MachOLayoutAbstraction*>::iterator lit = possibleLibs.begin(); lit != possibleLibs.end(); ++lit) {
-               if ( canBeShared(*lit, arch, possibleLibs, shareableMap) )
+               if ( canBeShared(*lit, ap, possibleLibs, shareableMap) )
                        sharedLibs.insert(*lit);
        }
 }
 
-const char*    ArchGraph::archName(cpu_type_t arch)
+const char*    ArchGraph::archName(ArchPair ap)
 {
-       switch ( arch ) {
+       switch ( ap.arch ) {
                case CPU_TYPE_POWERPC:
                        return "ppc";
-               case CPU_TYPE_POWERPC64:
-                       return "ppc64";
                case CPU_TYPE_I386:
                        return "i386";
                case CPU_TYPE_X86_64:
                        return "x86_64";
+               case CPU_TYPE_ARM:
+                       switch ( ap.subtype ) {
+                               case CPU_SUBTYPE_ARM_V4T:
+                                       return "armv4t";
+                               case CPU_SUBTYPE_ARM_V6:
+                                       return "armv6";
+                               case CPU_SUBTYPE_ARM_V5TEJ:
+                                       return "armv5";
+                               case CPU_SUBTYPE_ARM_XSCALE:
+                                       return "arm-xscale";
+                               case CPU_SUBTYPE_ARM_V7:
+                                       return "armv7";
+                               default:
+                                       return "arm";
+                       }
                default:
                        return "unknown";
        }
 }
 
-bool ArchGraph::canBeShared(const MachOLayoutAbstraction* layout, cpu_type_t arch, const std::set<const MachOLayoutAbstraction*>& possibleLibs, std::map<const MachOLayoutAbstraction*, bool>& shareableMap)
+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
        std::map<const MachOLayoutAbstraction*, bool>::iterator mapPos = shareableMap.find(layout);
@@ -348,37 +417,47 @@ bool ArchGraph::canBeShared(const MachOLayoutAbstraction* layout, cpu_type_t arc
                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", layout->getID().name);
+                       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);
                warnings.push_back(msg);
                if ( verbose )
-                       fprintf(stderr, "update_dyld_shared_cache: for arch %s, %s\n", archName(arch), msg);
+                       fprintf(stderr, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap), msg);
                return false;
        }
        // look recursively
        shareableMap[layout] = true; // mark this shareable early in case of circular references
-       const PathToNode& nodes = fgPerArchGraph[arch]->fNodes;
+       const PathToNode& nodes = fgPerArchGraph[ap]->fNodes;
        const std::vector<MachOLayoutAbstraction::Library>&     dependents = layout->getLibraries();
        for (std::vector<MachOLayoutAbstraction::Library>::const_iterator dit = dependents.begin(); dit != dependents.end(); ++dit) {
                PathToNode::const_iterator pos = nodes.find(dit->name);
                if ( pos == nodes.end() ) {
+                       // path from load command does not match any loaded dylibs, maybe there is a temp symlink
+                       char realPath[MAXPATHLEN];
+                       if ( realpath(dit->name, realPath) != NULL ) {
+                               if ( nodes.find(realPath) != nodes.end() )
+                                       continue;
+                       }
                        shareableMap[layout] = false;
                        char* msg;
                        asprintf(&msg, "can't put %s in shared cache because it depends on %s which can't be found", layout->getID().name, dit->name);
                        warnings.push_back(msg);
                        if ( verbose )
-                               fprintf(stderr, "update_dyld_shared_cache: for arch %s, %s\n", archName(arch), msg);
+                               fprintf(stderr, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap), msg);
                        return false;
                }
                else {
-                       if ( ! canBeShared(pos->second->getLayout(), arch, possibleLibs, shareableMap) ) {
+                       if ( ! canBeShared(pos->second->getLayout(), ap, possibleLibs, shareableMap) ) {
                                shareableMap[layout] = false;
                                char* msg;
                                asprintf(&msg, "can't put %s in shared cache because it depends on %s which can't be in shared cache", layout->getID().name, dit->name);
                                warnings.push_back(msg);
                                if ( verbose )
-                                       fprintf(stderr, "update_dyld_shared_cache: for arch %s, %s\n", archName(arch), msg);
+                                       fprintf(stderr, "update_dyld_shared_cache: for arch %s, %s\n", archName(ap), msg);
                                return false;
                        }
                }
@@ -391,16 +470,22 @@ template <typename A>
 class SharedCache
 {
 public:
-                                                       SharedCache(ArchGraph* graph, bool alphaSort, uint64_t dyldBaseAddress);
-       bool                                    update(const char* rootPath, const char* cacheDir, bool force, bool optimize, bool deleteExistingFirst, int archIndex, int archCount);
-       static const char*              filename(bool optimized);
+                                                       SharedCache(ArchGraph* graph, const char* rootPath, 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);
 
 private:
-       typedef typename A::P::E        E;
+       typedef typename A::P                   P;
+    typedef typename A::P::E           E;
+    typedef typename A::P::uint_t      pint_t;
 
-       bool                                    notUpToDate(const char* cachePath);
+       bool                                    notUpToDate(const char* path);
        bool                                    notUpToDate(const void* cache);
-       uint8_t*                                optimizeLINKEDIT();
+       uint8_t*                                optimizeLINKEDIT(bool keepSignatures);
+       void                                    optimizeObjC();
 
        static void                             getSharedCacheBasAddresses(cpu_type_t arch, uint64_t* baseReadOnly, uint64_t* baseWritable);
        static cpu_type_t               arch();
@@ -425,75 +510,180 @@ private:
                                { return (strcmp(left.layout->getID().name, right.layout->getID().name) < 0); }
        };
 
-       struct RandomSorter {
-               RandomSorter(const std::vector<LayoutInfo>& infos) {
-                       for(typename std::vector<struct LayoutInfo>::const_iterator it = infos.begin(); it != infos.end(); ++it) 
-                               fMap[it->layout] = arc4random();
-               }
+    struct ByCStringSectionSizeSorter {
+        bool operator()(const LayoutInfo& left, const LayoutInfo& right) {
+            const std::vector<MachOLayoutAbstraction::Segment>& segs_l =
+                left.layout->getSegments();
+            const std::vector<MachOLayoutAbstraction::Segment>& segs_r = 
+                right.layout->getSegments();
+            if (segs_l.size() == 0  ||  segs_r.size() == 0) {
+                // 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_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) {
+                // one image has no cstrings
+                return cstring_l && !cstring_r;
+            }
+
+            return cstring_l->size() > cstring_r->size();
+        }
+    };
+
+       struct Sorter {
+               Sorter(std::map<const MachOLayoutAbstraction*, uint32_t>& map): fMap(map) {}
                bool operator()(const LayoutInfo& left, const LayoutInfo& right) {
                        return (fMap[left.layout] < fMap[right.layout]); 
                }
        private:
-               std::map<const MachOLayoutAbstraction*, uint32_t> fMap;
+               std::map<const MachOLayoutAbstraction*, uint32_t>& fMap;
        };
        
 
        ArchGraph*                                                      fArchGraph;
+       const bool                                                      fVerify;
+       bool                                                            fExistingIsNotUpToDate;
+       const char*                                                     fCacheFilePath;
+       uint8_t*                                                        fExistingCacheForVerification;
        std::vector<LayoutInfo>                         fDylibs;
        std::vector<shared_file_mapping_np>     fMappings;
        uint32_t                                                        fHeaderSize;
+    uint8_t*                                                   fInMemoryCache;
        uint64_t                                                        fDyldBaseAddress;
        uint64_t                                                        fLinkEditsTotalUnoptimizedSize;
        uint64_t                                                        fLinkEditsStartAddress;
        MachOLayoutAbstraction::Segment*        fFirstLinkEditSegment;
+       uint32_t                                                        fOffsetOfBindInfoInCombinedLinkedit;
+       uint32_t                                                        fOffsetOfWeakBindInfoInCombinedLinkedit;
+       uint32_t                                                        fOffsetOfLazyBindInfoInCombinedLinkedit;
+       uint32_t                                                        fOffsetOfExportInfoInCombinedLinkedit;
+       uint32_t                                                        fOffsetOfOldSymbolTableInfoInCombinedLinkedit;
+       uint32_t                                                        fLinkEditsTotalOptimizedSize;
+};
+
+
+// Access a section containing a list of pointers
+template <typename A, typename T>
+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;
+
+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)
+        , fCount(fSection ? fSection->size() / sizeof(pint_t) : 0)
+    {
+    }
+
+    uint64_t count() const { return fCount; }
+
+    uint64_t getUnmapped(uint64_t index) const {
+        if (index >= fCount) throwf("index out of range");
+        return P::getP(fBase[index]);
+    }
+
+    T get(uint64_t index) const { 
+        return (T)fCache->mappedCacheAddressForAddress(getUnmapped(index));
+    }
+
+    void set(uint64_t index, uint64_t value) {
+        if (index >= fCount) throwf("index out of range");
+        P::setP(fBase[index], value);
+    }
+};
+
+// Access a section containing an array of structures
+template <typename A, typename T>
+class ArraySection 
+{
+    typedef typename A::P P;
+
+    SharedCache<A>* const fCache;
+    const macho_section<P>* const fSection;
+    T * const fBase;
+    uint64_t const fCount;
+
+public:
+    ArraySection(SharedCache<A>* cache, const macho_header<P>* header, 
+                 const char *segname, const char *sectname)
+        : fCache(cache)
+        , fSection(header->getSection(segname, sectname))
+        , fBase(fSection ? (T *)cache->mappedCacheAddressForAddress(fSection->addr()) : 0)
+        , fCount(fSection ? fSection->size() / sizeof(T) : 0)
+    {
+    }
+
+    uint64_t count() const { return fCount; }
+
+    T& get(uint64_t index) const { 
+        if (index >= fCount) throwf("index out of range");
+        return fBase[index];
+    }
 };
 
 
+// GrP fixme
+#include "ObjCLegacyAbstraction.hpp"
+#include "ObjCModernAbstraction.hpp"
+
 
        
 template <>     cpu_type_t     SharedCache<ppc>::arch()        { return CPU_TYPE_POWERPC; }
-template <>     cpu_type_t     SharedCache<ppc64>::arch()      { return CPU_TYPE_POWERPC64; }
 template <>     cpu_type_t     SharedCache<x86>::arch()        { return CPU_TYPE_I386; }
 template <>     cpu_type_t     SharedCache<x86_64>::arch()     { return CPU_TYPE_X86_64; }
+template <>     cpu_type_t     SharedCache<arm>::arch()        { return CPU_TYPE_ARM; }
 
 template <>     uint64_t       SharedCache<ppc>::sharedRegionReadOnlyStartAddress()    { return 0x90000000; }
-template <>     uint64_t       SharedCache<ppc64>::sharedRegionReadOnlyStartAddress()  { return 0x7FFF80000000LL; }
 template <>     uint64_t       SharedCache<x86>::sharedRegionReadOnlyStartAddress()    { return 0x90000000; }
 template <>     uint64_t       SharedCache<x86_64>::sharedRegionReadOnlyStartAddress() { return 0x7FFF80000000LL; }
+template <>     uint64_t       SharedCache<arm>::sharedRegionReadOnlyStartAddress()    { return 0x30000000; }
 
 template <>     uint64_t       SharedCache<ppc>::sharedRegionWritableStartAddress()    { return 0xA0000000; }
-template <>     uint64_t       SharedCache<ppc64>::sharedRegionWritableStartAddress()  { return 0x7FFF70000000LL; }
 template <>     uint64_t       SharedCache<x86>::sharedRegionWritableStartAddress()    { return 0xA0000000; }
 template <>     uint64_t       SharedCache<x86_64>::sharedRegionWritableStartAddress() { return 0x7FFF70000000LL; }
+template <>     uint64_t       SharedCache<arm>::sharedRegionWritableStartAddress()    { return 0x38000000; }
 
 template <>     uint64_t       SharedCache<ppc>::sharedRegionReadOnlySize()                    { return 0x10000000; }
-template <>     uint64_t       SharedCache<ppc64>::sharedRegionReadOnlySize()                  { return 0x7FE00000; }
 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<ppc>::sharedRegionWritableSize()                    { return 0x10000000; }
-template <>     uint64_t       SharedCache<ppc64>::sharedRegionWritableSize()                  { return 0x20000000; }
 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 <>     const char*    SharedCache<ppc>::archName()    { return "ppc"; }
-template <>     const char*    SharedCache<ppc64>::archName()  { return "ppc64"; }
 template <>     const char*    SharedCache<x86>::archName()    { return "i386"; }
 template <>     const char*    SharedCache<x86_64>::archName() { return "x86_64"; }
+template <>     const char*    SharedCache<arm>::archName()    { return "arm"; }
 
-template <>     const char*    SharedCache<ppc>::filename(bool optimized)      { return optimized ? "ppc" : "rosetta"; }
-template <>     const char*    SharedCache<ppc64>::filename(bool)      { return "ppc64"; }
-template <>     const char*    SharedCache<x86>::filename(bool)        { return "i386"; }
-template <>     const char*    SharedCache<x86_64>::filename(bool)     { return "x86_64"; }
+template <>     const char*    SharedCache<ppc>::cacheFileSuffix(bool optimized, const char*)  { return optimized ? "ppc" : "rosetta"; }
+template <>     const char*    SharedCache<x86>::cacheFileSuffix(bool, const char* archName)   { return archName; }
+template <>     const char*    SharedCache<x86_64>::cacheFileSuffix(bool, const char* archName){ return archName; }
+template <>     const char*    SharedCache<arm>::cacheFileSuffix(bool, const char* archName)   { return archName; }
 
 template <typename A>
-SharedCache<A>::SharedCache(ArchGraph* graph, bool alphaSort, uint64_t dyldBaseAddress) 
-  : fArchGraph(graph), fDyldBaseAddress(dyldBaseAddress)
+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)
 {
-       if ( fArchGraph->getArch() != arch() )
-               throw "wrong architecture";
-       
+       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
        std::set<const MachOLayoutAbstraction*>& dylibs = fArchGraph->getSharedDylibs();
        for(std::set<const MachOLayoutAbstraction*>::iterator it = dylibs.begin(); it != dylibs.end(); ++it) {
@@ -506,17 +696,59 @@ SharedCache<A>::SharedCache(ArchGraph* graph, bool alphaSort, uint64_t dyldBaseA
                temp.info.pathFileOffset = lib->getNameFileOffset();
                fDylibs.push_back(temp);
        }
+
+       // examine the existing shared cache file
+       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];
+       if ( overlay ) {
+               strcpy(cachePathNonOverlay, DYLD_SHARED_CACHE_DIR);
+               strcat(cachePathNonOverlay, DYLD_SHARED_CACHE_BASE_NAME);
+               strcat(cachePathNonOverlay, cacheFileSuffix(optimize, fArchGraph->archName()));
+               pathToExistingCacheFile = cachePathNonOverlay;
+       }
+       fExistingIsNotUpToDate = this->notUpToDate(pathToExistingCacheFile);
        
        // sort shared dylibs
-       if ( alphaSort )
+       if ( verify ) {
+               // already sorted by notUpToDate()
+       }
+       else if ( alphaSort ) {
                std::sort(fDylibs.begin(), fDylibs.end(), ByNameSorter());
-       else
-               std::sort(fDylibs.begin(), fDylibs.end(), RandomSorter(fDylibs));
-               
+       }
+       else {
+               // random sort for Address Space Randomization
+               std::map<const MachOLayoutAbstraction*, uint32_t> map;
+               for(typename std::vector<struct LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) 
+                       map[it->layout] = arc4random();
+               std::sort(fDylibs.begin(), fDylibs.end(), Sorter(map));
+       }
        
        // assign segments in each dylib a new address
        this->assignNewBaseAddresses();
        
+       // check that cache we are about to create for verification purposes has same layout as existing cache
+       if ( verify ) {
+               // 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());
+               }
+               const dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)fExistingCacheForVerification;
+               const dyldCacheImageInfo<E>* cacheEntry = (dyldCacheImageInfo<E>*)(fExistingCacheForVerification + header->imagesOffset());
+               for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it, ++cacheEntry) {
+                       if ( cacheEntry->address() != it->layout->getSegments()[0].newAddress() ) {
+                               throwf("update_dyld_shared_cache[%u] warning: for arch=%s, could not verify cache because start address of %s is 0x%llX in cache, but should be 0x%llX\n",
+                                                       getpid(), archName(), it->layout->getID().name, cacheEntry->address(), it->layout->getSegments()[0].newAddress());
+                       }
+               }
+       }
+       
        // calculate cache file header size
        fHeaderSize = pageAlign(sizeof(dyld_cache_header) 
                                                        + fMappings.size()*sizeof(shared_file_mapping_np) 
@@ -537,14 +769,7 @@ uint64_t SharedCache<A>::getWritableSegmentNewAddress(uint64_t proposedNewAddres
 template <>
 uint64_t SharedCache<ppc>::getWritableSegmentNewAddress(uint64_t proposedNewAddress, uint64_t originalAddress, uint64_t executableSlide)
 {
-       // for ppc64 writable segments can only move in increments of 64K (so only hi16 instruction needs to be modified)
-       return (((executableSlide & 0x000000000000F000ULL) - ((proposedNewAddress - originalAddress) & 0x000000000000F000ULL)) & 0x000000000000F000ULL) + proposedNewAddress;
-}
-
-template <>
-uint64_t SharedCache<ppc64>::getWritableSegmentNewAddress(uint64_t proposedNewAddress, uint64_t originalAddress, uint64_t executableSlide)
-{
-       // for ppc64 writable segments can only move in increments of 64K (so only hi16 instruction needs to be modified)
+       // for ppc writable segments can only move in increments of 64K (so only hi16 instruction needs to be modified)
        return (((executableSlide & 0x000000000000F000ULL) - ((proposedNewAddress - originalAddress) & 0x000000000000F000ULL)) & 0x000000000000F000ULL) + proposedNewAddress;
 }
 
@@ -560,6 +785,7 @@ void SharedCache<A>::assignNewBaseAddresses()
                MachOLayoutAbstraction::Segment* executableSegment = NULL;
                for (int i=0; i < segs.size(); ++i) {
                        MachOLayoutAbstraction::Segment& seg = segs[i];
+                       seg.reset();
                        if ( seg.writable() ) {
                                if ( seg.executable() && it->layout->hasSplitSegInfo() ) {
                                        // skip __IMPORT segments in this pass
@@ -588,11 +814,6 @@ void SharedCache<A>::assignNewBaseAddresses()
                                }
                                else {
                                        // skip read-only segments in this pass
-                                       // any non-LINKEDIT read-only segments leave a hole so that all R/W segment slide together
-                                       if ( (strcmp(seg.name(), "__LINKEDIT") != 0) && (i < (segs.size()-2)) ) {
-                                               fprintf(stderr, "update_dyld_shared_cache: warning %s segment in %s leaves a hole\n", seg.name(), it->layout->getID().name);
-                                               currentWritableAddress = pageAlign(currentWritableAddress + seg.size());
-                                       }
                                }
                        }
                }
@@ -615,7 +836,6 @@ void SharedCache<A>::assignNewBaseAddresses()
                        else if ( seg.writable() && seg.executable() && it->layout->hasSplitSegInfo() ) {
                                // allocate IMPORT segments to end of writable shared region
                                seg.setNewAddress(currentWritableExecutableAddress);
-                               seg.setWritable(false); // __IMPORT segments are not-writable in shared cache
                                currentWritableExecutableAddress += pageAlign(seg.size());
                        }
                }
@@ -667,8 +887,7 @@ void SharedCache<A>::assignNewBaseAddresses()
                        writableExecutableMapping.sfm_size              = currentWritableExecutableAddress - startWritableExecutableAddress;
                        writableExecutableMapping.sfm_file_offset= cacheFileOffset;
                        writableExecutableMapping.sfm_max_prot  = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
-                       // __IMPORT segments in shared cache are not writable 
-                       writableExecutableMapping.sfm_init_prot = VM_PROT_READ | VM_PROT_EXECUTE; 
+                       writableExecutableMapping.sfm_init_prot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; 
                        fMappings.push_back(writableExecutableMapping);
                        cacheFileOffset += writableExecutableMapping.sfm_size;
                }
@@ -708,47 +927,107 @@ uint64_t SharedCache<A>::cacheFileOffsetForAddress(uint64_t addr)
 }
 
 
+template <typename A>
+uint64_t SharedCache<A>::mappedCacheAddressForAddress(uint64_t addr)
+{
+    if (!addr) return 0;
+    else return (uint64_t)(fInMemoryCache + cacheFileOffsetForAddress(addr));
+}
+
+
 template <typename A>
 bool SharedCache<A>::notUpToDate(const void* cache)
 {
        dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)cache;
        // not valid if header signature is wrong
+       const char* archPairName = fArchGraph->archName();
        char temp[16];
        strcpy(temp, "dyld_v1        ");
-       strcpy(&temp[15-strlen(archName())], archName());
-       if ( strcmp(header->magic(), temp) != 0 ) 
-               return true;
+       strcpy(&temp[15-strlen(archPairName)], archPairName);
+       if ( strcmp(header->magic(), temp) != 0 ) {
+               if ( fVerify ) {
+                       fprintf(stderr, "update_dyld_shared_cache[%u] cannot verify %s because current cache file has invalid header\n", getpid(), archName());
+                       return false;
+               }
+               else {
+                       fprintf(stderr, "update_dyld_shared_cache[%u] 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() )
-               return true;
+       if ( header->imagesCount() != fDylibs.size() ) {
+               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());
+                       return true;
+               }
+       }
        // 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());
        const dyldCacheImageInfo<E>* imagesEnd = &imagesStart[header->imagesCount()];
        for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
                bool found = false;
                //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 ( (cacheEntry->inode() == it->info.inode) 
-                        && (cacheEntry->modTime() == it->info.modTime) 
-                        && (strcmp((char*)cache+cacheEntry->pathFileOffset(), it->layout->getID().name) == 0) ) {
+                       if ( fVerify ) {
+                               // 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;
+                                       sortingMap[it->layout] = cacheEntry-imagesStart;
+                                       if ( (cacheEntry->inode() != it->info.inode) || (cacheEntry->modTime() != it->info.modTime) ) {
+                                               fprintf(stderr, "update_dyld_shared_cache[%u] warning: for arch=%s, %s has changed since cache was built\n", 
+                                                               getpid(), archName(), it->layout->getID().name);
+                                       }
+                                       break;
+                               }
+                       }
+                       else {
+                               // 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) 
+                                               && (strcmp((char*)cache+cacheEntry->pathFileOffset(), it->layout->getID().name) == 0) ) {
                                        found = true;
                                        break;
+                               }
                        }
                }
                if ( !found ) {
-                       fprintf(stderr, "update_dyld_shared_cache[%u] current cache invalid because %s has changed\n", getpid(), it->layout->getID().name);
-                       return true;
+                       if ( fVerify ) {
+                               throwf("update_dyld_shared_cache[%u] can't verify %s cache because %s is not in existing cache\n", getpid(), archName(), it->layout->getID().name);
+                       }
+                       else {
+                               fprintf(stderr, "update_dyld_shared_cache[%u] current %s cache file invalid because %s has changed\n", getpid(), archName(), it->layout->getID().name);
+                               return true;
+                       }
                }
        }
-       return false;
+       // all dylibs in existing cache file match those determined need to be in shared cache
+       if ( fVerify ) {
+               // sort fDylibs to match existing cache file so we can compare content
+               std::sort(fDylibs.begin(), fDylibs.end(), Sorter(sortingMap));
+               //fprintf(stderr, "dylibs sorted like existing cache:\n");
+               //for(typename std::vector<LayoutInfo>::iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
+               //      fprintf(stderr,"   %s\n", it->layout->getID().name);
+               //}
+               // do regenerate a new cache so we can compare content with existing
+               return true;
+       }
+       else {
+               // existing cache file is up-to-date, don't need to regenerate
+               return false;
+       }
 }
 
 
 template <typename A>
-bool SharedCache<A>::notUpToDate(const char* cachePath)
+bool SharedCache<A>::notUpToDate(const char* path)
 {
        // mmap existing cache file 
-       int fd = ::open(cachePath, O_RDONLY);   
+       int fd = ::open(path, O_RDONLY);        
        if ( fd == -1 )
                return true;
        struct stat stat_buf;
@@ -760,11 +1039,16 @@ bool SharedCache<A>::notUpToDate(const char* cachePath)
 
        // validate it
        bool result = this->notUpToDate(mappingAddr);
-       // unmap
-       ::munmap(mappingAddr, stat_buf.st_size);
-       if ( verbose && !result )
-               fprintf(stderr, "update_dyld_shared_cache: %s is up-to-date\n", cachePath);
-
+       if ( fVerify ) {
+               // don't unmap yet, leave so it can be verified later
+               fExistingCacheForVerification = mappingAddr;
+       }
+       else {
+               // unmap
+               ::munmap(mappingAddr, stat_buf.st_size);
+               if ( verbose && !result )
+                       fprintf(stderr, "update_dyld_shared_cache: %s is up-to-date\n", path);
+       }
        return result;
 }
 
@@ -794,7 +1078,7 @@ private:
 
 
 StringPool::StringPool() 
-       : fBufferUsed(0), fBufferAllocated(4*1024*1024)
+       : fBufferUsed(0), fBufferAllocated(32*1024*1024)
 {
        fBuffer = (char*)malloc(fBufferAllocated);
 }
@@ -804,8 +1088,7 @@ uint32_t StringPool::add(const char* str)
        uint32_t len = strlen(str);
        if ( (fBufferUsed + len + 1) > fBufferAllocated ) {
                // grow buffer
-               fBufferAllocated = fBufferAllocated*2;
-               fBuffer = (char*)realloc(fBuffer, fBufferAllocated);
+               throw "string buffer exhausted";
        }
        strcpy(&fBuffer[fBufferUsed], str);
        uint32_t result = fBufferUsed;
@@ -848,13 +1131,17 @@ public:
                                                                                        LinkEditOptimizer(const MachOLayoutAbstraction&, uint8_t*, StringPool&);
        virtual                                                                 ~LinkEditOptimizer() {}
 
-       static void                                                             makeDummyLocalSymbol(uint32_t&, uint8_t*, StringPool&);
-               void                                                            copyLocalSymbols();
-               void                                                            copyExportedSymbols(uint32_t&);
-               void                                                            copyImportedSymbols(uint32_t&);
-               void                                                            copyExternalRelocations(uint32_t&);
-               void                                                            copyIndirectSymbolTable(uint32_t&);
-               void                                                            updateLoadCommands(uint64_t newVMAddress, uint64_t size, uint32_t stringPoolOffset);
+               void                                                            copyBindInfo(uint32_t&);
+               void                                                            copyWeakBindInfo(uint32_t&);
+               void                                                            copyLazyBindInfo(uint32_t&);
+               void                                                            copyExportInfo(uint32_t&);
+               void                                                            copyLocalSymbols(uint32_t symbolTableOffset, uint32_t&);
+               void                                                            copyExportedSymbols(uint32_t symbolTableOffset, uint32_t&);
+               void                                                            copyImportedSymbols(uint32_t symbolTableOffset, uint32_t&);
+               void                                                            copyExternalRelocations(uint32_t& offset);
+               void                                                            copyIndirectSymbolTable(uint32_t& offset);
+               void                                                            updateLoadCommands(uint64_t newVMAddress, uint64_t size, uint32_t stringPoolOffset, 
+                                                                                                                               uint32_t linkEditsFileOffset, bool keepSignatures);
        
 
 protected:
@@ -868,12 +1155,22 @@ private:
        uint8_t*                                                                        fNewLinkEditStart;      
        uint8_t*                                                                        fLinkEditBase;          
        const MachOLayoutAbstraction&                           fLayout;
+       macho_dyld_info_command<P>*                                     fDyldInfo;
        macho_dysymtab_command<P>*                                      fDynamicSymbolTable;
        macho_symtab_command<P>*                                        fSymbolTableLoadCommand;
        const macho_nlist<P>*                                           fSymbolTable;
        const char*                                                                     fStrings;
        StringPool&                                                                     fNewStringPool;
        std::map<uint32_t,uint32_t>                                     fOldToNewSymbolIndexes;
+       uint32_t                                                                        fBindInfoOffsetIntoNewLinkEdit;
+       uint32_t                                                                        fBindInfoSizeInNewLinkEdit;
+       uint32_t                                                                        fWeakBindInfoOffsetIntoNewLinkEdit;
+       uint32_t                                                                        fWeakBindInfoSizeInNewLinkEdit;
+       uint32_t                                                                        fLazyBindInfoOffsetIntoNewLinkEdit;
+       uint32_t                                                                        fLazyBindInfoSizeInNewLinkEdit;
+       uint32_t                                                                        fExportInfoOffsetIntoNewLinkEdit;
+       uint32_t                                                                        fExportInfoSizeInNewLinkEdit;
+       uint32_t                                                                        fSymbolTableStartOffsetInNewLinkEdit;
        uint32_t                                                                        fLocalSymbolsStartIndexInNewLinkEdit;
        uint32_t                                                                        fLocalSymbolsCountInNewLinkEdit;
        uint32_t                                                                        fExportedSymbolsStartIndexInNewLinkEdit;
@@ -882,16 +1179,19 @@ private:
        uint32_t                                                                        fImportedSymbolsCountInNewLinkEdit;
        uint32_t                                                                        fExternalRelocationsOffsetIntoNewLinkEdit;
        uint32_t                                                                        fIndirectSymbolTableOffsetInfoNewLinkEdit;
-       static int32_t                                                          fgLocalSymbolsStartIndexInNewLinkEdit;
 };
 
-template <typename A> int32_t LinkEditOptimizer<A>::fgLocalSymbolsStartIndexInNewLinkEdit = 0;
 
 
 template <typename A>
 LinkEditOptimizer<A>::LinkEditOptimizer(const MachOLayoutAbstraction& layout, uint8_t* newLinkEdit, StringPool& stringPool)
- :     fLayout(layout), fLinkEditBase(NULL), fNewLinkEditStart(newLinkEdit), 
+ :     fLayout(layout), fLinkEditBase(NULL), fNewLinkEditStart(newLinkEdit), fDyldInfo(NULL),
        fDynamicSymbolTable(NULL), fSymbolTableLoadCommand(NULL), fSymbolTable(NULL), fStrings(NULL), fNewStringPool(stringPool),
+       fBindInfoOffsetIntoNewLinkEdit(0), fBindInfoSizeInNewLinkEdit(0),
+       fWeakBindInfoOffsetIntoNewLinkEdit(0), fWeakBindInfoSizeInNewLinkEdit(0),
+       fLazyBindInfoOffsetIntoNewLinkEdit(0), fLazyBindInfoSizeInNewLinkEdit(0),
+       fExportInfoOffsetIntoNewLinkEdit(0), fExportInfoSizeInNewLinkEdit(0),
+       fSymbolTableStartOffsetInNewLinkEdit(0), 
        fLocalSymbolsStartIndexInNewLinkEdit(0), fLocalSymbolsCountInNewLinkEdit(0),
        fExportedSymbolsStartIndexInNewLinkEdit(0), fExportedSymbolsCountInNewLinkEdit(0),
        fImportSymbolsStartIndexInNewLinkEdit(0), fImportedSymbolsCountInNewLinkEdit(0),
@@ -924,6 +1224,10 @@ LinkEditOptimizer<A>::LinkEditOptimizer(const MachOLayoutAbstraction& layout, ui
                        case LC_DYSYMTAB:
                                fDynamicSymbolTable = (macho_dysymtab_command<P>*)cmd;
                                break;
+                       case LC_DYLD_INFO:
+                       case LC_DYLD_INFO_ONLY:
+                               fDyldInfo = (macho_dyld_info_command<P>*)cmd;
+                               break;
                }
                cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
        }       
@@ -951,51 +1255,97 @@ private:
 
 
 template <typename A>
-void LinkEditOptimizer<A>::makeDummyLocalSymbol(uint32_t& symbolIndex, uint8_t* storage, StringPool& pool)
+void LinkEditOptimizer<A>::copyBindInfo(uint32_t& offset)
+{
+       if ( (fDyldInfo != NULL) && (fDyldInfo->bind_off() != 0) ) {
+               fBindInfoOffsetIntoNewLinkEdit = offset;
+               fBindInfoSizeInNewLinkEdit = fDyldInfo->bind_size();
+               memcpy(fNewLinkEditStart+offset, &fLinkEditBase[fDyldInfo->bind_off()], fDyldInfo->bind_size());
+               offset += fDyldInfo->bind_size();
+       }
+}
+
+template <typename A>
+void LinkEditOptimizer<A>::copyWeakBindInfo(uint32_t& offset)
+{
+       if ( (fDyldInfo != NULL) && (fDyldInfo->weak_bind_off() != 0) ) {
+               fWeakBindInfoOffsetIntoNewLinkEdit = offset;
+               fWeakBindInfoSizeInNewLinkEdit = fDyldInfo->weak_bind_size();
+               memcpy(fNewLinkEditStart+offset, &fLinkEditBase[fDyldInfo->weak_bind_off()], fDyldInfo->weak_bind_size());
+               offset += fDyldInfo->weak_bind_size();
+       }
+}
+
+template <typename A>
+void LinkEditOptimizer<A>::copyLazyBindInfo(uint32_t& offset)
+{
+       if ( (fDyldInfo != NULL) && (fDyldInfo->lazy_bind_off() != 0) ) {
+               fLazyBindInfoOffsetIntoNewLinkEdit = offset;
+               fLazyBindInfoSizeInNewLinkEdit = fDyldInfo->lazy_bind_size();
+               memcpy(fNewLinkEditStart+offset, &fLinkEditBase[fDyldInfo->lazy_bind_off()], fDyldInfo->lazy_bind_size());
+               offset += fDyldInfo->lazy_bind_size();
+       }
+}
+
+template <typename A>
+void LinkEditOptimizer<A>::copyExportInfo(uint32_t& offset)
 {
-       fgLocalSymbolsStartIndexInNewLinkEdit = symbolIndex;
-       macho_nlist<P>* newSymbolEntry = (macho_nlist<P>*)storage;
-       newSymbolEntry->set_n_strx(pool.add("__no_local_symbols_in_dyld_shared_cache"));
-       newSymbolEntry->set_n_type(N_SECT);
-       newSymbolEntry->set_n_sect(1);
-       newSymbolEntry->set_n_desc(0);
-       newSymbolEntry->set_n_value(0);
-       ++symbolIndex;
+       if ( (fDyldInfo != NULL) && (fDyldInfo->export_off() != 0) ) {
+               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());
+               offset += fDyldInfo->export_size();
+       }
 }
 
+
+
 template <typename A>
-void LinkEditOptimizer<A>::copyLocalSymbols()
+void LinkEditOptimizer<A>::copyLocalSymbols(uint32_t symbolTableOffset, uint32_t& symbolIndex)
 {
-       if ( fDynamicSymbolTable->nlocalsym() > 0 ) {
-               // if image has any local symbols, make cache look like it has one local symbol
-               // which is actually shared by all images
-               fLocalSymbolsCountInNewLinkEdit = 1; 
-               fLocalSymbolsStartIndexInNewLinkEdit = fgLocalSymbolsStartIndexInNewLinkEdit;
+       fLocalSymbolsStartIndexInNewLinkEdit = symbolIndex;
+       fSymbolTableStartOffsetInNewLinkEdit = symbolTableOffset + symbolIndex*sizeof(macho_nlist<P>);
+       macho_nlist<P>* const newSymbolTableStart = (macho_nlist<P>*)(fNewLinkEditStart+symbolTableOffset);
+       const macho_nlist<P>* const firstLocal = &fSymbolTable[fDynamicSymbolTable->ilocalsym()];
+       const macho_nlist<P>* const lastLocal  = &fSymbolTable[fDynamicSymbolTable->ilocalsym()+fDynamicSymbolTable->nlocalsym()];
+       uint32_t oldIndex = fDynamicSymbolTable->ilocalsym();
+       for (const macho_nlist<P>* entry = firstLocal; entry < lastLocal; ++entry, ++oldIndex) {
+               if ( (entry->n_type() & N_TYPE) == N_SECT ) {
+                       macho_nlist<P>* newSymbolEntry = &newSymbolTableStart[symbolIndex];
+                       *newSymbolEntry = *entry;
+                       newSymbolEntry->set_n_strx(fNewStringPool.add(&fStrings[entry->n_strx()]));
+                       ++symbolIndex;
+               }
        }
+       fLocalSymbolsCountInNewLinkEdit = symbolIndex - fLocalSymbolsStartIndexInNewLinkEdit;
+       //fprintf(stderr, "%u locals starting at %u for %s\n", fLocalSymbolsCountInNewLinkEdit, fLocalSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
 }
 
 
 template <typename A>
-void LinkEditOptimizer<A>::copyExportedSymbols(uint32_t& symbolIndex)
+void LinkEditOptimizer<A>::copyExportedSymbols(uint32_t symbolTableOffset, uint32_t& symbolIndex)
 {
        fExportedSymbolsStartIndexInNewLinkEdit = symbolIndex;
+       macho_nlist<P>* const newSymbolTableStart = (macho_nlist<P>*)(fNewLinkEditStart+symbolTableOffset);
        const macho_nlist<P>* const firstExport = &fSymbolTable[fDynamicSymbolTable->iextdefsym()];
        const macho_nlist<P>* const lastExport  = &fSymbolTable[fDynamicSymbolTable->iextdefsym()+fDynamicSymbolTable->nextdefsym()];
        uint32_t oldIndex = fDynamicSymbolTable->iextdefsym();
        for (const macho_nlist<P>* entry = firstExport; entry < lastExport; ++entry, ++oldIndex) {
-               if ( ((entry->n_type() & N_TYPE) == N_SECT) && (strncmp(&fStrings[entry->n_strx()], ".objc_", 6) != 0) ) {
-                       macho_nlist<P>* newSymbolEntry = &((macho_nlist<P>*)fNewLinkEditStart)[symbolIndex];
+               if ( ((entry->n_type() & N_TYPE) == N_SECT) && (strncmp(&fStrings[entry->n_strx()], ".objc_", 6) != 0)
+                                               && (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()]));
-                       fOldToNewSymbolIndexes[oldIndex] = symbolIndex;
+                       fOldToNewSymbolIndexes[oldIndex] = symbolIndex-fLocalSymbolsStartIndexInNewLinkEdit;
                        ++symbolIndex;
                }
        }
        fExportedSymbolsCountInNewLinkEdit = symbolIndex - fExportedSymbolsStartIndexInNewLinkEdit;
        //fprintf(stderr, "%u exports starting at %u for %s\n", fExportedSymbolsCountInNewLinkEdit, fExportedSymbolsStartIndexInNewLinkEdit, fLayout.getFilePath());
        // sort by name, so that dyld does not need a toc
-       macho_nlist<P>* newSymbolsStart = &((macho_nlist<P>*)fNewLinkEditStart)[fExportedSymbolsStartIndexInNewLinkEdit];
-       macho_nlist<P>* newSymbolsEnd = &((macho_nlist<P>*)fNewLinkEditStart)[fExportedSymbolsStartIndexInNewLinkEdit+fExportedSymbolsCountInNewLinkEdit];
+       macho_nlist<P>* newSymbolsStart = &newSymbolTableStart[fExportedSymbolsStartIndexInNewLinkEdit];
+       macho_nlist<P>* newSymbolsEnd = &newSymbolTableStart[fExportedSymbolsStartIndexInNewLinkEdit+fExportedSymbolsCountInNewLinkEdit];
        std::sort(newSymbolsStart, newSymbolsEnd, SymbolSorter<A>(fNewStringPool));
        //for (macho_nlist<P>* entry = newSymbolsStart; entry < newSymbolsEnd; ++entry)
        //      fprintf(stderr, "\t%u\t %s\n", (entry-newSymbolsStart)+fExportedSymbolsStartIndexInNewLinkEdit, fNewStringPool.stringAtIndex(entry->n_strx()));
@@ -1003,18 +1353,19 @@ void LinkEditOptimizer<A>::copyExportedSymbols(uint32_t& symbolIndex)
 
 
 template <typename A>
-void LinkEditOptimizer<A>::copyImportedSymbols(uint32_t& symbolIndex)
+void LinkEditOptimizer<A>::copyImportedSymbols(uint32_t symbolTableOffset, uint32_t& symbolIndex)
 {
        fImportSymbolsStartIndexInNewLinkEdit = symbolIndex;
+       macho_nlist<P>* const newSymbolTableStart = (macho_nlist<P>*)(fNewLinkEditStart+symbolTableOffset);
        const macho_nlist<P>* const firstImport = &fSymbolTable[fDynamicSymbolTable->iundefsym()];
        const macho_nlist<P>* const lastImport  = &fSymbolTable[fDynamicSymbolTable->iundefsym()+fDynamicSymbolTable->nundefsym()];
        uint32_t oldIndex = fDynamicSymbolTable->iundefsym();
        for (const macho_nlist<P>* entry = firstImport; entry < lastImport; ++entry, ++oldIndex) {
                if ( ((entry->n_type() & N_TYPE) == N_UNDF) && (strncmp(&fStrings[entry->n_strx()], ".objc_", 6) != 0) ) {
-                       macho_nlist<P>* newSymbolEntry = &((macho_nlist<P>*)fNewLinkEditStart)[symbolIndex];
+                       macho_nlist<P>* newSymbolEntry = &newSymbolTableStart[symbolIndex];
                        *newSymbolEntry = *entry;
                        newSymbolEntry->set_n_strx(fNewStringPool.addUnique(&fStrings[entry->n_strx()]));
-                       fOldToNewSymbolIndexes[oldIndex] = symbolIndex;
+                       fOldToNewSymbolIndexes[oldIndex] = symbolIndex-fLocalSymbolsStartIndexInNewLinkEdit;
                        ++symbolIndex;
                }
        }
@@ -1064,13 +1415,13 @@ void LinkEditOptimizer<A>::copyIndirectSymbolTable(uint32_t& offset)
 }
 
 template <typename A>
-void LinkEditOptimizer<A>::updateLoadCommands(uint64_t newVMAddress, uint64_t size, uint32_t stringPoolOffset)
+void LinkEditOptimizer<A>::updateLoadCommands(uint64_t newVMAddress, uint64_t size, uint32_t stringPoolOffset, 
+                                                                                               uint32_t linkEditsFileOffset, bool keepSignatures)
 {
        // set LINKEDIT segment commmand to new merged LINKEDIT
        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;
-       uint32_t linkEditStartFileOffset = 0;
        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;
@@ -1078,37 +1429,94 @@ void LinkEditOptimizer<A>::updateLoadCommands(uint64_t newVMAddress, uint64_t si
                                seg->set_vmaddr(newVMAddress);
                                seg->set_vmsize(size);
                                seg->set_filesize(size);
-                               linkEditStartFileOffset = seg->fileoff();
+                               seg->set_fileoff(linkEditsFileOffset);
                        }
                }
                cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
        }       
+       
+       // update dyld_info with new offsets
+       if ( fDyldInfo != NULL ) {
+               fDyldInfo->set_rebase_off(0);
+               fDyldInfo->set_rebase_size(0);
+               fDyldInfo->set_bind_off(linkEditsFileOffset+fBindInfoOffsetIntoNewLinkEdit);
+               fDyldInfo->set_bind_size(fBindInfoSizeInNewLinkEdit);
+               fDyldInfo->set_weak_bind_off(linkEditsFileOffset+fWeakBindInfoOffsetIntoNewLinkEdit);
+               fDyldInfo->set_weak_bind_size(fWeakBindInfoSizeInNewLinkEdit);
+               fDyldInfo->set_lazy_bind_off(linkEditsFileOffset+fLazyBindInfoOffsetIntoNewLinkEdit);
+               fDyldInfo->set_lazy_bind_size(fLazyBindInfoSizeInNewLinkEdit);
+               fDyldInfo->set_export_off(linkEditsFileOffset+fExportInfoOffsetIntoNewLinkEdit);
+               fDyldInfo->set_export_size(fExportInfoSizeInNewLinkEdit);
                
+//             fprintf(stderr, "dylib %s\n", fLayout.getFilePath());
+//             fprintf(stderr, "  bind_off=0x%08X\n", fDyldInfo->bind_off());
+//             fprintf(stderr, "  export_off=0x%08X\n", fDyldInfo->export_off());
+//             fprintf(stderr, "  export_size=%d\n", fDyldInfo->export_size());
+               
+       }       
+       
        // update symbol table and dynamic symbol table with new offsets
-       fSymbolTableLoadCommand->set_symoff(linkEditStartFileOffset);
-       fSymbolTableLoadCommand->set_nsyms(fExportedSymbolsCountInNewLinkEdit+fImportedSymbolsCountInNewLinkEdit);
-       fSymbolTableLoadCommand->set_stroff(linkEditStartFileOffset+stringPoolOffset);
+       fSymbolTableLoadCommand->set_symoff(linkEditsFileOffset+fSymbolTableStartOffsetInNewLinkEdit);
+       fSymbolTableLoadCommand->set_nsyms(fLocalSymbolsCountInNewLinkEdit+fExportedSymbolsCountInNewLinkEdit+fImportedSymbolsCountInNewLinkEdit);
+       fSymbolTableLoadCommand->set_stroff(linkEditsFileOffset+stringPoolOffset);
        fSymbolTableLoadCommand->set_strsize(fNewStringPool.size());
-       fDynamicSymbolTable->set_ilocalsym(fLocalSymbolsStartIndexInNewLinkEdit);
+       fDynamicSymbolTable->set_ilocalsym(0);
        fDynamicSymbolTable->set_nlocalsym(fLocalSymbolsCountInNewLinkEdit);
-       fDynamicSymbolTable->set_iextdefsym(fExportedSymbolsStartIndexInNewLinkEdit);
+       fDynamicSymbolTable->set_iextdefsym(fExportedSymbolsStartIndexInNewLinkEdit-fLocalSymbolsStartIndexInNewLinkEdit);
        fDynamicSymbolTable->set_nextdefsym(fExportedSymbolsCountInNewLinkEdit);
-       fDynamicSymbolTable->set_iundefsym(fImportSymbolsStartIndexInNewLinkEdit);
+       fDynamicSymbolTable->set_iundefsym(fImportSymbolsStartIndexInNewLinkEdit-fLocalSymbolsStartIndexInNewLinkEdit);
        fDynamicSymbolTable->set_nundefsym(fImportedSymbolsCountInNewLinkEdit);
        fDynamicSymbolTable->set_tocoff(0);
        fDynamicSymbolTable->set_ntoc(0);
        fDynamicSymbolTable->set_modtaboff(0);
        fDynamicSymbolTable->set_nmodtab(0);
-       fDynamicSymbolTable->set_indirectsymoff(linkEditStartFileOffset+fIndirectSymbolTableOffsetInfoNewLinkEdit);
-       fDynamicSymbolTable->set_extreloff(linkEditStartFileOffset+fExternalRelocationsOffsetIntoNewLinkEdit);
+       fDynamicSymbolTable->set_indirectsymoff(linkEditsFileOffset+fIndirectSymbolTableOffsetInfoNewLinkEdit);
+       fDynamicSymbolTable->set_extreloff(linkEditsFileOffset+fExternalRelocationsOffsetIntoNewLinkEdit);
        fDynamicSymbolTable->set_locreloff(0);
        fDynamicSymbolTable->set_nlocrel(0);
+
+       // now remove load commands no longer needed
+       const macho_load_command<P>* srcCmd = cmds;
+       macho_load_command<P>* dstCmd = (macho_load_command<P>*)cmds;
+       int32_t newCount = 0;
+       for (uint32_t i = 0; i < cmd_count; ++i) {      
+               uint32_t cmdSize = srcCmd->cmdsize();
+               switch ( srcCmd->cmd() ) {
+                       case LC_SEGMENT_SPLIT_INFO:
+                               // don't copy
+                               break;
+                       case LC_CODE_SIGNATURE:
+                               if ( !keepSignatures )
+                                       break;
+                               // otherwise fall into copy case
+                       default:
+                               memmove(dstCmd, srcCmd, cmdSize);
+                               dstCmd = (macho_load_command<P>*)(((uint8_t*)dstCmd)+cmdSize);
+                               ++newCount;
+                               break;
+               }
+               srcCmd = (const macho_load_command<P>*)(((uint8_t*)srcCmd)+cmdSize);
+       }
+       // zero out stuff removed
+       bzero(dstCmd, (uint8_t*)srcCmd - (uint8_t*)dstCmd);
+       
+       // update mach_header
+       macho_header<P>* writableHeader = (macho_header<P>*)fHeader; 
+       writableHeader->set_ncmds(newCount);
+       writableHeader->set_sizeofcmds((uint8_t*)dstCmd - ((uint8_t*)fHeader + sizeof(macho_header<P>)));
+       
+       // this invalidates some ivars
+       fDynamicSymbolTable = NULL;
+       fSymbolTableLoadCommand = NULL;
+       fDyldInfo = NULL;
+       fSymbolTable = NULL;
+       fStrings = NULL;
 }
 
 
 
 template <typename A>
-uint8_t* SharedCache<A>::optimizeLINKEDIT()
+uint8_t* SharedCache<A>::optimizeLINKEDIT(bool keepSignatures)
 {
        // allocate space for optimized LINKEDIT area
        uint8_t* newLinkEdit = new uint8_t[fLinkEditsTotalUnoptimizedSize];
@@ -1123,34 +1531,49 @@ uint8_t* SharedCache<A>::optimizeLINKEDIT()
                optimizers.push_back(new LinkEditOptimizer<A>(*it->layout, newLinkEdit, stringPool));
        }
 
-       // copy local symbol table entries
-       uint32_t symbolTableIndex = 0;
-       LinkEditOptimizer<A>::makeDummyLocalSymbol(symbolTableIndex, newLinkEdit, stringPool);
+       // rebase info is not copied because images in shared cache are never rebased
+       
+       // copy weak bind info
+       uint32_t offset = 0;
+       fOffsetOfWeakBindInfoInCombinedLinkedit = offset;
+       for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
+               (*it)->copyWeakBindInfo(offset);
+       }
+       
+       // copy export info
+       fOffsetOfExportInfoInCombinedLinkedit = offset;
        for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
-               (*it)->copyLocalSymbols();
+               (*it)->copyExportInfo(offset);
        }
 
-       // copy exported symbol table entries
+       // copy bind info
+       fOffsetOfBindInfoInCombinedLinkedit = offset;
        for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
-               (*it)->copyExportedSymbols(symbolTableIndex);
+               (*it)->copyBindInfo(offset);
        }
-       //fprintf(stderr, "%u exported symbols, with %d bytes of strings\n", symbolTableIndex, stringPool.size());
-       //uint32_t importStart = symbolTableIndex;
-       //uint32_t importPoolStart =  stringPool.size();
        
-       // copy imported symbol table entries
+       // copy lazy bind info
+       fOffsetOfLazyBindInfoInCombinedLinkedit = offset;
+       for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
+               (*it)->copyLazyBindInfo(offset);
+       }
+
+       // copy symbol table entries
+       fOffsetOfOldSymbolTableInfoInCombinedLinkedit = offset;
+       uint32_t symbolTableOffset = offset;
+       uint32_t symbolTableIndex = 0;
        for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
-               (*it)->copyImportedSymbols(symbolTableIndex);
+               (*it)->copyLocalSymbols(symbolTableOffset, symbolTableIndex);
+               (*it)->copyExportedSymbols(symbolTableOffset, symbolTableIndex);
+               (*it)->copyImportedSymbols(symbolTableOffset, symbolTableIndex);
        }
-       //fprintf(stderr, "%u imported symbols, with %d bytes of strings\n", symbolTableIndex-importStart, stringPool.size()-importPoolStart);
        
        // copy external relocations, 8-byte aligned after end of symbol table
-       uint32_t externalRelocsOffset = (symbolTableIndex * sizeof(macho_nlist<typename A::P>) + 7) & (-8);
+       uint32_t externalRelocsOffset = symbolTableOffset + (symbolTableIndex * sizeof(macho_nlist<typename A::P>) + 7) & (-8);
        //uint32_t externalRelocsStartOffset = externalRelocsOffset;
        for(typename std::vector<LinkEditOptimizer<A>*>::iterator it = optimizers.begin(); it != optimizers.end(); ++it) {
                (*it)->copyExternalRelocations(externalRelocsOffset);
        }
-       //fprintf(stderr, "%u bytes of external relocs\n", externalRelocsOffset-externalRelocsStartOffset);
        
        // copy indirect symbol tables
        uint32_t indirectSymbolTableOffset = externalRelocsOffset;
@@ -1163,15 +1586,18 @@ uint8_t* SharedCache<A>::optimizeLINKEDIT()
        memcpy(&newLinkEdit[stringPoolOffset], stringPool.getBuffer(), stringPool.size());
        
        // find new size
-       uint32_t linkEditsTotalOptimizedSize = (stringPoolOffset + stringPool.size() + 4095) & (-4096);
+       fLinkEditsTotalOptimizedSize = (stringPoolOffset + stringPool.size() + 4095) & (-4096);
+       
+       // choose new linkedit file  offset 
+       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);
+               (*it)->updateLoadCommands(fLinkEditsStartAddress, fLinkEditsTotalUnoptimizedSize, stringPoolOffset, linkEditsFileOffset, keepSignatures);
        }
 
-       //fprintf(stderr, "fLinkEditsTotalUnoptimizedSize=%llu, linkEditsTotalOptimizedSize=%u\n", fLinkEditsTotalUnoptimizedSize, linkEditsTotalOptimizedSize);
-       //fprintf(stderr, "mega link edit mapped starting at: %p\n", fFirstLinkEditSegment->mappedAddress());
+       //fprintf(stderr, "fLinkEditsTotalUnoptimizedSize=%llu, fLinkEditsTotalOptimizedSize=%u\n", fLinkEditsTotalUnoptimizedSize, fLinkEditsTotalOptimizedSize);
+       //printf(stderr, "mega link edit mapped starting at: %p\n", fFirstLinkEditSegment->mappedAddress());
 
        // overwrite mapped LINKEDIT area with new optimized LINKEDIT segment
        memcpy(fFirstLinkEditSegment->mappedAddress(), newLinkEdit, fLinkEditsTotalUnoptimizedSize);
@@ -1184,15 +1610,131 @@ uint8_t* SharedCache<A>::optimizeLINKEDIT()
                        if ( !seg.writable() && !seg.executable() && (strcmp(seg.name(), "__LINKEDIT") == 0) ) {
                                seg.setNewAddress(fLinkEditsStartAddress);
                                seg.setMappedAddress(fFirstLinkEditSegment->mappedAddress());
-                               seg.setSize(linkEditsTotalOptimizedSize);
-                               seg.setFileSize(linkEditsTotalOptimizedSize);
-                               //seg.setFileOffset(0);
+                               seg.setSize(fLinkEditsTotalOptimizedSize);
+                               seg.setFileSize(fLinkEditsTotalOptimizedSize);
+                               seg.setFileOffset(linkEditsFileOffset);
                        }
                }
        }
        
        // return new end of cache
-       return (uint8_t*)fFirstLinkEditSegment->mappedAddress() + linkEditsTotalOptimizedSize;
+       return (uint8_t*)fFirstLinkEditSegment->mappedAddress() + fLinkEditsTotalOptimizedSize;
+}
+
+
+
+template <typename A>
+class ObjCSelectorUniquer
+{
+private:
+    objc_selopt::string_map fSelectorStrings;
+    SharedCache<A> *fCache;
+    size_t fCount;
+
+public:
+
+    ObjCSelectorUniquer(SharedCache<A> *newCache)
+        : fSelectorStrings()
+        , fCache(newCache)
+        , fCount(0)
+    { }
+
+    typename A::P::uint_t visit(typename A::P::uint_t oldValue) 
+    {
+        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;
+        return (typename A::P::uint_t)element->second;
+    }
+
+    objc_selopt::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()
+{
+    if ( verbose ) {
+        fprintf(stderr, "update_dyld_shared_cache: for %s, uniquing objc selectors\n", archName());
+    }
+
+    // Find libobjc's __TEXT,__objc_selopt section
+    const macho_section<P> *seloptSection = 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 (!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;
+    }
+
+
+    // Update selector references and build selector list
+    ObjCSelectorUniquer<A> uniq(this);
+
+    // Heuristic: choose selectors from libraries with more cstring data first.
+    // This tries to localize selector cstring memory.
+    std::vector<LayoutInfo> sortedDylibs = fDylibs;
+    std::sort(sortedDylibs.begin(), sortedDylibs.end(), ByCStringSectionSizeSorter());
+
+       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);
+       }
+
+    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);
+    if (err) {
+        warn(archName(), err);
+        return;
+    }
+
+    if ( verbose ) {
+        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));
+        fprintf(stderr, "update_dyld_shared_cache: for %s, "
+                "updated %zu selector references\n", 
+                archName(), uniq.count());
+    }
+
+    return;
 }
 
 
@@ -1210,19 +1752,15 @@ static void cleanup(int sig)
 
 
 template <typename A>
-bool SharedCache<A>::update(const char* rootPath, const char* cacheDir, bool force, bool optimize, bool deleteExistingFirst, int archIndex, int archCount)
+bool SharedCache<A>::update(bool usesOverlay, bool force, bool optimize, bool deleteExistingFirst, int archIndex,
+                                                               int archCount, bool keepSignatures)
 {
        bool didUpdate = false;
-       char cachePath[1024];
-       strcpy(cachePath, rootPath);
-       strcat(cachePath, cacheDir);
-       strcat(cachePath, DYLD_SHARED_CACHE_BASE_NAME);
-       strcat(cachePath, filename(optimize));
        
        // already up to date?
-       if ( force || this->notUpToDate(cachePath) ) {
+       if ( force || fExistingIsNotUpToDate ) {
                if ( verbose )
-                       fprintf(stderr, "update_dyld_shared_cache: regenerating %s\n", cachePath);
+                       fprintf(stderr, "update_dyld_shared_cache: regenerating %s\n", fCacheFilePath);
                if ( fDylibs.size() == 0 ) {
                        fprintf(stderr, "update_dyld_shared_cache: warning, empty cache not generated for arch %s\n", archName());
                        return false;
@@ -1230,11 +1768,11 @@ bool SharedCache<A>::update(const char* rootPath, const char* cacheDir, bool for
                // delete existing cache while building the new one
                // this is a flag to dyld to stop pinging update_dyld_shared_cache
                if ( deleteExistingFirst )
-                       ::unlink(cachePath);
+                       ::unlink(fCacheFilePath);
                uint8_t* inMemoryCache = NULL;
                uint32_t allocatedCacheSize = 0;
-               char tempCachePath[strlen(cachePath)+16];
-               sprintf(tempCachePath, "%s.tmp%u", cachePath, getpid());
+               char tempCachePath[strlen(fCacheFilePath)+16];
+               sprintf(tempCachePath, "%s.tmp%u", fCacheFilePath, getpid());
                try {
                        // allocate a memory block to hold cache
                        uint32_t cacheFileSize = 0;
@@ -1246,12 +1784,14 @@ bool SharedCache<A>::update(const char* rootPath, const char* cacheDir, bool for
                        if ( vm_allocate(mach_task_self(), (vm_address_t*)(&inMemoryCache), cacheFileSize, VM_FLAGS_ANYWHERE) != KERN_SUCCESS )
                                throwf("can't vm_allocate cache of size %u", cacheFileSize);
                        allocatedCacheSize = cacheFileSize;
+            fInMemoryCache = inMemoryCache;
                        
                        // fill in header
                        dyldCacheHeader<E>* header = (dyldCacheHeader<E>*)inMemoryCache;
+                       const char* archPairName = fArchGraph->archName();
                        char temp[16];
                        strcpy(temp, "dyld_v1        ");
-                       strcpy(&temp[15-strlen(archName())], archName());
+                       strcpy(&temp[15-strlen(archPairName)], archPairName);
                        header->set_magic(temp);
                        //header->set_architecture(arch());
                        header->set_mappingOffset(sizeof(dyldCacheHeader<E>)); 
@@ -1288,10 +1828,12 @@ bool SharedCache<A>::update(const char* rootPath, const char* cacheDir, bool for
                        }
                                                
                        // copy each segment to cache buffer
+                       const int dylibCount = fDylibs.size();
                        int dylibIndex = 0;
+                       int progressIndex = 0;
                        for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it, ++dylibIndex) {
                                const char* path = it->layout->getFilePath();
-                               int src = ::open(path, O_RDONLY, 0);    
+                               int src = ::open(path, O_RDONLY, 0);
                                if ( src == -1 )
                                        throwf("can't open file %s, errnor=%d", it->layout->getID().name, errno);
                                // mark source as "don't cache"
@@ -1301,7 +1843,7 @@ bool SharedCache<A>::update(const char* rootPath, const char* cacheDir, bool for
                                if ( fstat(src, &stat_buf) == -1)
                                        throwf("can't stat open file %s, errno=%d", path, errno);
                                if ( (it->layout->getInode() != stat_buf.st_ino) || (it->layout->getLastModTime() != stat_buf.st_mtime) )
-                                       throwf("aborting because OS dylib modified during cache creation: %s", path);
+                                       throwf("file modified during cache creation: %s", path);
 
                                if ( verbose )
                                        fprintf(stderr, "update_dyld_shared_cache: copying %s to cache\n", it->layout->getID().name);
@@ -1316,31 +1858,12 @@ bool SharedCache<A>::update(const char* rootPath, const char* cacheDir, bool for
                                                        const uint64_t segmentSize = seg.fileSize();
                                                        const uint64_t segmentDstStartOffset = cacheFileOffsetForAddress(seg.newAddress());
                                                        ssize_t readResult = ::pread(src, &inMemoryCache[segmentDstStartOffset], segmentSize, segmentSrcStartOffset);
-                                                       if ( readResult != segmentSize ) 
+                                                       if ( readResult != segmentSize ) {
                                                                if ( readResult == -1 )
                                                                        throwf("read failure copying dylib errno=%d for %s", errno, it->layout->getID().name);
                                                                else
                                                                        throwf("read failure copying dylib. Read of %lld bytes at file offset %lld returned %ld for %s", 
                                                                                        segmentSize, segmentSrcStartOffset, readResult, it->layout->getID().name);
-                                                       // verify __TEXT segment has no zeroed out pages
-                                                       if ( strcmp(seg.name(), "__TEXT") == 0 ) {
-                                                               // only scan first 128KB.  Some OS dylibs have zero filled TEXT pages later in __const...
-                                                               int scanEnd = segmentSize;
-                                                               if ( scanEnd > 0x20000 )
-                                                                       scanEnd = 0x20000;
-                                                               for (int pageOffset = 0; pageOffset < scanEnd; pageOffset += 4096) {
-                                                                       const uint32_t* page = (uint32_t*)(&inMemoryCache[segmentDstStartOffset+pageOffset]);
-                                                                       bool foundNonZero = false;
-                                                                       for(int p=0; p < 1024; ++p) {
-                                                                               if ( page[p] != 0 ) {
-                                                                                       //fprintf(stderr, "found non-zero at pageOffset=0x%08X, p=0x%08X in memory=%p for %s\n", pageOffset, p, page, it->layout->getID().name);
-                                                                                       foundNonZero = true;
-                                                                                       break;
-                                                                               }
-                                                                       }
-                                                                       if ( !foundNonZero )
-                                                                               throwf("suspected bad read. Found __TEXT segment page at offset 0x%08X that is all zeros for %s in %s", pageOffset, archName(), it->layout->getID().name);
-                                                               }
                                                        }
                                                }
                                        }
@@ -1349,6 +1872,13 @@ bool SharedCache<A>::update(const char* rootPath, const char* cacheDir, bool for
                                        throwf("%s while copying %s to shared cache", msg, it->layout->getID().name);
                                }
                                ::close(src);
+                               if ( progress ) {
+                                       // assuming read takes 40% of time
+                                       int nextProgressIndex = archIndex*100+(40*dylibIndex)/dylibCount;
+                                       if ( nextProgressIndex != progressIndex )
+                                               fprintf(stdout, "%3u/%u\n", nextProgressIndex, archCount*100);
+                                       progressIndex = nextProgressIndex;
+                               }
                        }
                                                
                        // set mapped address for each segment
@@ -1378,7 +1908,7 @@ bool SharedCache<A>::update(const char* rootPath, const char* cacheDir, bool for
                        // 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() - inMemoryCache);
+                               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;
@@ -1402,6 +1932,7 @@ bool SharedCache<A>::update(const char* rootPath, const char* cacheDir, bool for
                                if ( it->layout->getID().name != NULL )
                                        map[it->layout->getID().name] = binder;
                        }
+                       
                        // tell each Binder about the others
                        for(typename std::vector<Binder<A>*>::iterator it = binders.begin(); it != binders.end(); ++it) {
                                (*it)->setDependentBinders(map);
@@ -1422,93 +1953,212 @@ bool SharedCache<A>::update(const char* rootPath, const char* cacheDir, bool for
                                delete *it;
                        }
        
-                       // install signal handlers to delete temp file if program is killed 
-                       sCleanupFile = tempCachePath;
-                       ::signal(SIGINT, cleanup);
-                       ::signal(SIGBUS, cleanup);
-                       ::signal(SIGSEGV, cleanup);
-                       
-                       // create temp file for cache
-                       int fd = ::open(tempCachePath, O_CREAT | O_RDWR | O_TRUNC, 0644);       
-                       if ( fd == -1 )
-                               throwf("can't create temp file %s, errnor=%d", tempCachePath, errno);
-                               
-                       // try to allocate whole cache file contiguously
-                       fstore_t fcntlSpec = { F_ALLOCATECONTIG|F_ALLOCATEALL, F_PEOFPOSMODE, 0, cacheFileSize, 0 };
-                       ::fcntl(fd, F_PREALLOCATE, &fcntlSpec);
+                       // 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);
+                       }
 
-                       // write out cache file
-                       if ( verbose )
-                               fprintf(stderr, "update_dyld_shared_cache: writing cache to disk\n");
-                       if ( ::pwrite(fd, inMemoryCache, cacheFileSize, 0) != cacheFileSize )
-                               throwf("write() failure creating cache file, errno=%d", errno);
-                       
-                       // flush to disk and close
-                       int result = ::fcntl(fd, F_FULLFSYNC, NULL);
-                       if ( result == -1 ) 
-                               fprintf(stderr, "update_dyld_shared_cache: warning, fcntl(F_FULLFSYNC) failed with errno=%d for %s\n", errno, tempCachePath);
-                       result = ::close(fd);
-                       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
-                       result = ::rename(tempCachePath, cachePath);
-                       if ( result != 0 ) 
-                               throwf("can't swap newly create dyld shared cache file: rename(%s,%s) returned errno=%d", tempCachePath, cachePath, errno);
+                       if ( fVerify ) {
+                               // new cache is built, compare header entries
+                               const dyldCacheHeader<E>* newHeader = (dyldCacheHeader<E>*)inMemoryCache;
+                               const dyldCacheHeader<E>* oldHeader = (dyldCacheHeader<E>*)fExistingCacheForVerification;
+                               if ( newHeader->mappingCount() != oldHeader->mappingCount() ) {
+                                       throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify cache because caches have a different number of mappings\n",
+                                        getpid(), archName());
+                               }
+                               const dyldCacheFileMapping<E>* newMappings = (dyldCacheFileMapping<E>*)&inMemoryCache[newHeader->mappingOffset()];
+                               const dyldCacheFileMapping<E>* oldMappings = (dyldCacheFileMapping<E>*)&fExistingCacheForVerification[oldHeader->mappingOffset()];
+                               for (int i=0; i < newHeader->mappingCount(); ++i) {
+                                       if ( newMappings[i].address() != oldMappings[i].address() ) {
+                                               throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify cache because mapping %d starts at a different address 0x%0llX vs 0x%0llX\n", 
+                                                       getpid(), archName(), i, newMappings[i].address(), oldMappings[i].address() );
+                                       }
+                                       if ( newMappings[i].size() != oldMappings[i].size() ) {
+                                               throwf("update_dyld_shared_cache[%u] for arch=%s, could not verify cache because mapping %d has a different size\n",
+                                                getpid(), archName(), i);
+                                       }
+                               }
                                
-                       // flush everything to disk to assure rename() gets recorded
-                       ::sync();
-                       didUpdate = true;
-                       
-                       // restore default signal handlers
-                       ::signal(SIGINT, SIG_DFL);
-                       ::signal(SIGBUS, SIG_DFL);
-                       ::signal(SIGSEGV, SIG_DFL);
-
-                       // generate human readable "map" file that shows the layout of the cache file
-                       if ( verbose )
-                               fprintf(stderr, "update_dyld_shared_cache: writing .map file to disk\n");
-                       sprintf(tempCachePath, "%s.map", cachePath);// re-use path buffer
-                       FILE* fmap = ::fopen(tempCachePath, "w");       
-                       if ( fmap == NULL ) {
-                               fprintf(stderr, "can't create map file %s, errnor=%d", tempCachePath, errno);
+                               //fprintf(stderr, "%s existing cache = %p\n", archName(), fExistingCacheForVerification);
+                               //fprintf(stderr, "%s new cache = %p\n", archName(), inMemoryCache);
+                               // compare content to existing cache page by page
+                               for (int offset=0; offset < cacheFileSize; offset += 4096) {
+                                       if ( memcmp(&inMemoryCache[offset], &fExistingCacheForVerification[offset], 4096) != 0 ) {
+                                               fprintf(stderr, "verifier found differences on page offset 0x%08X for %s:\n", offset, archName());
+                                               for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it, ++dylibIndex) {
+                                                       const std::vector<MachOLayoutAbstraction::Segment>& segs = it->layout->getSegments();
+                                                       for(std::vector<MachOLayoutAbstraction::Segment>::const_iterator sit = segs.begin(); sit != segs.end(); ++sit) {
+                                                               const MachOLayoutAbstraction::Segment& seg = *sit;
+                                                               if ( (seg.mappedAddress() <= &inMemoryCache[offset]) && (&inMemoryCache[offset] < ((uint8_t*)seg.mappedAddress() + seg.fileSize())) ) {
+                                                                       // all LINKEDITs point to the same region, so just print one
+                                                                       if ( strcmp(seg.name(), "__LINKEDIT") == 0 ) 
+                                                                               fprintf(stderr, "  in merged LINKEDIT segment\n");
+                                                                       else
+                                                                               fprintf(stderr, "  in segment %s of dylib %s\n", seg.name(), it->layout->getID().name);
+                                                                       break;
+                                                               }
+                                                       }
+                                               }
+                                               for (int po=0; po < 4096; po += 16) {
+                                                       if ( memcmp(&inMemoryCache[offset+po], &fExistingCacheForVerification[offset+po], 16) != 0 ) {
+                                                               fprintf(stderr, "   existing: 0x%08X: ", offset+po);
+                                                               for ( int j=0; j < 16; ++j)
+                                                                       fprintf(stderr, " 0x%02X", fExistingCacheForVerification[offset+po+j]);
+                                                               fprintf(stderr, "\n");
+                                                               fprintf(stderr, "  should be: 0x%08X: ", offset+po);
+                                                               for ( int j=0; j < 16; ++j)
+                                                                       fprintf(stderr, " 0x%02X", inMemoryCache[offset+po+j]);
+                                                               fprintf(stderr, "\n");
+                                                       }
+                                               }
+                                       }
+                               }
                        }
                        else {
-                               for(std::vector<shared_file_mapping_np>::iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
-                                       const char* prot = "RW";
-                                       if ( it->sfm_init_prot == (VM_PROT_EXECUTE|VM_PROT_READ) )
-                                               prot = "EX";
-                                       else if ( it->sfm_init_prot == VM_PROT_READ )
-                                               prot = "RO";
-                                       else if ( it->sfm_init_prot == (VM_PROT_EXECUTE|VM_PROT_WRITE|VM_PROT_READ) )
-                                               prot = "WX";
-                                       if ( it->sfm_size > 1024*1024 )
-                                               fprintf(fmap, "mapping %s %4lluMB 0x%0llX -> 0x%0llX\n", prot, it->sfm_size/(1024*1024),
-                                                                                                                       it->sfm_address, it->sfm_address+it->sfm_size);
-                                       else
-                                               fprintf(fmap, "mapping %s %4lluKB 0x%0llX -> 0x%0llX\n", prot, it->sfm_size/1024,
-                                                                                                                       it->sfm_address, it->sfm_address+it->sfm_size);
-                               }
-                               for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
-                                       fprintf(fmap, "%s\n", it->layout->getID().name);
-                                       const std::vector<MachOLayoutAbstraction::Segment>&     segs = it->layout->getSegments();
-                                       for (int i=0; i < segs.size(); ++i) {
-                                               const MachOLayoutAbstraction::Segment& seg = segs[i];
-                                               fprintf(fmap, "\t%16s 0x%0llX -> 0x%0llX\n", seg.name(), seg.newAddress(), seg.newAddress()+seg.size());
+                               // install signal handlers to delete temp file if program is killed 
+                               sCleanupFile = tempCachePath;
+                               ::signal(SIGINT, cleanup);
+                               ::signal(SIGBUS, cleanup);
+                               ::signal(SIGSEGV, cleanup);
+                               
+                               // create var/db/dyld dirs if needed
+                               char dyldDirs[1024];
+                               strcpy(dyldDirs, fCacheFilePath);
+                               char* lastSlash = strrchr(dyldDirs, '/');
+                               if ( lastSlash != NULL )
+                                       lastSlash[1] = '\0';
+                               struct stat stat_buf;
+                               if ( stat(dyldDirs, &stat_buf) != 0 ) {
+                                       const char* afterSlash = &dyldDirs[1];
+                                       char* slash;
+                                       while ( (slash = strchr(afterSlash, '/')) != NULL ) {
+                                               *slash = '\0';
+                                               ::mkdir(dyldDirs, S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH);
+                                               *slash = '/';
+                                               afterSlash = slash+1;
                                        }
                                }
-                               if ( warnings.size() > 0 ) {
-                                       fprintf(fmap, "# Warnings:\n");
-                                       for (std::vector<const char*>::iterator it=warnings.begin(); it != warnings.end(); ++it) {
-                                               fprintf(fmap, "# %s\n", *it);
+                               
+                               // create temp file for cache
+                               int fd = ::open(tempCachePath, O_CREAT | O_RDWR | O_TRUNC, 0644);       
+                               if ( fd == -1 )
+                                       throwf("can't create temp file %s, errnor=%d", tempCachePath, errno);
+                                       
+                               // try to allocate whole cache file contiguously
+                               fstore_t fcntlSpec = { F_ALLOCATECONTIG|F_ALLOCATEALL, F_PEOFPOSMODE, 0, cacheFileSize, 0 };
+                               ::fcntl(fd, F_PREALLOCATE, &fcntlSpec);
+
+                               // write out cache file
+                               if ( verbose )
+                                       fprintf(stderr, "update_dyld_shared_cache: writing cache to disk\n");
+                               if ( ::pwrite(fd, inMemoryCache, cacheFileSize, 0) != cacheFileSize )
+                                       throwf("write() failure creating cache file, errno=%d", errno);
+                               if ( progress ) {
+                                       // assuming write takes 35% of time
+                                       fprintf(stdout, "%3u/%u\n", (archIndex+1)*90, archCount*100);
+                               }
+                               
+                               // flush to disk and close
+                               int result = ::fcntl(fd, F_FULLFSYNC, NULL);
+                               if ( result == -1 ) 
+                                       fprintf(stderr, "update_dyld_shared_cache: warning, fcntl(F_FULLFSYNC) failed with errno=%d for %s\n", errno, tempCachePath);
+                               result = ::close(fd);
+                               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
+                               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;
+                               
+                               // restore default signal handlers
+                               ::signal(SIGINT, SIG_DFL);
+                               ::signal(SIGBUS, SIG_DFL);
+                               ::signal(SIGSEGV, SIG_DFL);
+
+                               // generate human readable "map" file that shows the layout of the cache file
+                               if ( verbose )
+                                       fprintf(stderr, "update_dyld_shared_cache: writing .map file to disk\n");
+                               char mapFilePath[strlen(fCacheFilePath)+16];
+                               sprintf(mapFilePath, "%s.map", fCacheFilePath);
+                               char tempMapFilePath[strlen(fCacheFilePath)+32];
+                               sprintf(tempMapFilePath, "%s.map%u", fCacheFilePath, getpid());
+                               FILE* fmap = ::fopen(tempMapFilePath, "w");     
+                               if ( fmap == NULL ) {
+                                       fprintf(stderr, "can't create map file %s, errnor=%d", tempCachePath, errno);
+                               }
+                               else {
+                                       for(std::vector<shared_file_mapping_np>::iterator it = fMappings.begin(); it != fMappings.end(); ++it) {
+                                               const char* prot = "RW";
+                                               if ( it->sfm_init_prot == (VM_PROT_EXECUTE|VM_PROT_READ) )
+                                                       prot = "EX";
+                                               else if ( it->sfm_init_prot == VM_PROT_READ )
+                                                       prot = "RO";
+                                               else if ( it->sfm_init_prot == (VM_PROT_EXECUTE|VM_PROT_WRITE|VM_PROT_READ) )
+                                                       prot = "WX";
+                                               if ( it->sfm_size > 1024*1024 )
+                                                       fprintf(fmap, "mapping %s %4lluMB 0x%0llX -> 0x%0llX\n", prot, it->sfm_size/(1024*1024),
+                                                                                                                               it->sfm_address, it->sfm_address+it->sfm_size);
+                                               else
+                                                       fprintf(fmap, "mapping %s %4lluKB 0x%0llX -> 0x%0llX\n", prot, it->sfm_size/1024,
+                                                                                                                               it->sfm_address, it->sfm_address+it->sfm_size);
+                                       }
+
+                                       fprintf(fmap, "linkedit   %4uKB 0x%0llX -> 0x%0llX weak binding info\n",                
+                                                               (fOffsetOfExportInfoInCombinedLinkedit-fOffsetOfWeakBindInfoInCombinedLinkedit)/1024,
+                                                               fLinkEditsStartAddress+fOffsetOfWeakBindInfoInCombinedLinkedit,
+                                                               fLinkEditsStartAddress+fOffsetOfExportInfoInCombinedLinkedit);
+                                       fprintf(fmap, "linkedit   %4uKB 0x%0llX -> 0x%0llX export info\n",              
+                                                               (fOffsetOfBindInfoInCombinedLinkedit-fOffsetOfExportInfoInCombinedLinkedit)/1024,
+                                                               fLinkEditsStartAddress+fOffsetOfExportInfoInCombinedLinkedit,
+                                                               fLinkEditsStartAddress+fOffsetOfBindInfoInCombinedLinkedit);
+                                       fprintf(fmap, "linkedit   %4uKB 0x%0llX -> 0x%0llX binding info\n",             
+                                                               (fOffsetOfLazyBindInfoInCombinedLinkedit-fOffsetOfBindInfoInCombinedLinkedit)/1024,
+                                                               fLinkEditsStartAddress+fOffsetOfBindInfoInCombinedLinkedit,
+                                                               fLinkEditsStartAddress+fOffsetOfLazyBindInfoInCombinedLinkedit);
+                                       fprintf(fmap, "linkedit   %4uKB 0x%0llX -> 0x%0llX lazy binding info\n",                
+                                                               (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),
+                                                               fLinkEditsStartAddress+fOffsetOfOldSymbolTableInfoInCombinedLinkedit,
+                                                               fLinkEditsStartAddress+fLinkEditsTotalOptimizedSize);                           
+                                       
+                                       for(typename std::vector<LayoutInfo>::const_iterator it = fDylibs.begin(); it != fDylibs.end(); ++it) {
+                                               fprintf(fmap, "%s\n", it->layout->getID().name);
+                                               const std::vector<MachOLayoutAbstraction::Segment>&     segs = it->layout->getSegments();
+                                               for (int i=0; i < segs.size(); ++i) {
+                                                       const MachOLayoutAbstraction::Segment& seg = segs[i];
+                                                       fprintf(fmap, "\t%16s 0x%0llX -> 0x%0llX\n", seg.name(), seg.newAddress(), seg.newAddress()+seg.size());
+                                               }
+                                       }
+                                       if ( warnings.size() > 0 ) {
+                                               fprintf(fmap, "# Warnings:\n");
+                                               for (std::vector<const char*>::iterator it=warnings.begin(); it != warnings.end(); ++it) {
+                                                       fprintf(fmap, "# %s\n", *it);
+                                               }
                                        }
+                                       fclose(fmap);
+                                       result = ::rename(tempMapFilePath, mapFilePath);
                                }
-                               fclose(fmap);
                        }
                        
                        // free in memory cache
                        vm_deallocate(mach_task_self(), (vm_address_t)inMemoryCache, allocatedCacheSize);
                        inMemoryCache = NULL;
+                       if ( progress ) {
+                               // finished
+                               fprintf(stdout, "%3u/%u\n", (archIndex+1)*100, archCount*100);
+                       }
                }
                catch (...){
                        // remove temp cache file
@@ -1592,10 +2242,32 @@ static void parsePathsFile(const char* filePath, std::vector<const char*>& paths
 }
 
 
-static void scanForSharedDylibs(const char* rootPath, const char* dirOfPathFiles, const std::set<cpu_type_t>& onlyArchs)
+
+static void setSharedDylibs(const char* rootPath, bool usesOverlay, const std::set<ArchPair>& onlyArchs, std::vector<const char*> rootsPaths)
+{
+       // set file system root
+       ArchGraph::setFileSystemRoot(rootPath, usesOverlay);
+
+       // initialize all architectures requested
+       for(std::set<ArchPair>::iterator a = onlyArchs.begin(); a != onlyArchs.end(); ++a)
+               ArchGraph::addArchPair(*a);
+
+       // add roots to graph
+       for(std::vector<const char*>::const_iterator it = rootsPaths.begin(); it != rootsPaths.end(); ++it) 
+               ArchGraph::addRoot(*it, onlyArchs);
+
+       // determine shared dylibs
+       for(std::set<ArchPair>::iterator a = onlyArchs.begin(); a != onlyArchs.end(); ++a)
+               ArchGraph::findSharedDylibs(*a);
+}
+
+
+static void scanForSharedDylibs(const char* rootPath, bool usesOverlay, const char* dirOfPathFiles, const std::set<ArchPair>& onlyArchs)
 {
        char rootDirOfPathFiles[strlen(rootPath)+strlen(dirOfPathFiles)+2];
-       if ( strlen(rootPath) != 0 ) {
+       // in -overlay mode, still look for roots in /var/db/dyld
+       // in -root mode, look for roots in /rootpath/var/db/dyld
+       if ( !usesOverlay && (strlen(rootPath) != 0) ) {
                strcpy(rootDirOfPathFiles, rootPath);
                strcat(rootDirOfPathFiles, dirOfPathFiles);
                dirOfPathFiles = rootDirOfPathFiles;
@@ -1624,24 +2296,17 @@ static void scanForSharedDylibs(const char* rootPath, const char* dirOfPathFiles
                }
        }
        ::closedir(dir);
-
-       // set file system root
-       ArchGraph::setFileSystemRoot(rootPath);
-
-       // initialize all architectures requested
-       for(std::set<cpu_type_t>::iterator a = onlyArchs.begin(); a != onlyArchs.end(); ++a)
-               ArchGraph::addArch(*a);
-
-       // add roots to graph
-       for(std::vector<const char*>::iterator it = rootsPaths.begin(); it != rootsPaths.end(); ++it) 
-               ArchGraph::addRoot(*it, onlyArchs);
-
-       // determine shared dylibs
-       for(std::set<cpu_type_t>::iterator a = onlyArchs.begin(); a != onlyArchs.end(); ++a)
-               ArchGraph::findSharedDylibs(*a);
        
        if ( rootsPaths.size() == 0 )
                fprintf(stderr, "update_dyld_shared_cache: warning, no entries found in shared_region_roots\n");
+       setSharedDylibs(rootPath, usesOverlay, onlyArchs, rootsPaths);
+}
+
+static void setSharedDylibs(const char* rootPath, bool usesOverlay, const char* pathsFile, const std::set<ArchPair>& onlyArchs)
+{
+       std::vector<const char*> rootsPaths;
+       parsePathsFile(pathsFile, rootsPaths);
+       setSharedDylibs(rootPath, usesOverlay, onlyArchs, rootsPaths);
 }
 
 
@@ -1688,48 +2353,60 @@ static void deleteOrphanTempCacheFiles()
 
 
 
-static bool updateSharedeCacheFile(const char* rootPath, const char* cacheDir, const std::set<cpu_type_t>& onlyArchs, 
-                                                                       bool force, bool alphaSort, bool optimize, bool deleteExistingFirst)
+static bool updateSharedeCacheFile(const char* rootPath, bool usesOverlay, const char* cacheDir, const std::set<ArchPair>& onlyArchs, 
+                                                                       bool force, bool alphaSort, bool optimize, bool deleteExistingFirst, bool verify, bool keepSignatures)
 {
        bool didUpdate = false;
        // get dyld load address info
-       UniversalMachOLayout* dyldLayout = new UniversalMachOLayout("/usr/lib/dyld", &onlyArchs);
-
+       UniversalMachOLayout* dyldLayout = NULL;
+       char dyldPath[1024];
+       strlcpy(dyldPath, rootPath, 1024);
+       strlcat(dyldPath, "/usr/lib/dyld", 1024);
+       struct stat stat_buf;
+       if ( stat(dyldPath, &stat_buf) == 0 ) {
+               dyldLayout = new UniversalMachOLayout(dyldPath, &onlyArchs);
+       }
+       else {
+               dyldLayout = new UniversalMachOLayout("/usr/lib/dyld", &onlyArchs);
+       }
        const int archCount = onlyArchs.size();
        int index = 0;
-       for(std::set<cpu_type_t>::iterator a = onlyArchs.begin(); a != onlyArchs.end(); ++a, ++index) {
-               const MachOLayoutAbstraction* dyldLayoutForArch = dyldLayout->getArch(*a);
-               if ( dyldLayoutForArch == NULL )
-                       throw "dyld not avaiable for specified architecture";
-               uint64_t dyldBaseAddress = dyldLayoutForArch->getBaseAddress();
-               switch ( *a ) {
+       for(std::set<ArchPair>::iterator a = onlyArchs.begin(); a != onlyArchs.end(); ++a, ++index) {
+               const MachOLayoutAbstraction* dyldLayoutForArch = dyldLayout->getSlice(*a);
+               uint64_t dyldBaseAddress = 0;
+               if ( dyldLayoutForArch != NULL )
+                       dyldBaseAddress = dyldLayoutForArch->getBaseAddress();
+               else
+                       fprintf(stderr, "update_dyld_shared_cache: warning, dyld not available for specified architectures\n");
+               switch ( a->arch ) {
                        case CPU_TYPE_POWERPC:
                                {
-                                       SharedCache<ppc> cache(ArchGraph::getArch(*a), alphaSort, dyldBaseAddress);
-               #if __i386__
+               #if __i386__ || __x86_64__
                                        // <rdar://problem/5217377> Rosetta does not work with optimized dyld shared cache
-                                       didUpdate |= cache.update(rootPath, cacheDir, force, false, deleteExistingFirst, index, archCount);
+                                       SharedCache<ppc> cache(ArchGraph::graphForArchPair(*a), rootPath, alphaSort, verify, false, usesOverlay, dyldBaseAddress);
+                                       didUpdate |= cache.update(usesOverlay, force, false, deleteExistingFirst, index, archCount, keepSignatures);
                #else
-                                       didUpdate |= cache.update(rootPath, cacheDir, force, optimize, deleteExistingFirst, index, archCount);
+                                       SharedCache<ppc> cache(ArchGraph::graphForArchPair(*a), rootPath, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress);
+                                       didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
                #endif
                                }
                                break;
-                       case CPU_TYPE_POWERPC64:
+                       case CPU_TYPE_I386:
                                {
-                                       SharedCache<ppc64> cache(ArchGraph::getArch(*a), alphaSort, dyldBaseAddress);
-                                       didUpdate |= cache.update(rootPath, cacheDir, force, optimize, deleteExistingFirst, index, archCount);
+                                       SharedCache<x86> cache(ArchGraph::graphForArchPair(*a), rootPath, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress);
+                                       didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
                                }
                                break;
-                       case CPU_TYPE_I386:
+                       case CPU_TYPE_X86_64:
                                {
-                                       SharedCache<x86> cache(ArchGraph::getArch(*a), alphaSort, dyldBaseAddress);
-                                       didUpdate |= cache.update(rootPath, cacheDir, force, optimize, deleteExistingFirst, index, archCount);
+                                       SharedCache<x86_64> cache(ArchGraph::graphForArchPair(*a), rootPath, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress);
+                                       didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
                                }
                                break;
-                       case CPU_TYPE_X86_64:
+                       case CPU_TYPE_ARM:
                                {
-                                       SharedCache<x86_64> cache(ArchGraph::getArch(*a), alphaSort, dyldBaseAddress);
-                                       didUpdate |= cache.update(rootPath, cacheDir, force, optimize, deleteExistingFirst, index, archCount);
+                                       SharedCache<arm> cache(ArchGraph::graphForArchPair(*a), rootPath, alphaSort, verify, optimize, usesOverlay, dyldBaseAddress);
+                                       didUpdate |= cache.update(usesOverlay, force, optimize, deleteExistingFirst, index, archCount, keepSignatures);
                                }
                                break;
                }
@@ -1743,192 +2420,163 @@ static bool updateSharedeCacheFile(const char* rootPath, const char* cacheDir, c
 
 static void usage()
 {
-       fprintf(stderr, "update_dyld_shared_cache [-force] [-root dir] [-arch arch] [-debug]\n");
-}
-
-// flag so that we only update cache once per invocation
-static bool doNothingAndDrainQueue = false;
-
-static kern_return_t do_update_cache(cpu_type_t arch, bool deleteExistingCacheFileFirst)
-{
-       if ( !doNothingAndDrainQueue ) {
-               std::set<cpu_type_t> onlyArchs;
-               onlyArchs.insert(arch);
-               try {
-                       scanForSharedDylibs("", "/var/db/dyld/shared_region_roots/", onlyArchs);
-                       if ( updateSharedeCacheFile("", DYLD_SHARED_CACHE_DIR, onlyArchs, false, false, true, deleteExistingCacheFileFirst) )
-                               fprintf(stderr, "update_dyld_shared_cache[%u] regenerated cache for arch=%s\n", getpid(), ArchGraph::archName(arch));
-               }
-               catch (const char* msg) {
-                       fprintf(stderr, "update_dyld_shared_cache[%u] for arch=%s failed: %s\n", getpid(), ArchGraph::archName(arch), msg);
-                       return KERN_FAILURE;
-               }
-               // <rdar://problem/6378354> only build one cache file per life of process
-               doNothingAndDrainQueue = true;
-       }
-       return KERN_SUCCESS;
-}
-
-
-
-kern_return_t do_dyld_shared_cache_missing(mach_port_t dyld_port, cpu_type_t arch)
-{
-       return do_update_cache(arch, false);
-}
-
-
-kern_return_t do_dyld_shared_cache_out_of_date(mach_port_t dyld_port, cpu_type_t arch)
-{
-       // If cache exists but is out of date, delete the file while building the new one.
-       // This will stop dyld from pinging update_dyld_share_cache while the cache is being built.
-       return do_update_cache(arch, true);
+       fprintf(stderr, "update_dyld_shared_cache [-force] [-root dir] [-overlay dir] [-arch arch] [-debug]\n");
 }
 
 
 int main(int argc, const char* argv[])
 {
-       mach_port_t mp;
-       if ( bootstrap_check_in(bootstrap_port, "com.apple.dyld", &mp) == KERN_SUCCESS ) {
-               // started by launchd
-               mach_msg_size_t mxmsgsz = sizeof(union __RequestUnion__do_dyld_server_subsystem) + MAX_TRAILER_SIZE;
-               doNothingAndDrainQueue = false;
-               while ( mach_msg_server(dyld_server_server, mxmsgsz, mp, MACH_RCV_TIMEOUT) == KERN_SUCCESS ) {
-                       // keep processing messages
-                       doNothingAndDrainQueue = true;
-                       // but set flag so work is no longer done.
-                       // This is because the rest of the tool leaks and processing more than once
-                       // can hog system resources: <rdar://problem/5392427> 9A516 - Keep getting disk full errors
-                       // We drain the queue of messages because there is usually are a couple of duplicate messages.
-                       // It is ok to miss some messages.  If the cache is out of date or missing, some new process
-                       // will discover it and send another message.  
-               }
-               return 0;
-       }
-       else {
-               // started as command line tool
-               std::set<cpu_type_t> onlyArchs;
-               const char* rootPath = "";
-               bool force = false;
-               bool alphaSort = false;
-               bool optimize = true;
-               bool makeSymLink = false;
+       std::set<ArchPair> onlyArchs;
+       const char* rootPath = "";
+       const char* dylibListFile = NULL;
+       bool force = false;
+       bool alphaSort = false;
+       bool optimize = true;
+       bool hasRoot = false;
+       bool hasOverlay = false;
+       bool verify = false;
+       bool keepSignatures = false;
        
-               try {
-                       // parse command line options
-                       for(int i=1; i < argc; ++i) {
-                               const char* arg = argv[i];
-                               if ( arg[0] == '-' ) {
-                                       if ( strcmp(arg, "-debug") == 0 ) {
-                                               verbose = true;
-                                       }
-                                       else if ( strcmp(arg, "-force") == 0 ) {
-                                               force = true;
-                                       }
-                                       else if ( strcmp(arg, "-sort_by_name") == 0 ) {
-                                               alphaSort = true;
-                                       }
-                                       else if ( strcmp(arg, "-opt") == 0 ) {
-                                               optimize = true;
-                                       }
-                                       else if ( strcmp(arg, "-no_opt") == 0 ) {
-                                               optimize = false;
-                                       }
-                                       else if ( (strcmp(arg, "-root") == 0) || (strcmp(arg, "--root") == 0) ) {
-                                               rootPath = argv[++i];
-                                               if ( rootPath == NULL )
-                                                       throw "-root missing path argument";
-                                               // strip tailing slashes
-                                               int len = strlen(rootPath)-1;
-                                               if (  rootPath[len] == '/' ) {
-                                                       char* newRootPath = strdup(rootPath);
-                                                       while ( newRootPath[len] == '/' )       
-                                                               newRootPath[len--] = '\0';
-                                                       rootPath = newRootPath;
-                                               }
-                                       }
-                                       else if ( strcmp(arg, "-arch") == 0 ) {
-                                               const char* arch = argv[++i];
-                                               if ( strcmp(arch, "ppc") == 0 ) 
-                                                       onlyArchs.insert(CPU_TYPE_POWERPC);
-                                               else if ( strcmp(arch, "ppc64") == 0 )
-                                                       onlyArchs.insert(CPU_TYPE_POWERPC64);
-                                               else if ( strcmp(arch, "i386") == 0 )
-                                                       onlyArchs.insert(CPU_TYPE_I386);
-                                               else if ( strcmp(arch, "x86_64") == 0 )
-                                                       onlyArchs.insert(CPU_TYPE_X86_64);
-                                               else 
-                                                       throwf("unknown architecture %s", arch);
-                                       }
-                                       else if ( strcmp(arg, "-universal_boot") == 0 ) {
-                               #if __ppc__
-                                               throwf("universal_boot option can only be used on Intel machines");
-                               #endif
-                                               onlyArchs.insert(CPU_TYPE_POWERPC);
-                                               onlyArchs.insert(CPU_TYPE_I386);
-                                               makeSymLink = true;
-                                       }
-                                       else {
-                                               usage();
-                                               throwf("unknown option: %s\n", arg);
-                                       }
+       try {
+               // parse command line options
+               for(int i=1; i < argc; ++i) {
+                       const char* arg = argv[i];
+                       if ( arg[0] == '-' ) {
+                               if ( strcmp(arg, "-debug") == 0 ) {
+                                       verbose = true;
+                               }
+                               else if ( strcmp(arg, "-force") == 0 ) {
+                                       force = true;
+                               }
+                               else if ( strcmp(arg, "-verify") == 0 ) {
+                                       verify = true;
+                               }
+                               else if ( strcmp(arg, "-sort_by_name") == 0 ) {
+                                       alphaSort = true;
+                               }
+                               else if ( strcmp(arg, "-progress") == 0 ) {
+                                       progress = true;
+                               }
+                               else if ( strcmp(arg, "-opt") == 0 ) {
+                                       optimize = true;
+                               }
+                               else if ( strcmp(arg, "-no_opt") == 0 ) {
+                                       optimize = false;
+                               }
+                               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 )
+                                               throw "cannot use both -root and -overlay";
+                                       rootPath = argv[++i];
+                                       if ( rootPath == NULL )
+                                               throw "-root missing path argument";
+                                       hasRoot = true;
+                               }
+                               else if ( strcmp(arg, "-overlay") == 0 ) {
+                                       if ( hasRoot )
+                                               throw "cannot use both -root and -overlay";
+                                       rootPath = argv[++i];
+                                       if ( rootPath == NULL )
+                                               throw "-root missing path argument";
+                                       hasOverlay = true;
+                               }
+                               else if ( strcmp(arg, "-arch") == 0 ) {
+                                       const char* arch = argv[++i];
+                                       if ( strcmp(arch, "ppc") == 0 ) 
+                                               onlyArchs.insert(ArchPair(CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL));
+                                       else if ( strcmp(arch, "i386") == 0 )
+                                               onlyArchs.insert(ArchPair(CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL));
+                                       else if ( strcmp(arch, "x86_64") == 0 )
+                                               onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL));
+                                       else if ( strcmp(arch, "armv4t") == 0 )
+                                               onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V4T));
+                                       else if ( strcmp(arch, "armv5") == 0 )
+                                               onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V5TEJ));
+                                       else if ( strcmp(arch, "armv6") == 0 )
+                                               onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6));
+                                       else if ( strcmp(arch, "armv7") == 0 )
+                                               onlyArchs.insert(ArchPair(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7));
+                                       else 
+                                               throwf("unknown architecture %s", arch);
+                               }
+                               else if ( strcmp(arg, "-universal_boot") == 0 ) {
+                       #if __ppc__
+                                       throwf("universal_boot option can only be used on Intel machines");
+                       #endif
+                                       onlyArchs.insert(ArchPair(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL));
+                                       onlyArchs.insert(ArchPair(CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL));
                                }
                                else {
                                        usage();
                                        throwf("unknown option: %s\n", arg);
                                }
                        }
-                                       
-                       // if no restrictions specified, use architectures that work on this machine
-                       if ( onlyArchs.size() == 0 ) {
-                               int available;
-                               size_t len = sizeof(int);
-                       #if __ppc__     
-                               onlyArchs.insert(CPU_TYPE_POWERPC);
-                               if ( (sysctlbyname("hw.optional.64bitops", &available, &len, NULL, 0) == 0) && available )
-                                       onlyArchs.insert(CPU_TYPE_POWERPC64);
-                       #elif __i386__
-                               onlyArchs.insert(CPU_TYPE_I386);
-                               onlyArchs.insert(CPU_TYPE_POWERPC);     // assume rosetta always available
-                               if ( (sysctlbyname("hw.optional.x86_64", &available, &len, NULL, 0) == 0) && available )
-                                       onlyArchs.insert(CPU_TYPE_X86_64);
-                       #else
-                               #error unknown architecture
-                       #endif
+                       else {
+                               usage();
+                               throwf("unknown option: %s\n", arg);
                        }
-                       
-                       if ( geteuid() != 0 )
-                               throw "you must be root to run this tool";
-                       
-                       // build list of shared dylibs
-                       scanForSharedDylibs(rootPath, "/var/db/dyld/shared_region_roots/", onlyArchs);
-                       updateSharedeCacheFile(rootPath, DYLD_SHARED_CACHE_DIR, onlyArchs, force, alphaSort, optimize, false);
-                       
-                       // To make a universal bootable image with dyld caches,
-                       // build the rosetta cache and symlink ppc to point to it.
-                       // A rosetta cache is just an unoptimized ppc cache, so ppc machine can use it too.
-                       // rdar://problem/5498469
-                       if ( makeSymLink ) {
-                               char symLinkLocation[1024];
-                               strcpy(symLinkLocation, rootPath);
-                               strcat(symLinkLocation, DYLD_SHARED_CACHE_DIR);
-                               strcat(symLinkLocation, DYLD_SHARED_CACHE_BASE_NAME);
-                               strcat(symLinkLocation, SharedCache<ppc>::filename(true));
-                               char symLinkTarget[1024];
-                               strcpy(symLinkTarget, DYLD_SHARED_CACHE_BASE_NAME);
-                               strcat(symLinkTarget, SharedCache<ppc>::filename(false));
-                               if ( symlink(symLinkTarget, symLinkLocation) == -1 ) {
-                                       if ( errno != EEXIST )
-                                               throwf("symlink() returned errno=%d", errno);
-                               }
+               }
+                               
+               // strip tailing slashes on -root or -overlay
+               if ( rootPath[0] != '\0' ) {
+                       int len = strlen(rootPath)-1;
+                       if (  rootPath[len] == '/' ) {
+                               char* newRootPath = strdup(rootPath);
+                               while ( newRootPath[len] == '/' )       
+                                       newRootPath[len--] = '\0';
+                               rootPath = newRootPath;
                        }
                }
-               catch (const char* msg) {
-                       fprintf(stderr, "update_dyld_shared_cache failed: %s\n", msg);
-                       return 1;
+               
+               // 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));
+                       }
+                       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 unknown architecture
+               #endif
                }
                
-               return 0;
+               if ( !verify && (geteuid() != 0) )
+                       throw "you must be root to run this tool";
+               
+               // build list of shared dylibs
+               if ( dylibListFile != NULL )
+                       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, 
+                                                               false, verify, keepSignatures);
        }
+       catch (const char* msg) {
+               fprintf(stderr, "update_dyld_shared_cache failed: %s\n", msg);
+               return 1;
+       }
+       
+       return 0;
 }
 
 
index 1274a7f0478437103f108ef7366bdd9262860401..23f89cbde1341333932f7daea3e7164f2576421b 100644 (file)
 
 #include "ImageLoader.h"
 
-// in libc.a
-extern "C" void _spin_lock(uint32_t*);
-extern "C" void _spin_unlock(uint32_t*);
 
 uint32_t                                                               ImageLoader::fgImagesUsedFromSharedCache = 0;
 uint32_t                                                               ImageLoader::fgImagesWithUsedPrebinding = 0;
 uint32_t                                                               ImageLoader::fgImagesRequiringNoFixups = 0;
+uint32_t                                                               ImageLoader::fgImagesRequiringCoalescing = 0;
+uint32_t                                                               ImageLoader::fgImagesHasWeakDefinitions = 0;
 uint32_t                                                               ImageLoader::fgTotalRebaseFixups = 0;
 uint32_t                                                               ImageLoader::fgTotalBindFixups = 0;
 uint32_t                                                               ImageLoader::fgTotalBindSymbolsResolved = 0;
@@ -56,61 +55,39 @@ uint64_t                                                            ImageLoader::fgTotalBytesPreFetched = 0;
 uint64_t                                                               ImageLoader::fgTotalLoadLibrariesTime;
 uint64_t                                                               ImageLoader::fgTotalRebaseTime;
 uint64_t                                                               ImageLoader::fgTotalBindTime;
+uint64_t                                                               ImageLoader::fgTotalWeakBindTime;
+uint64_t                                                               ImageLoader::fgTotalDOF;
 uint64_t                                                               ImageLoader::fgTotalInitTime;
-uintptr_t                                                              ImageLoader::fgNextSplitSegAddress = 0x90000000;
 uint16_t                                                               ImageLoader::fgLoadOrdinal = 0;
-uintptr_t                                                              Segment::fgNextPIEDylibAddress = 0;
+uintptr_t                                                              ImageLoader::fgNextPIEDylibAddress = 0;
 
 
-void ImageLoader::init(const char* path, uint64_t offsetInFat, dev_t device, ino_t inode, time_t modDate)
+
+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), 
+       fAllLibraryChecksumsAndLoadAddressesMatch(false), fLeaveMapped(false), fNeverUnload(false),
+       fHideSymbols(false), fMatchByInstallName(false),
+       fRegisteredDOF(false), fAllLazyPointersBound(false), fBeingRemoved(false), fAddFuncNotified(false),
+       fPathOwnedByImage(false), fWeakSymbolsBound(false)
 {
-       fPathHash = 0;
-       fPath = path;
-       fLogicalPath = NULL;
-       fDevice = device;
-       fInode = inode;
-       fLastModified = modDate;
-       fOffsetInFatFile = offsetInFat;
-       fLibraries = NULL;
-       fLibrariesCount = 0;
-       fDlopenReferenceCount = 0;
-       fStaticReferenceCount = 0;
-       fDynamicReferenceCount = 0;
-       fDynamicReferences = NULL;
-       fDepth = 0;
-       fLoadOrder = fgLoadOrdinal++;
-       fState = 0;
-       fAllLibraryChecksumsAndLoadAddressesMatch = false;
-       fLeaveMapped = false;
-       fNeverUnload = false;
-       fHideSymbols = false;
-       fMatchByInstallName = false;
-       fRegisteredDOF = false;
-#if IMAGE_NOTIFY_SUPPORT
-       fAnnounced = false;
-#endif
-       fAllLazyPointersBound = false;
-       fBeingRemoved = false;
-       fAddFuncNotified = false;
-       fPathOwnedByImage = false;
-#if RECURSIVE_INITIALIZER_LOCK
-       fInitializerRecursiveLock = NULL;
-#else
-       fInitializerLock = 0;
-#endif
        if ( fPath != NULL )
                fPathHash = hash(fPath);
 }
 
 
-ImageLoader::ImageLoader(const char* path, uint64_t offsetInFat, const struct stat& info)
+void ImageLoader::deleteImage(ImageLoader* image)
 {
-       init(path, offsetInFat, info.st_dev, info.st_ino, info.st_mtime);
-}
-
-ImageLoader::ImageLoader(const char* moduleName)
-{
-       init(moduleName, 0, 0, 0, 0);
+       // this cannot be done in destructor because libImage() is implemented
+       // in a subclass
+       for(unsigned int i=0; i < image->libraryCount(); ++i) {
+               ImageLoader* lib = image->libImage(i);
+               if ( lib != NULL )
+                       lib->fStaticReferenceCount--;
+       }
+       delete image;
 }
 
 
@@ -118,15 +95,6 @@ ImageLoader::~ImageLoader()
 {
        if ( fPathOwnedByImage && (fPath != NULL) ) 
                delete [] fPath;
-       if ( fLogicalPath != NULL ) 
-               delete [] fLogicalPath;
-       if ( fLibraries != NULL ) {
-               for (uint32_t i = 0; i < fLibrariesCount; ++i) {
-                       if ( fLibraries[i].image != NULL )
-                               fLibraries[i].image->fStaticReferenceCount--;
-               }
-               delete [] fLibraries;
-       }
        if ( fDynamicReferences != NULL ) {
                for (std::set<const ImageLoader*>::iterator it = fDynamicReferences->begin(); it != fDynamicReferences->end(); ++it ) {
                        const_cast<ImageLoader*>(*it)->fDynamicReferenceCount--;
@@ -135,10 +103,17 @@ ImageLoader::~ImageLoader()
        }
 }
 
+void ImageLoader::setFileInfo(dev_t device, ino_t inode, time_t modDate)
+{
+       fDevice = device;
+       fInode = inode;
+       fLastModified = modDate;
+}
+
 void ImageLoader::setMapped(const LinkContext& context)
 {
        fState = dyld_image_state_mapped;
-       context.notifySingle(dyld_image_state_mapped, this->machHeader(), fPath, fLastModified);
+       context.notifySingle(dyld_image_state_mapped, this);  // note: can throw exception
 }
 
 void ImageLoader::addDynamicReference(const ImageLoader* target)
@@ -190,29 +165,6 @@ void ImageLoader::setPathUnowned(const char* path)
        fPathHash = hash(fPath);
 }
 
-void ImageLoader::setLogicalPath(const char* path)
-{
-       if ( fPath == NULL ) {
-               // no physical path set yet, so use this path as physical
-               this->setPath(path);
-       }
-       else if ( strcmp(path, fPath) == 0 ) {
-               // do not set logical path because it is the same as the physical path
-               fLogicalPath = NULL;
-       }
-       else {
-               fLogicalPath = new char[strlen(path)+1];
-               strcpy((char*)fLogicalPath, path);
-       }
-}
-
-const char* ImageLoader::getLogicalPath() const
-{
-       if ( fLogicalPath != NULL )
-               return fLogicalPath;
-       else
-               return fPath;
-}
 
 uint32_t ImageLoader::hash(const char* path)
 {
@@ -251,11 +203,6 @@ const char* ImageLoader::getShortName() const
        return fPath; 
 }
 
-uint64_t ImageLoader::getOffsetInFatFile() const
-{
-       return fOffsetInFatFile;
-}
-
 void ImageLoader::setLeaveMapped()
 {
        fLeaveMapped = true;
@@ -285,11 +232,10 @@ bool ImageLoader::containsAddress(const void* addr) const
 {
        if ( ! this->isLinked() )
                return false;
-       for(ImageLoader::SegmentIterator it = this->beginSegments(); it != this->endSegments(); ++it ) {
-               Segment* seg = *it;
-               const uint8_t* start = (const uint8_t*)seg->getActualLoadAddress(this);
-               const uint8_t* end = start + seg->getSize();
-               if ( (start <= addr) && (addr < end) && !seg->unaccessible() )
+       for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
+               const uint8_t* start = (const uint8_t*)segActualLoadAddress(i);
+               const uint8_t* end = (const uint8_t*)segActualEndAddress(i);
+               if ( (start <= addr) && (addr < end) && !segUnaccessible(i) )
                        return true;
        }
        return false;
@@ -297,10 +243,9 @@ bool ImageLoader::containsAddress(const void* addr) const
 
 bool ImageLoader::overlapsWithAddressRange(const void* start, const void* end) const
 {
-       for(ImageLoader::SegmentIterator it = this->beginSegments(); it != this->endSegments(); ++it ) {
-               Segment* seg = *it;
-               const uint8_t* segStart = (const uint8_t*)(seg->getActualLoadAddress(this));
-               const uint8_t* segEnd = segStart + seg->getSize();
+       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 ( (start <= segStart) && (segStart < end) )
                        return true;
                if ( (start <= segEnd) && (segEnd < end) )
@@ -313,11 +258,10 @@ bool ImageLoader::overlapsWithAddressRange(const void* start, const void* end) c
 
 void ImageLoader::getMappedRegions(MappedRegion*& regions) const
 {
-       for(ImageLoader::SegmentIterator it = this->beginSegments(); it != this->endSegments(); ++it ) {
-               Segment* seg = *it;
+       for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
                MappedRegion region;
-               region.address = seg->getActualLoadAddress(this);
-               region.size = seg->getSize();
+               region.address = segActualLoadAddress(i);
+               region.size = segSize(i);
                *regions++ = region;
        }
 }
@@ -340,25 +284,25 @@ const ImageLoader::Symbol* ImageLoader::findExportedSymbolInDependentImagesExcep
        
        // search self
        if ( notInImgageList(this, dsiStart, dsiCur) ) {
-               sym = this->findExportedSymbol(name, NULL, false, foundIn);
+               sym = this->findExportedSymbol(name, false, foundIn);
                if ( sym != NULL )
                        return sym;
                *dsiCur++ = this;
        }
 
        // search directly dependent libraries
-       for (uint32_t i=0; i < fLibrariesCount; ++i) {
-               ImageLoader* dependentImage = fLibraries[i].image;
+       for(unsigned int i=0; i < libraryCount(); ++i) {
+               ImageLoader* dependentImage = libImage(i);
                if ( (dependentImage != NULL) && notInImgageList(dependentImage, dsiStart, dsiCur) ) {
-                       const ImageLoader::Symbol* sym = dependentImage->findExportedSymbol(name, NULL, false, foundIn);
+                       const ImageLoader::Symbol* sym = dependentImage->findExportedSymbol(name, false, foundIn);
                        if ( sym != NULL )
                                return sym;
                }
        }
        
        // search indirectly dependent libraries
-       for (uint32_t i=0; i < fLibrariesCount; ++i) {
-               ImageLoader* dependentImage = fLibraries[i].image;
+       for(unsigned int i=0; i < libraryCount(); ++i) {
+               ImageLoader* dependentImage = libImage(i);
                if ( (dependentImage != NULL) && notInImgageList(dependentImage, dsiStart, dsiCur) ) {
                        *dsiCur++ = dependentImage; 
                        const ImageLoader::Symbol* sym = dependentImage->findExportedSymbolInDependentImagesExcept(name, dsiStart, dsiCur, dsiEnd, foundIn);
@@ -394,7 +338,7 @@ void ImageLoader::link(const LinkContext& context, bool forceLazysBound, bool pr
        //dyld::log("ImageLoader::link(%s) refCount=%d, neverUnload=%d\n", this->getPath(), fStaticReferenceCount, fNeverUnload);
        
        uint64_t t0 = mach_absolute_time();
-       this->recursiveLoadLibraries(context,loaderRPaths);
+       this->recursiveLoadLibraries(context, preflightOnly, loaderRPaths);
        context.notifyBatch(dyld_image_state_dependents_mapped);
        
        // we only do the loading step for preflights
@@ -411,20 +355,26 @@ void ImageLoader::link(const LinkContext& context, bool forceLazysBound, bool pr
        
        uint64_t t3 = mach_absolute_time();
        this->recursiveBind(context, forceLazysBound);
+
+       uint64_t t4 = mach_absolute_time();
+       this->weakBind(context);
        context.notifyBatch(dyld_image_state_bound);
 
-       uint64_t t4 = 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();     
 
        
        fgTotalLoadLibrariesTime += t1 - t0;
        fgTotalRebaseTime += t3 - t2;
        fgTotalBindTime += t4 - t3;
+       fgTotalWeakBindTime += t5 - t4;
+       fgTotalDOF += t6 - t5;
        
        // done with initial dylib loads
-       Segment::fgNextPIEDylibAddress = 0;
+       fgNextPIEDylibAddress = 0;
 }
 
 
@@ -445,16 +395,11 @@ bool ImageLoader::decrementDlopenReferenceCount()
 
 void ImageLoader::runInitializers(const LinkContext& context)
 {
-#if IMAGE_NOTIFY_SUPPORT
-       ImageLoader* newImages[context.imageCount()];
-       ImageLoader** end = newImages;
-       this->recursiveImageAnnouncement(context, end);  // build bottom up list images being added
-       context.notifyAdding(newImages, end-newImages); // tell anyone who cares about these
-#endif
-
        uint64_t t1 = mach_absolute_time();
-       this->recursiveInitialization(context, mach_thread_self());
+       mach_port_t this_thread = mach_thread_self();
+       this->recursiveInitialization(context, this_thread);
        context.notifyBatch(dyld_image_state_initialized);
+       mach_port_deallocate(mach_task_self(), this_thread);
        uint64_t t2 = mach_absolute_time();
        fgTotalInitTime += (t2 - t1);
 }
@@ -467,10 +412,10 @@ void ImageLoader::bindAllLazyPointers(const LinkContext& context, bool recursive
 
                if ( recursive ) {
                        // bind lower level libraries first
-                       for(unsigned int i=0; i < fLibrariesCount; ++i){
-                               DependentLibrary& libInfo = fLibraries[i];
-                               if ( libInfo.image != NULL )
-                                       libInfo.image->bindAllLazyPointers(context, recursive);
+                       for(unsigned int i=0; i < libraryCount(); ++i) {
+                               ImageLoader* dependentImage = libImage(i);
+                               if ( dependentImage != NULL )
+                                       dependentImage->bindAllLazyPointers(context, recursive);
                        }
                }
                // bind lazies in this image
@@ -479,83 +424,6 @@ void ImageLoader::bindAllLazyPointers(const LinkContext& context, bool recursive
 }
 
 
-intptr_t ImageLoader::assignSegmentAddresses(const LinkContext& context)
-{
-       // preflight and calculate slide if needed
-       intptr_t slide = 0;
-       if ( this->segmentsCanSlide() && this->segmentsMustSlideTogether() ) {
-               bool needsToSlide = false;
-               uintptr_t lowAddr = UINTPTR_MAX;
-               uintptr_t highAddr = 0;
-               for(ImageLoader::SegmentIterator it = this->beginSegments(); it != this->endSegments(); ++it ) {
-                       Segment* seg = *it;
-                       const uintptr_t segLow = seg->getPreferredLoadAddress();
-                       const uintptr_t segHigh = (segLow + seg->getSize() + 4095) & -4096;
-                       if ( segLow < lowAddr )
-                               lowAddr = segLow;
-                       if ( segHigh > highAddr )
-                               highAddr = segHigh;
-                               
-                       if ( !seg->hasPreferredLoadAddress() || !Segment::reserveAddressRange(seg->getPreferredLoadAddress(), seg->getSize()) )
-                               needsToSlide = true;
-               }
-               if ( needsToSlide ) {
-                       // find a chunk of address space to hold all segments
-                       uintptr_t addr = Segment::reserveAnAddressRange(highAddr-lowAddr, context);
-                       slide = addr - lowAddr;
-               }
-       } 
-       else if ( ! this->segmentsCanSlide() ) {
-               for(ImageLoader::SegmentIterator it = this->beginSegments(); it != this->endSegments(); ++it ) {
-                       Segment* seg = *it;
-                       if ( strcmp(seg->getName(), "__PAGEZERO") == 0 )
-                               continue;
-                       if ( !Segment::reserveAddressRange(seg->getPreferredLoadAddress(), seg->getSize()) )
-                               throw "can't map";
-               }
-       }
-       else {
-               // mach-o does not support independently sliding segments
-       }
-       return slide;
-}
-
-
-void ImageLoader::mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context)
-{
-       if ( context.verboseMapping )
-               dyld::log("dyld: Mapping %s\n", this->getPath());
-       // find address range for image
-       intptr_t slide = this->assignSegmentAddresses(context);
-       // map in all segments
-       for(ImageLoader::SegmentIterator it = this->beginSegments(); it != this->endSegments(); ++it ) {
-               Segment* seg = *it;
-               seg->map(fd, offsetInFat, slide, this, context);                
-       }
-       // update slide to reflect load location                        
-       this->setSlide(slide);
-}
-
-void ImageLoader::mapSegments(const void* memoryImage, uint64_t imageLen, const LinkContext& context)
-{
-       if ( context.verboseMapping )
-               dyld::log("dyld: Mapping memory %p\n", memoryImage);
-       // find address range for image
-       intptr_t slide = this->assignSegmentAddresses(context);
-       // map in all segments
-       for(ImageLoader::SegmentIterator it = this->beginSegments(); it != this->endSegments(); ++it ) {
-               Segment* seg = *it;
-               seg->map(memoryImage, slide, this, context);            
-       }
-       // update slide to reflect load location                        
-       this->setSlide(slide);
-       // set R/W permissions on all segments at slide location
-       for(ImageLoader::SegmentIterator it = this->beginSegments(); it != this->endSegments(); ++it ) {
-               Segment* seg = *it;
-               seg->setPermissions(context, this);             
-       }
-}
-
 bool ImageLoader::allDependentLibrariesAsWhenPreBound() const
 {
        return fAllLibraryChecksumsAndLoadAddressesMatch;
@@ -573,10 +441,10 @@ unsigned int ImageLoader::recursiveUpdateDepth(unsigned int maxDepth)
                
                // get depth of dependents
                unsigned int minDependentDepth = maxDepth;
-               for(unsigned int i=0; i < fLibrariesCount; ++i) {
-                       DependentLibrary& libInfo = fLibraries[i];
-                       if ( libInfo.image != NULL ) {
-                               unsigned int d = libInfo.image->recursiveUpdateDepth(maxDepth);
+               for(unsigned int i=0; i < libraryCount(); ++i) {
+                       ImageLoader* dependentImage = libImage(i);
+                       if ( dependentImage != NULL ) {
+                               unsigned int d = dependentImage->recursiveUpdateDepth(maxDepth);
                                if ( d < minDependentDepth )
                                        minDependentDepth = d;
                        }
@@ -590,17 +458,15 @@ unsigned int ImageLoader::recursiveUpdateDepth(unsigned int maxDepth)
 }
 
 
-void ImageLoader::recursiveLoadLibraries(const LinkContext& context, const RPathChain& loaderRPaths)
+void ImageLoader::recursiveLoadLibraries(const LinkContext& context, bool preflightOnly, const RPathChain& loaderRPaths)
 {
        if ( fState < dyld_image_state_dependents_mapped ) {
                // break cycles
                fState = dyld_image_state_dependents_mapped;
                
                // get list of libraries this image needs
-               fLibrariesCount = this->doGetDependentLibraryCount();
-               fLibraries = new DependentLibrary[fLibrariesCount];
-               bzero(fLibraries, sizeof(DependentLibrary)*fLibrariesCount);
-               DependentLibraryInfo libraryInfos[fLibrariesCount]; 
+               //dyld::log("ImageLoader::recursiveLoadLibraries() %ld = %d*%ld\n", fLibrariesCount*sizeof(DependentLibrary), fLibrariesCount, sizeof(DependentLibrary));
+               DependentLibraryInfo libraryInfos[fLibraryCount]; 
                this->doGetDependentLibraries(libraryInfos);
                
                // get list of rpaths that this image adds
@@ -610,74 +476,85 @@ void ImageLoader::recursiveLoadLibraries(const LinkContext& context, const RPath
                
                // try to load each
                bool canUsePrelinkingInfo = true; 
-               for(unsigned int i=0; i < fLibrariesCount; ++i){
-                       DependentLibrary& requiredLib = fLibraries[i];
+               for(unsigned int i=0; i < fLibraryCount; ++i){
+                       ImageLoader* dependentLib;
+                       bool depLibReExported = false;
+                       bool depLibReRequired = false;
+                       bool depLibCheckSumsMatch = false;
                        DependentLibraryInfo& requiredLibInfo = libraryInfos[i];
+#if DYLD_SHARED_CACHE_SUPPORT
+                       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);
+                               continue;
+                       }
+#endif
                        try {
-                               bool depNamespace = false;
-                               requiredLib.image = context.loadLibrary(requiredLibInfo.name, true, depNamespace, this->getPath(), &thisRPaths);
-                               if ( requiredLib.image == this ) {
+                               dependentLib = context.loadLibrary(requiredLibInfo.name, true, this->getPath(), &thisRPaths);
+                               if ( dependentLib == this ) {
                                        // found circular reference, perhaps DYLD_LIBARY_PATH is causing this rdar://problem/3684168 
-                                       requiredLib.image = context.loadLibrary(requiredLibInfo.name, false, depNamespace, NULL, NULL);
-                                       if ( requiredLib.image != this )
+                                       dependentLib = context.loadLibrary(requiredLibInfo.name, false, NULL, NULL);
+                                       if ( dependentLib != this )
                                                dyld::warn("DYLD_ setting caused circular dependency in %s\n", this->getPath());
                                }
                                if ( fNeverUnload )
-                                       requiredLib.image->setNeverUnload();
-                               requiredLib.image->fStaticReferenceCount += 1;
-                               LibraryInfo actualInfo = requiredLib.image->doGetLibraryInfo();
-                               requiredLib.required = requiredLibInfo.required;
-                               requiredLib.checksumMatches = ( actualInfo.checksum == requiredLibInfo.info.checksum );
-                               requiredLib.isReExported = requiredLibInfo.reExported;
-                               if ( ! requiredLib.isReExported ) {
-                                       requiredLib.isSubFramework = requiredLib.image->isSubframeworkOf(context, this);
-                                       requiredLib.isReExported = requiredLib.isSubFramework || this->hasSubLibrary(context, requiredLib.image);
+                                       dependentLib->setNeverUnload();
+                               dependentLib->fStaticReferenceCount += 1;
+                               LibraryInfo actualInfo = dependentLib->doGetLibraryInfo();
+                               depLibReRequired = requiredLibInfo.required;
+                               depLibCheckSumsMatch = ( actualInfo.checksum == requiredLibInfo.info.checksum );
+                               depLibReExported = requiredLibInfo.reExported;
+                               if ( ! depLibReExported ) {
+                                       // for pre-10.5 binaries that did not use LC_REEXPORT_DYLIB
+                                       depLibReExported = dependentLib->isSubframeworkOf(context, this) || this->hasSubLibrary(context, dependentLib);
                                }
                                // check found library version is compatible
                                if ( actualInfo.minVersion < requiredLibInfo.info.minVersion ) {
                                        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,
-                                                       requiredLib.image->getShortName(), actualInfo.minVersion >> 16, (actualInfo.minVersion >> 8) & 0xff, actualInfo.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 ( !requiredLib.checksumMatches || (requiredLib.image->getSlide() != 0) )
+                               if ( !depLibCheckSumsMatch || (dependentLib->getSlide() != 0) )
                                        canUsePrelinkingInfo = false;
                                //if ( context.verbosePrebinding ) {
                                //      if ( !requiredLib.checksumMatches )
                                //              fprintf(stderr, "dyld: checksum mismatch, (%u v %u) for %s referencing %s\n", 
-                               //                      requiredLibInfo.info.checksum, actualInfo.checksum, this->getPath(),    requiredLib.image->getPath());          
-                               //      if ( requiredLib.image->getSlide() != 0 )
-                               //              fprintf(stderr, "dyld: dependent library slid for %s referencing %s\n", this->getPath(), requiredLib.image->getPath());         
+                               //                      requiredLibInfo.info.checksum, actualInfo.checksum, this->getPath(),    dependentLib->getPath());               
+                               //      if ( dependentLib->getSlide() != 0 )
+                               //              fprintf(stderr, "dyld: dependent library slid for %s referencing %s\n", this->getPath(), dependentLib->getPath());              
                                //}
                        }
                        catch (const char* msg) {
                                //if ( context.verbosePrebinding )
-                               //      fprintf(stderr, "dyld: exception during processing for %s referencing %s\n", this->getPath(), requiredLib.image->getPath());            
+                               //      fprintf(stderr, "dyld: exception during processing for %s referencing %s\n", this->getPath(), dependentLib->getPath());         
                                if ( requiredLibInfo.required ) {
                                        fState = dyld_image_state_mapped;
                                        dyld::throwf("Library not loaded: %s\n  Referenced from: %s\n  Reason: %s", requiredLibInfo.name, this->getPath(), msg);
                                }
                                // ok if weak library not found
-                               requiredLib.image = NULL;
+                               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);
                }
                fAllLibraryChecksumsAndLoadAddressesMatch = canUsePrelinkingInfo;
 
                // tell each to load its dependents
-               for(unsigned int i=0; i < fLibrariesCount; ++i){
-                       DependentLibrary& lib = fLibraries[i];
-                       if ( lib.image != NULL ) {      
-                               lib.image->recursiveLoadLibraries(context, thisRPaths);
+               for(unsigned int i=0; i < libraryCount(); ++i) {
+                       ImageLoader* dependentImage = libImage(i);
+                       if ( dependentImage != NULL ) { 
+                               dependentImage->recursiveLoadLibraries(context, preflightOnly, thisRPaths);
                        }
                }
                
                // do deep prebind check
                if ( fAllLibraryChecksumsAndLoadAddressesMatch ) {
-                       for(unsigned int i=0; i < fLibrariesCount; ++i){
-                               const DependentLibrary& libInfo = fLibraries[i];
-                               if ( libInfo.image != NULL ) {
-                                       if ( !libInfo.image->allDependentLibrariesAsWhenPreBound() )
+                       for(unsigned int i=0; i < libraryCount(); ++i){
+                               ImageLoader* dependentImage = libImage(i);
+                               if ( dependentImage != NULL ) { 
+                                       if ( !dependentImage->allDependentLibrariesAsWhenPreBound() )
                                                fAllLibraryChecksumsAndLoadAddressesMatch = false;
                                }
                        }
@@ -700,17 +577,17 @@ void ImageLoader::recursiveRebase(const LinkContext& context)
                
                try {
                        // rebase lower level libraries first
-                       for(unsigned int i=0; i < fLibrariesCount; ++i){
-                               DependentLibrary& libInfo = fLibraries[i];
-                               if ( libInfo.image != NULL )
-                                       libInfo.image->recursiveRebase(context);
+                       for(unsigned int i=0; i < libraryCount(); ++i) {
+                               ImageLoader* dependentImage = libImage(i);
+                               if ( dependentImage != NULL )
+                                       dependentImage->recursiveRebase(context);
                        }
                                
                        // rebase this image
                        doRebase(context);
                        
                        // notify
-                       context.notifySingle(dyld_image_state_rebased, this->machHeader(), fPath, fLastModified);
+                       context.notifySingle(dyld_image_state_rebased, this);
                }
                catch (const char* msg) {
                        // this image is not rebased
@@ -735,19 +612,18 @@ void ImageLoader::recursiveBind(const LinkContext& context, bool forceLazysBound
        
                try {
                        // bind lower level libraries first
-                       for(unsigned int i=0; i < fLibrariesCount; ++i){
-                               DependentLibrary& libInfo = fLibraries[i];
-                               if ( libInfo.image != NULL )
-                                       libInfo.image->recursiveBind(context, forceLazysBound);
+                       for(unsigned int i=0; i < libraryCount(); ++i) {
+                               ImageLoader* dependentImage = libImage(i);
+                               if ( dependentImage != NULL )
+                                       dependentImage->recursiveBind(context, forceLazysBound);
                        }
                        // bind this image
                        this->doBind(context, forceLazysBound); 
-                       this->doUpdateMappingPermissions(context);
                        // mark if lazys are also bound
                        if ( forceLazysBound || this->usablePrebinding(context) )
                                fAllLazyPointersBound = true;
                                
-                       context.notifySingle(dyld_image_state_bound, this->machHeader(), fPath, fLastModified);
+                       context.notifySingle(dyld_image_state_bound, this);
                }
                catch (const char* msg) {
                        // restore state
@@ -757,31 +633,116 @@ void ImageLoader::recursiveBind(const LinkContext& context, bool forceLazysBound
        }
 }
 
-
-#if IMAGE_NOTIFY_SUPPORT
-void ImageLoader::recursiveImageAnnouncement(const LinkContext& context, ImageLoader**& newImages)
+void ImageLoader::weakBind(const LinkContext& context)
 {
-       if ( ! fAnnounced ) {
-               // break cycles
-               fAnnounced = true;
-               
-               // announce lower level libraries first
-               for(unsigned int i=0; i < fLibrariesCount; ++i){
-                       DependentLibrary& libInfo = fLibraries[i];
-                       if ( libInfo.image != NULL )
-                               libInfo.image->recursiveImageAnnouncement(context, newImages);
+       if ( context.verboseWeakBind )
+               dyld::log("dyld: weak bind start:\n");
+       // get set of ImageLoaders that participate in coalecsing
+       ImageLoader* imagesNeedingCoalescing[fgImagesRequiringCoalescing];
+       int count = context.getCoalescedImages(imagesNeedingCoalescing);
+       
+       // count how many have not already had weakbinding done
+       int countNotYetWeakBound = 0;
+       int countOfImagesWithWeakDefinitions = 0;
+       for(int i=0; i < count; ++i) {
+               if ( ! imagesNeedingCoalescing[i]->fWeakSymbolsBound )
+                       ++countNotYetWeakBound;
+               if ( imagesNeedingCoalescing[i]->hasCoalescedExports() )
+                       ++countOfImagesWithWeakDefinitions;
+       }
+
+       // don't need to do any coalescing if only one image has overrides, or all have already been done
+       if ( (countOfImagesWithWeakDefinitions > 1) && (countNotYetWeakBound > 0) ) {
+               // make symbol iterators for each
+               ImageLoader::CoalIterator iterators[count];
+               ImageLoader::CoalIterator* sortedIts[count];
+               for(int i=0; i < count; ++i) {
+                       imagesNeedingCoalescing[i]->initializeCoalIterator(iterators[i], i);
+                       sortedIts[i] = &iterators[i];
+                       if ( context.verboseWeakBind )
+                               dyld::log("dyld: weak bind load order %d/%d for %s\n", i, count, imagesNeedingCoalescing[i]->getPath());
                }
                
-               // add to list of images to notify about
-               *newImages++ = this;
-               //dyld::log("next size = %d\n", newImages.size());
+               // walk all symbols keeping iterators in sync by 
+               // only ever incrementing the iterator with the lowest symbol 
+               int doneCount = 0;
+               while ( doneCount != count ) {
+                       //for(int i=0; i < count; ++i)
+                       //      dyld::log("sym[%d]=%s ", sortedIts[i]->loadOrder, sortedIts[i]->symbolName);
+                       //dyld::log("\n");
+                       // increment iterator with lowest symbol
+                       if ( sortedIts[0]->image->incrementCoalIterator(*sortedIts[0]) )
+                               ++doneCount; 
+                       // re-sort iterators
+                       for(int i=1; i < count; ++i) {
+                               int result = strcmp(sortedIts[i-1]->symbolName, sortedIts[i]->symbolName);
+                               if ( result == 0 )
+                                       sortedIts[i-1]->symbolMatches = true;
+                               if ( result > 0 ) {
+                                       // new one is bigger then next, so swap
+                                       ImageLoader::CoalIterator* temp = sortedIts[i-1];
+                                       sortedIts[i-1] = sortedIts[i];
+                                       sortedIts[i] = temp;
+                               }
+                               if ( result < 0 )
+                                       break;
+                       }
+                       // process all matching symbols just before incrementing the lowest one that matches
+                       if ( sortedIts[0]->symbolMatches && !sortedIts[0]->done ) {
+                               const char* nameToCoalesce = sortedIts[0]->symbolName;
+                               // pick first symbol in load order (and non-weak overrides weak)
+                               uintptr_t targetAddr = 0;
+                               ImageLoader* targetImage = NULL;
+                               for(int i=0; i < count; ++i) {
+                                       if ( strcmp(iterators[i].symbolName, nameToCoalesce) == 0 ) {
+                                               if ( context.verboseWeakBind )
+                                                       dyld::log("dyld: weak bind, found %s weak=%d in %s \n", nameToCoalesce, iterators[i].weakSymbol, iterators[i].image->getPath());
+                                               if ( iterators[i].weakSymbol ) {
+                                                       if ( targetAddr == 0 ) {
+                                                               targetAddr = iterators[i].image->getAddressCoalIterator(iterators[i], context);
+                                                               if ( targetAddr != 0 )
+                                                                       targetImage = iterators[i].image;
+                                                       }
+                                               }
+                                               else {
+                                                       targetAddr = iterators[i].image->getAddressCoalIterator(iterators[i], context);
+                                                       if ( targetAddr != 0 ) {
+                                                               targetImage = iterators[i].image;
+                                                               // strong implementation found, stop searching
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                               }
+                               if ( context.verboseWeakBind )
+                                       dyld::log("dyld: weak binding all uses of %s to copy from %s\n", nameToCoalesce, targetImage->getShortName());
+                               
+                               // tell each to bind to this symbol (unless already bound)
+                               if ( targetAddr != 0 ) {
+                                       for(int i=0; i < count; ++i) {
+                                               if ( strcmp(iterators[i].symbolName, nameToCoalesce) == 0 ) {
+                                                       if ( context.verboseWeakBind )
+                                                               dyld::log("dyld: weak bind, setting all uses of %s in %s to 0x%lX from %s\n", nameToCoalesce, iterators[i].image->getShortName(), targetAddr, targetImage->getShortName());
+                                                       if ( ! iterators[i].image->fWeakSymbolsBound )
+                                                               iterators[i].image->updateUsesCoalIterator(iterators[i], targetAddr, targetImage, context);
+                                                       iterators[i].symbolMatches = false; 
+                                               }
+                                       }
+                               }
+                               
+                       }
+               }
                
-               // remember that this image wants to be notified about other images
-                if ( this->hasImageNotification() )
-                       context.addImageNeedingNotification(this);
+               // mark all as having all weak symbols bound
+               for(int i=0; i < count; ++i) {
+                       imagesNeedingCoalescing[i]->fWeakSymbolsBound = true;
+               }
        }
+       if ( context.verboseWeakBind )
+               dyld::log("dyld: weak bind end\n");
 }
-#endif
+
+
 
 void ImageLoader::recursiveGetDOFSections(const LinkContext& context, std::vector<DOFInfo>& dofs)
 {
@@ -790,10 +751,10 @@ void ImageLoader::recursiveGetDOFSections(const LinkContext& context, std::vecto
                fRegisteredDOF = true;
                
                // gather lower level libraries first
-               for(unsigned int i=0; i < fLibrariesCount; ++i){
-                       DependentLibrary& libInfo = fLibraries[i];
-                       if ( libInfo.image != NULL )
-                               libInfo.image->recursiveGetDOFSections(context, dofs);
+               for(unsigned int i=0; i < libraryCount(); ++i) {
+                       ImageLoader* dependentImage = libImage(i);
+                       if ( dependentImage != NULL )
+                               dependentImage->recursiveGetDOFSections(context, dofs);
                }
                this->doGetDOFSections(context, dofs);
        }
@@ -822,25 +783,21 @@ void ImageLoader::recursiveSpinUnLock()
 
 void ImageLoader::recursiveInitialization(const LinkContext& context, mach_port_t this_thread)
 {
-#if RECURSIVE_INITIALIZER_LOCK
        recursive_lock lock_info(this_thread);
        recursiveSpinLock(lock_info);
-#else
-       _spin_lock(&fInitializerLock);
-#endif
 
        if ( fState < dyld_image_state_dependents_initialized-1 ) {
                uint8_t oldState = fState;
                // break cycles
                fState = dyld_image_state_dependents_initialized-1;
-
                try {
                        // initialize lower level libraries first
-                       for(unsigned int i=0; i < fLibrariesCount; ++i){
-                               DependentLibrary& libInfo = fLibraries[i];
+                       for(unsigned int i=0; i < libraryCount(); ++i) {
+                               ImageLoader* dependentImage = libImage(i);
+                               if ( dependentImage != NULL )
                                // don't try to initialize stuff "above" me
-                               if ( (libInfo.image != NULL) && (libInfo.image->fDepth >= fDepth) )
-                                       libInfo.image->recursiveInitialization(context, this_thread);
+                               if ( (dependentImage != NULL) && (dependentImage->fDepth >= fDepth) )
+                                       dependentImage->recursiveInitialization(context, this_thread);
                        }
                        
                        // record termination order
@@ -850,32 +807,25 @@ void ImageLoader::recursiveInitialization(const LinkContext& context, mach_port_
                        // let objc know we are about to initalize this image
                        fState = dyld_image_state_dependents_initialized;
                        oldState = fState;
-                       context.notifySingle(dyld_image_state_dependents_initialized, this->machHeader(), fPath, fLastModified);
+                       context.notifySingle(dyld_image_state_dependents_initialized, this);
 
                        // initialize this image
                        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->machHeader(), fPath, fLastModified);
+                       context.notifySingle(dyld_image_state_initialized, this);
                }
                catch (const char* msg) {
                        // this image is not initialized
                        fState = oldState;
-               #if RECURSIVE_INITIALIZER_LOCK
                        recursiveSpinUnLock();
-               #else
-                       _spin_unlock(&fInitializerLock);
-               #endif
                        throw;
                }
        }
        
-#if RECURSIVE_INITIALIZER_LOCK
        recursiveSpinUnLock();
-#else
-       _spin_unlock(&fInitializerLock);
-#endif
 }
 
 
@@ -889,11 +839,11 @@ static void printTime(const char* msg, uint64_t partTime, uint64_t totalTime)
                }
        }
        if ( partTime < sUnitsPerSecond ) {
-               uint32_t milliSecondsTimeTen = (partTime*10000)/sUnitsPerSecond;
-               uint32_t milliSeconds = milliSecondsTimeTen/10;
+               uint32_t milliSecondsTimesHundred = (partTime*100000)/sUnitsPerSecond;
+               uint32_t milliSeconds = milliSecondsTimesHundred/100;
                uint32_t percentTimesTen = (partTime*1000)/totalTime;
                uint32_t percent = percentTimesTen/10;
-               dyld::log("%s: %u.%u milliseconds (%u.%u%%)\n", msg, milliSeconds, milliSecondsTimeTen-milliSeconds*10, percent, percentTimesTen-percent*10);
+               dyld::log("%s: %u.%02u milliseconds (%u.%u%%)\n", msg, milliSeconds, milliSecondsTimesHundred-milliSeconds*100, percent, percentTimesTen-percent*10);
        }
        else {
                uint32_t secondsTimeTen = (partTime*10)/sUnitsPerSecond;
@@ -926,10 +876,9 @@ static char* commatize(uint64_t in, char* out)
 }
 
 
-
 void ImageLoader::printStatistics(unsigned int imageCount)
 {
-       uint64_t totalTime = fgTotalLoadLibrariesTime + fgTotalRebaseTime + fgTotalBindTime + fgTotalInitTime;
+       uint64_t totalTime = fgTotalLoadLibrariesTime + fgTotalRebaseTime + fgTotalBindTime + fgTotalWeakBindTime + fgTotalDOF + fgTotalInitTime;
        char commaNum1[40];
        char commaNum2[40];
 
@@ -937,6 +886,7 @@ void ImageLoader::printStatistics(unsigned int imageCount)
        dyld::log("total images loaded:  %d (%u from dyld shared cache, %u needed no fixups)\n", imageCount, fgImagesUsedFromSharedCache, fgImagesRequiringNoFixups);
        dyld::log("total segments mapped: %u, into %llu pages with %llu pages pre-fetched\n", fgTotalSegmentsMapped, fgTotalBytesMapped/4096, fgTotalBytesPreFetched/4096);
        printTime("total images loading time", fgTotalLoadLibrariesTime, totalTime);
+       printTime("total dtrace DOF registration time", fgTotalDOF, totalTime);
        dyld::log("total rebase fixups:  %s\n", commatize(fgTotalRebaseFixups, commaNum1));
        printTime("total rebase fixups time", fgTotalRebaseTime, totalTime);
        dyld::log("total binding fixups: %s\n", commatize(fgTotalBindFixups, commaNum1));
@@ -948,8 +898,9 @@ void ImageLoader::printStatistics(unsigned int imageCount)
                                commatize(fgTotalBindSymbolsResolved, commaNum1), avgInt, avgTenths);
        }
        printTime("total binding fixups time", fgTotalBindTime, totalTime);
+       printTime("total weak binding fixups time", fgTotalWeakBindTime, totalTime);
        dyld::log("total bindings lazily fixed up: %s of %s\n", commatize(fgTotalLazyBindFixups, commaNum1), commatize(fgTotalPossibleLazyBindFixups, commaNum2));
-       printTime("total init time time", fgTotalInitTime, totalTime);
+       printTime("total initializer time", fgTotalInitTime, totalTime);
 }
 
 
@@ -983,129 +934,5 @@ void ImageLoader::addSuffix(const char* path, const char* suffix, char* result)
 }
 
 
-void Segment::map(int fd, uint64_t offsetInFatWrapper, intptr_t slide, const ImageLoader* image, const ImageLoader::LinkContext& context)
-{
-       vm_offset_t fileOffset = this->getFileOffset() + offsetInFatWrapper;
-       vm_size_t size = this->getFileSize();
-       void* requestedLoadAddress = (void*)(this->getPreferredLoadAddress() + slide);
-       int protection = 0;
-       if ( !this->unaccessible() ) {
-               if ( this->executable() )
-                       protection   |= PROT_EXEC;
-               if ( this->readable() )
-                       protection   |= PROT_READ;
-               if ( this->writeable() )
-                       protection   |= PROT_WRITE;
-       }
-#if __i386__
-       // initially map __IMPORT segments R/W so dyld can update them
-       if ( this->readOnlyImportStubs() )
-               protection |= PROT_WRITE;
-#endif
-       // wholly zero-fill segments have nothing to mmap() in
-       if ( size > 0 ) {
-               void* loadAddress = mmap(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, this->getName(), image->getPath());
-       }
-       // update stats
-       ++ImageLoader::fgTotalSegmentsMapped;
-       ImageLoader::fgTotalBytesMapped += size;
-       if ( context.verboseMapping )
-               dyld::log("%18s at %p->%p with permissions %c%c%c\n", this->getName(), requestedLoadAddress, (char*)requestedLoadAddress+this->getFileSize()-1,
-                       (protection & PROT_READ) ? 'r' : '.',  (protection & PROT_WRITE) ? 'w' : '.',  (protection & PROT_EXEC) ? 'x' : '.' );
-}
-
-void Segment::map(const void* memoryImage, intptr_t slide, const ImageLoader* image, const ImageLoader::LinkContext& context)
-{
-       vm_address_t loadAddress = this->getPreferredLoadAddress() + slide;
-       vm_address_t srcAddr = (uintptr_t)memoryImage + this->getFileOffset();
-       vm_size_t size = this->getFileSize();
-       kern_return_t r = vm_copy(mach_task_self(), srcAddr, size, loadAddress);
-       if ( r != KERN_SUCCESS ) 
-               throw "can't map segment";
-               
-       if ( context.verboseMapping )
-               dyld::log("%18s at %p->%p\n", this->getName(), (char*)loadAddress, (char*)loadAddress+this->getFileSize()-1);
-}
-
-void Segment::setPermissions(const ImageLoader::LinkContext& context, const ImageLoader* image)
-{
-       vm_prot_t protection = 0;
-       if ( !this->unaccessible() ) {
-               if ( this->executable() )
-                       protection   |= VM_PROT_EXECUTE;
-               if ( this->readable() )
-                       protection   |= VM_PROT_READ;
-               if ( this->writeable() )
-                       protection   |= VM_PROT_WRITE;
-       }
-       vm_address_t addr = this->getActualLoadAddress(image);
-       vm_size_t size = this->getSize();
-       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 ( context.verboseMapping ) {
-               dyld::log("%18s at %p->%p altered permissions to %c%c%c\n", this->getName(), (char*)addr, (char*)addr+this->getFileSize()-1,
-                       (protection & PROT_READ) ? 'r' : '.',  (protection & PROT_WRITE) ? 'w' : '.',  (protection & PROT_EXEC) ? 'x' : '.' );
-       }
-}      
-
-void Segment::tempWritable(const ImageLoader::LinkContext& context, const ImageLoader* image)
-{
-       vm_address_t addr = this->getActualLoadAddress(image);
-       vm_size_t size = this->getSize();
-       const bool setCurrentPermissions = false;
-       vm_prot_t protection = VM_PROT_WRITE | VM_PROT_READ;
-       if ( this->executable() )
-               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 ( context.verboseMapping ) {
-               dyld::log("%18s at %p->%p altered permissions to %c%c%c\n", this->getName(), (char*)addr, (char*)addr+this->getFileSize()-1,
-                       (protection & PROT_READ) ? 'r' : '.',  (protection & PROT_WRITE) ? 'w' : '.',  (protection & PROT_EXEC) ? 'x' : '.' );
-       }
-}
-
-
-bool Segment::hasTrailingZeroFill()
-{
-       return ( this->writeable() && (this->getSize() > this->getFileSize()) );
-}
-
-
-uintptr_t Segment::reserveAnAddressRange(size_t length, const ImageLoader::LinkContext& context)
-{
-       vm_address_t addr = 0;
-       vm_size_t size = length;
-       // in PIE programs, load initial dylibs after main executable so they don't have fixed addresses either
-       if ( fgNextPIEDylibAddress != 0 ) {
-               addr = fgNextPIEDylibAddress + (arc4random() & 0x3) * 4096; // add small random padding between dylibs
-               kern_return_t r = vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_FIXED);
-               if ( r == KERN_SUCCESS ) {
-                       fgNextPIEDylibAddress = addr + size;
-                       return addr;
-               }
-               fgNextPIEDylibAddress = 0;
-       }
-       kern_return_t r = vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE);
-       if ( r != KERN_SUCCESS ) 
-               throw "out of address space";
-       
-       return addr;
-}
-
-bool Segment::reserveAddressRange(uintptr_t start, size_t length)
-{
-       vm_address_t addr = start;
-       vm_size_t size = length;
-       kern_return_t r = vm_allocate(mach_task_self(), &addr, size, false /*only this range*/);
-       if ( r != KERN_SUCCESS ) 
-               return false;
-       return true;
-}
-
 
 
index e6c24806afc08414dc1b954b8b909b3da5ea2e12..587a339d2b83612eb64b00d105ddcb0011b7a49b 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2008 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #define __IMAGELOADER__
 
 #include <sys/types.h>
+#include <unistd.h>
 #include <mach/mach_time.h> // struct mach_timebase_info
 #include <mach/mach_init.h> // struct mach_thread_self
+#include <mach/shared_region.h>
+#include <mach-o/loader.h> 
+#include <mach-o/nlist.h> 
 #include <stdint.h>
 #include <vector>
 #include <set>
+#include <new>
 
 #include "mach-o/dyld_images.h"
 #include "mach-o/dyld_priv.h"
 
+#if __i386__
+       #define SHARED_REGION_BASE SHARED_REGION_BASE_I386
+       #define SHARED_REGION_SIZE SHARED_REGION_SIZE_I386
+#elif __x86_64__
+       #define SHARED_REGION_BASE SHARED_REGION_BASE_X86_64
+       #define SHARED_REGION_SIZE SHARED_REGION_SIZE_X86_64
+#elif __ppc__
+       #define SHARED_REGION_BASE SHARED_REGION_BASE_PPC
+       #define SHARED_REGION_SIZE SHARED_REGION_SIZE_PPC
+#elif __ppc64__
+       #define SHARED_REGION_BASE SHARED_REGION_BASE_PPC64
+       #define SHARED_REGION_SIZE SHARED_REGION_SIZE_PPC64
+#elif __arm__
+       #define SHARED_REGION_BASE SHARED_REGION_BASE_ARM
+       #define SHARED_REGION_SIZE SHARED_REGION_SIZE_ARM
+#endif
+
 
-#define SPLIT_SEG_SHARED_REGION_SUPPORT 0
-#define SPLIT_SEG_DYLIB_SUPPORT (__ppc__ || __i386__)
+
+#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 IMAGE_NOTIFY_SUPPORT 0
-#define RECURSIVE_INITIALIZER_LOCK 1
 #define SUPPORT_OLD_CRT_INITIALIZATION (__ppc__ || __i386__)
+#define COMPRESSED_DYLD_INFO_SUPPORT (__i386__ || __x86_64__)
+#define CORESYMBOLICATION_SUPPORT   (__i386__ || __x86_64__)
+#if __arm__
+       #define INITIAL_IMAGE_COUNT 100
+#else
+       #define INITIAL_IMAGE_COUNT 200
+#endif
 
+#define CODESIGNING_SUPPORT __arm__
 
 // utilities
 namespace dyld {
@@ -55,6 +85,15 @@ namespace dyld {
 };
 
 
+#if __LP64__
+       struct macho_header                             : public mach_header_64  {};
+       struct macho_nlist                              : public nlist_64  {};  
+#else
+       struct macho_header                             : public mach_header  {};
+       struct macho_nlist                              : public nlist  {};     
+#endif
+
+
 struct ProgramVars
 {
        const void*             mh;
@@ -112,28 +151,22 @@ public:
        };
 
        struct LinkContext {
-               ImageLoader*    (*loadLibrary)(const char* libraryName, bool search, bool findDLL, const char* origin, const RPathChain* rpaths);
+               ImageLoader*    (*loadLibrary)(const char* libraryName, bool search, const char* origin, const RPathChain* rpaths);
                void                    (*terminationRecorder)(ImageLoader* image);
                bool                    (*flatExportFinder)(const char* name, const Symbol** sym, const ImageLoader** image);
                bool                    (*coalescedExportFinder)(const char* name, const Symbol** sym, const ImageLoader** image);
+               unsigned int    (*getCoalescedImages)(ImageLoader* images[]);
                void                    (*undefinedHandler)(const char* name);
-#if IMAGE_NOTIFY_SUPPORT
-               void                    (*addImageNeedingNotification)(ImageLoader* image);
-               void                    (*notifyAdding)(const ImageLoader* const * images, unsigned int count);
-#endif
                MappedRegion*   (*getAllMappedRegions)(MappedRegion*);
                void *                  (*bindingHandler)(const char *, const char *, void *);
-               void                    (*notifySingle)(dyld_image_states, const struct mach_header*, const char* path, time_t modDate);
+               void                    (*notifySingle)(dyld_image_states, const ImageLoader* image);
                void                    (*notifyBatch)(dyld_image_states state);
                void                    (*removeImage)(ImageLoader* image);
                void                    (*registerDOFs)(const std::vector<DOFInfo>& dofs);
                void                    (*clearAllDepths)();
                unsigned int    (*imageCount)();
-               void                    (*notifySharedCacheInvalid)();
-#if __i386__
-               void                    (*makeSharedCacheImportSegmentsWritable)(bool writable);
-#endif
                void                    (*setNewProgramVars)(const ProgramVars&);
+               bool                    (*inSharedCache)(const char* path);
 #if SUPPORT_OLD_CRT_INITIALIZATION
                void                    (*setRunInitialzersOldWay)();
 #endif
@@ -146,6 +179,7 @@ public:
                ProgramVars             programVars;
                ImageLoader*    mainExecutable;
                const char*             imageSuffix;
+               const char**    rootPaths;
                PrebindMode             prebindUsage;
                SharedRegionMode sharedRegionMode;
                bool                    dyldLoadedAtSameAddressNeededBySharedCache; 
@@ -154,17 +188,43 @@ public:
                bool                    bindFlat;
                bool                    linkingMainExecutable;
                bool                    startedInitializingMainExecutable;
+               bool                    noPIE;
+               bool                    processIsRestricted;
                bool                    verboseOpts;
                bool                    verboseEnv;
                bool                    verboseMapping;
                bool                    verboseRebase;
                bool                    verboseBind;
+               bool                    verboseWeakBind;
                bool                    verboseInit;
                bool                    verboseDOF;
                bool                    verbosePrebinding;
                bool                    verboseWarnings;
        };
        
+       struct CoalIterator
+       {
+               ImageLoader*    image;
+               const char*             symbolName;
+               unsigned int    loadOrder;
+               bool                    weakSymbol;
+               bool                    symbolMatches;
+               bool                    done;
+               // the following are private to the ImageLoader subclass
+               uintptr_t               curIndex;
+               uintptr_t               endIndex;
+               uintptr_t               address;
+               uintptr_t               type;
+               uintptr_t               addend;
+       };
+       
+       virtual void                    initializeCoalIterator(CoalIterator&, unsigned int loadOrder) = 0;
+       virtual bool                    incrementCoalIterator(CoalIterator&) = 0;
+       virtual uintptr_t               getAddressCoalIterator(CoalIterator&, const LinkContext& context) = 0;
+       virtual void                    updateUsesCoalIterator(CoalIterator&, uintptr_t newAddr, ImageLoader* target, const LinkContext& context) = 0;
+       
+       
+       
                                                                                // constructor is protected, but anyone can delete an image
        virtual                                                         ~ImageLoader();
        
@@ -190,9 +250,6 @@ public:
 
        uint32_t                                                        getPathHash() const { return fPathHash; }
 
-                                                                               // get path used to load this image represents (ZeroLink only) which image this .o is part of
-       const char*                                                     getLogicalPath() const;
-
                                                                                // get path this image is intended to be placed on disk or NULL if no preferred install location
        virtual const char*                                     getInstallPath() const = 0;
 
@@ -200,9 +257,6 @@ public:
        bool                                                            matchInstallPath() const;
        void                                                            setMatchInstallPath(bool);
        
-                                                                               // if path was a fat file, offset of image loaded in that fat file
-       uint64_t                                                        getOffsetInFatFile() const;
-
                                                                                // mark that this image's exported symbols should be ignored when linking other images (e.g. RTLD_LOCAL)
        void                                                            setHideExports(bool hide = true);
        
@@ -221,6 +275,9 @@ public:
                                                                                // checks if the specifed address is within one of this image's segments
        virtual bool                                            containsAddress(const void* addr) const;
 
+                                                                               // checks if the specifed symbol is within this image's symbol table
+       virtual bool                                            containsSymbol(const void* addr) const = 0;
+
                                                                                // checks if the specifed address range overlaps any of this image's segments
        virtual bool                                            overlapsWithAddressRange(const void* start, const void* end) const;
 
@@ -246,7 +303,7 @@ public:
        virtual bool                                            hasCoalescedExports() const = 0;
        
                                                                                // search symbol table of definitions in this image for requested name
-       virtual const Symbol*                           findExportedSymbol(const char* name, const void* hint, bool searchReExports, const ImageLoader** foundIn) const = 0;
+       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;
@@ -278,40 +335,47 @@ public:
        virtual const Symbol*                           getIndexedImportedSymbol(uint32_t index) const = 0;
                        
                                                                                // gets attributes of the specified imported symbol
-       virtual ReferenceFlags                          geImportedSymbolInfo(const Symbol* sym) const = 0;
+       virtual ReferenceFlags                          getImportedSymbolInfo(const Symbol* sym) const = 0;
                        
                                                                                // gets name of the specified imported symbol
        virtual const char*                                     getImportedSymbolName(const Symbol* sym) const = 0;
                        
+                                                                               // find the closest symbol before addr
+       virtual const char*                                     findClosestSymbol(const void* addr, const void** closestAddr) const = 0;
+       
                                                                                // checks if this image is a bundle and can be loaded but not linked
        virtual bool                                            isBundle() const = 0;
        
                                                                                // checks if this image is a dylib 
        virtual bool                                            isDylib() const = 0;
        
+                                                                               // checks if this image is a main executable 
+       virtual bool                                            isExecutable() const = 0;
+       
+                                                                               // checks if this image is a main executable 
+       virtual bool                                            isPositionIndependentExecutable() const = 0;
+       
                                                                                // only for main executable
        virtual bool                                            forceFlat() const = 0;
        
                                                                                // called at runtime when a lazily bound function is first called
        virtual uintptr_t                                       doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context) = 0;
        
+                                                                               // called at runtime when a fast lazily bound function is first called
+       virtual uintptr_t                                       doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context) = 0;
+
                                                                                // calls termination routines (e.g. C++ static destructors for image)
        virtual void                                            doTermination(const LinkContext& context) = 0;
                                        
-#if IMAGE_NOTIFY_SUPPORT
-                                                                               // tell this image about other images
-       virtual void                                            doNotification(enum dyld_image_mode mode, uint32_t infoCount, const struct dyld_image_info info[]) = 0;
-#endif                                 
                                                                                // return if this image has initialization routines
        virtual bool                                            needsInitialization() = 0;
                        
-#if IMAGE_NOTIFY_SUPPORT
-                                                                               // return if this image has a routine to be called when any image is loaded or unloaded
-       virtual bool                                            hasImageNotification() = 0;
-#endif 
                                                                                // return if this image has specified section and set start and length
        virtual bool                                            getSectionContent(const char* segmentName, const char* sectionName, void** start, size_t* length) = 0;
-                       
+
+                                                                               // fills in info about __eh_frame and __unwind_info sections
+       virtual void                                            getUnwindInfo(dyld_unwind_sections* info) = 0;
+
                                                                                // given a pointer into an image, find which segment and section it is in
        virtual bool                                            findSection(const void* imageInterior, const char** segmentName, const char** sectionName, size_t* sectionOffset) = 0;
        
@@ -324,6 +388,31 @@ public:
                                                                                // add all RPATH paths this image contains
        virtual void                                            getRPaths(const LinkContext& context, std::vector<const char*>&) const = 0;
        
+                                                                               // image has or uses weak definitions that need runtime coalescing
+       virtual bool                                            participatesInCoalescing() const = 0;
+               
+                                                                               // if image has a UUID, copy into parameter and return true
+       virtual bool                                            getUUID(uuid_t) const = 0;
+       
+       
+//
+// A segment is a chunk of an executable file that is mapped into memory.  
+//
+       virtual unsigned int                            segmentCount() const = 0;
+       virtual const char*                                     segName(unsigned int) const = 0;
+       virtual uintptr_t                                       segSize(unsigned int) const = 0;
+       virtual uintptr_t                                       segFileSize(unsigned int) const = 0;
+       virtual bool                                            segHasTrailingZeroFill(unsigned int) = 0;
+       virtual uintptr_t                                       segFileOffset(unsigned int) const = 0;
+       virtual bool                                            segReadable(unsigned int) const = 0;
+       virtual bool                                            segWriteable(unsigned int) const = 0;
+       virtual bool                                            segExecutable(unsigned int) const = 0;
+       virtual bool                                            segUnaccessible(unsigned int) const = 0;
+       virtual bool                                            segHasPreferredLoadAddress(unsigned int) const = 0;
+       virtual uintptr_t                                       segPreferredLoadAddress(unsigned int) const = 0;
+       virtual uintptr_t                                       segActualLoadAddress(unsigned int) const = 0;
+       virtual uintptr_t                                       segActualEndAddress(unsigned int) const = 0;
+
        
 
        dyld_image_states                                       getState() { return (dyld_image_states)fState; }
@@ -350,12 +439,13 @@ public:
        static void                                                     addSuffix(const char* path, const char* suffix, char* result);
        
        static uint32_t                                         hash(const char*);
+       
+                                                                               // used instead of directly deleting image
+       static void                                                     deleteImage(ImageLoader*);
                
                        void                                            setPath(const char* path);      // only called for images created from memory
                        void                                            setPathUnowned(const char* path);
-                       
-                       void                                            setLogicalPath(const char* path);
-                       
+                                               
                        void                                            clearDepth() { fDepth = 0; }
                        
                        void                                            setBeingRemoved() { fBeingRemoved = true; }
@@ -364,36 +454,12 @@ public:
                        void                                            setAddFuncNotified() { fAddFuncNotified = true; }
                        bool                                            addFuncNotified() const { return fAddFuncNotified; }
        
-protected:     
-       struct DependentLibrary;
-public:
-       friend class iterator;
-       
-       class iterator
-       {
-       public:
-               iterator&               operator++() { ++fLocation; return *this; }
-               bool                    operator!=(const iterator& it) const { return (it.fLocation != this->fLocation); }
-               ImageLoader*    operator*() const { return fLocation->image; }
-       private:
-               friend class ImageLoader;
-               iterator(DependentLibrary* loc) : fLocation(loc) {}
-               DependentLibrary*       fLocation;
-       };
-       
-       iterator beginDependents() { return iterator(fLibraries); }
-       iterator endDependents() { return iterator(&fLibraries[fLibrariesCount]); }
-       
-       
-               
-       friend class Segment;
-               
-protected:
+protected:                     
        // abstract base class so all constructors protected
-                                       ImageLoader(const char* path, uint64_t offsetInFat, const struct stat& info); 
-                                       ImageLoader(const char* moduleName); 
+                                       ImageLoader(const char* path, unsigned int libCount); 
                                        ImageLoader(const ImageLoader&);
        void                    operator=(const ImageLoader&);
+       void                    operator delete(void* image) throw() { free(image); } 
        
 
        struct LibraryInfo {
@@ -417,38 +483,31 @@ protected:
                bool                            reExported;
        };
 
-       class SegmentIterator
-       {
-       public:
-               SegmentIterator&        operator++(); // use inline later to work around circular reference
-               bool                            operator!=(const SegmentIterator& it) const { return (it.fLocation != this->fLocation); }
-               class Segment*          operator*() const { return fLocation; }
-               SegmentIterator(class Segment* loc) : fLocation(loc) {}
-       private:
-               class Segment*          fLocation;
-       };
 
        typedef void (*Initializer)(int argc, const char* argv[], const char* envp[], const char* apple[], const ProgramVars* vars);
        typedef void (*Terminator)(void);
        
+
+
+       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;
+
+
                                                // To link() an image, its dependent libraries are loaded, it is rebased, bound, and initialized.
                                                // These methods do the above, exactly once, and it the right order
-       void                            recursiveLoadLibraries(const LinkContext& context, const RPathChain& loaderRPaths);
+       void                            recursiveLoadLibraries(const LinkContext& context, bool preflightOnly, const RPathChain& loaderRPaths);
        void                            recursiveUnLoadMappedLibraries(const LinkContext& context);
        unsigned int            recursiveUpdateDepth(unsigned int maxDepth);
        void                            recursiveValidate(const LinkContext& context);
        void                            recursiveRebase(const LinkContext& context);
        void                            recursiveBind(const LinkContext& context, bool forceLazysBound);
+       void                            weakBind(const LinkContext& context);
        void                            recursiveGetDOFSections(const LinkContext& context, std::vector<DOFInfo>& dofs);
-#if IMAGE_NOTIFY_SUPPORT
-       void                            recursiveImageAnnouncement(const LinkContext& context, ImageLoader**& newImages);
-#endif
        void                            recursiveInitialization(const LinkContext& context, mach_port_t this_thread);
 
-                                                               // return how many libraries this image depends on
-       virtual uint32_t                        doGetDependentLibraryCount() = 0;
-       
-                                                               // fill in information about dependent libraries (array length is doGetDependentLibraryCount())
+                                                               // fill in information about dependent libraries (array length is fLibraryCount)
        virtual void                            doGetDependentLibraries(DependentLibraryInfo libs[]) = 0;
        
                                                                // called on images that are libraries, returns info about itself
@@ -463,9 +522,6 @@ protected:
                                                                // called later via API to force all lazy pointer to be bound
        virtual void                            doBindJustLazies(const LinkContext& context) = 0;
        
-                                                               // update any segment permissions
-       virtual void                            doUpdateMappingPermissions(const LinkContext& context) = 0;
-       
                                                                // if image has any dtrace DOF sections, append them to list to be registered
        virtual void                            doGetDOFSections(const LinkContext& context, std::vector<DOFInfo>& dofs) = 0;
        
@@ -484,12 +540,6 @@ protected:
                                                                // set how much all segments slide
        virtual void                            setSlide(intptr_t slide) = 0;           
        
-                                                               // utility routine to map in all segements in fSegments from a file
-       virtual void                            mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context);
-       
-                                                               // utility routine to map in all segements in fSegments from a memory image
-       virtual void                            mapSegments(const void* memoryImage, uint64_t imageLen, const LinkContext& context);
-
                                                                // returns if all dependent libraries checksum's were as expected and none slide
                        bool                            allDependentLibrariesAsWhenPreBound() const;
 
@@ -504,17 +554,15 @@ protected:
        
                                                                // mark that target should not be unloaded unless this is also unloaded
        void                                            addDynamicReference(const ImageLoader* target);
-                               
-                                                               // used to start iterating Segments
-       virtual SegmentIterator         beginSegments() const = 0;
        
-                                                               // used to end iterating Segments
-       virtual SegmentIterator         endSegments() const = 0;
+       void                                            setFileInfo(dev_t device, ino_t inode, time_t modDate);
        
-
+       static uintptr_t                        fgNextPIEDylibAddress;
        static uint32_t                         fgImagesWithUsedPrebinding;
        static uint32_t                         fgImagesUsedFromSharedCache;
        static uint32_t                         fgImagesRequiringNoFixups;
+       static uint32_t                         fgImagesHasWeakDefinitions;
+       static uint32_t                         fgImagesRequiringCoalescing;
        static uint32_t                         fgTotalRebaseFixups;
        static uint32_t                         fgTotalBindFixups;
        static uint32_t                         fgTotalBindSymbolsResolved;
@@ -527,16 +575,13 @@ protected:
        static uint64_t                         fgTotalLoadLibrariesTime;
        static uint64_t                         fgTotalRebaseTime;
        static uint64_t                         fgTotalBindTime;
+       static uint64_t                         fgTotalWeakBindTime;
+       static uint64_t                         fgTotalDOF;
        static uint64_t                         fgTotalInitTime;
-       static uintptr_t                        fgNextSplitSegAddress;
        const char*                                     fPath;
-       const char*                                     fLogicalPath; // for ZeroLink - the image which this bundle is part of
        dev_t                                           fDevice;
        ino_t                                           fInode;
        time_t                                          fLastModified;
-       uint64_t                                        fOffsetInFatFile;
-       DependentLibrary*                       fLibraries;
-       uint32_t                                        fLibrariesCount;
        uint32_t                                        fPathHash;
        uint32_t                                        fDlopenReferenceCount;  // count of how many dlopens have been done on this image
        uint32_t                                        fStaticReferenceCount;  // count of images that have a fLibraries entry pointing to this image
@@ -544,7 +589,6 @@ protected:
        std::set<const ImageLoader*>* fDynamicReferences;       // list of all images this image used because of a flat/coalesced lookup
 
 private:
-#if RECURSIVE_INITIALIZER_LOCK
        struct recursive_lock {
                                                recursive_lock(mach_port_t t) : thread(t), count(0) {}
                mach_port_t             thread;
@@ -552,95 +596,33 @@ private:
        };
        void                                            recursiveSpinLock(recursive_lock&);
        void                                            recursiveSpinUnLock();
-#endif 
 
-       void                                            init(const char* path, uint64_t offsetInFat, dev_t device, ino_t inode, time_t modDate);
-       intptr_t                                        assignSegmentAddresses(const LinkContext& context);
        const ImageLoader::Symbol*      findExportedSymbolInDependentImagesExcept(const char* name, const ImageLoader** dsiStart, 
                                                                                const ImageLoader**& dsiCur, const ImageLoader** dsiEnd, const ImageLoader** foundIn) const;
 
 
 
+       recursive_lock*                         fInitializerRecursiveLock;
        uint16_t                                        fDepth;
        uint16_t                                        fLoadOrder;
        uint32_t                                        fState : 8,
+                                                               fLibraryCount : 10,
                                                                fAllLibraryChecksumsAndLoadAddressesMatch : 1,
                                                                fLeaveMapped : 1,               // when unloaded, leave image mapped in cause some other code may have pointers into it
                                                                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
                                                                fRegisteredDOF : 1,
-#if IMAGE_NOTIFY_SUPPORT
-                                                               fAnnounced : 1,
-#endif
                                                                fAllLazyPointersBound : 1,
                                                                fBeingRemoved : 1,
                                                                fAddFuncNotified : 1,
-                                                               fPathOwnedByImage : 1;
+                                                               fPathOwnedByImage : 1,
+                                                               fWeakSymbolsBound : 1;
 
-#if RECURSIVE_INITIALIZER_LOCK
-       recursive_lock*                         fInitializerRecursiveLock;
-#else
-       uint32_t                                        fInitializerLock;
-#endif
        static uint16_t                         fgLoadOrdinal;
 };
 
 
-//
-// Segment is an abstract base class.  A segment is a chunk of an executable
-// file that is mapped into memory.  Each subclass of ImageLoader typically
-// implements its own concrete subclass of Segment.
-//
-//  
-class Segment {
-public:
-       virtual                                         ~Segment() {}
-
-       virtual const char*                     getName() = 0;
-       virtual uintptr_t                       getSize() = 0;
-       virtual uintptr_t                       getFileSize() = 0;
-       virtual bool                            hasTrailingZeroFill();
-       virtual uintptr_t                       getFileOffset() = 0;
-       virtual bool                            readable() = 0;
-       virtual bool                            writeable() = 0;
-       virtual bool                            executable() = 0;
-       virtual bool                            unaccessible() = 0;
-       virtual uintptr_t                       getActualLoadAddress(const ImageLoader*) = 0;
-       virtual uintptr_t                       getPreferredLoadAddress() = 0;
-       virtual void                            unmap(const ImageLoader*) = 0;
-       virtual Segment*                        next(Segment*) = 0;
-#if __i386__
-       virtual bool                            readOnlyImportStubs() = 0;
-#endif
-       
-       
-protected:
-       // abstract base class so all constructors protected
-                                                               Segment() {}
-                                                               Segment(const Segment&);
-       void                                            operator=(const Segment&);
-
-       virtual bool                            hasPreferredLoadAddress() = 0;
-       //virtual void                          setActualLoadAddress(uint64_t addr) = 0;
-       virtual void                            map(int fd, uint64_t offsetInFatWrapper, intptr_t slide, const ImageLoader* image, const ImageLoader::LinkContext& context);
-       
-       static bool                                     reserveAddressRange(uintptr_t start, size_t length);
-       static uintptr_t                        reserveAnAddressRange(size_t length, const class ImageLoader::LinkContext& context);
-       static uintptr_t                        fgNextPIEDylibAddress;
-
-private:
-       void                                            setPermissions(const ImageLoader::LinkContext& context, const ImageLoader* image);
-       void                                            map(const void* memoryImage, intptr_t slide, const ImageLoader* image, const ImageLoader::LinkContext& context);
-       void                                            tempWritable(const ImageLoader::LinkContext& context, const ImageLoader* image);
-       
-       friend class ImageLoader;
-       friend class ImageLoaderMachO;
-};
-
-inline ImageLoader::SegmentIterator& ImageLoader::SegmentIterator::operator++() { fLocation = fLocation->next(fLocation); return *this; }
-
-
 
 
 #endif
index 1a8bfdfcc9c64bd67d6ef399e1a9927687a0d8fb..094d56d2ae2cfc68260ad8ca42af893ccb221d25 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2008 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 
 #include <string.h>
 #include <fcntl.h>
+#include <errno.h>
 #include <sys/types.h>
 #include <sys/fcntl.h>
 #include <sys/stat.h> 
 #include <sys/mman.h>
-#include <mach/shared_memory_server.h>
 #include <mach/mach.h>
 #include <mach/thread_status.h>
 #include <mach-o/loader.h> 
-#include <mach-o/reloc.h> 
 #include <mach-o/nlist.h> 
 #include <sys/sysctl.h>
 #include <libkern/OSAtomic.h>
 #include <libkern/OSCacheControl.h>
-#if __ppc__ || __ppc64__
-       #include <mach-o/ppc/reloc.h>
-#endif
-#if __x86_64__
-       #include <mach-o/x86_64/reloc.h>
-#endif
-
-#ifndef MH_PIE
-       #define MH_PIE 0x200000 
-#endif
-
-#ifndef S_DTRACE_DOF
-  #define S_DTRACE_DOF 0xF
-#endif
-
-#ifndef S_ATTR_SELF_MODIFYING_CODE
-  #define S_ATTR_SELF_MODIFYING_CODE 0x04000000
-#endif
 
 #include "ImageLoaderMachO.h"
+#include "ImageLoaderMachOCompressed.h"
+#include "ImageLoaderMachOClassic.h"
 #include "mach-o/dyld_images.h"
 
-// optimize strcmp for ppc
-#if __ppc__
-       #include <ppc_intrinsics.h>
-#else
-       #define astrcmp(a,b) strcmp(a,b)
-#endif
-
-// in libc.a
-extern "C" void _spin_lock(uint32_t*);
-extern "C" void _spin_unlock(uint32_t*);
 
 
 // relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables
 #if __LP64__
-       #define RELOC_SIZE 3
        #define LC_SEGMENT_COMMAND              LC_SEGMENT_64
        #define LC_ROUTINES_COMMAND             LC_ROUTINES_64
-       struct macho_header                             : public mach_header_64  {};
        struct macho_segment_command    : public segment_command_64  {};
        struct macho_section                    : public section_64  {};        
-       struct macho_nlist                              : public nlist_64  {};  
        struct macho_routines_command   : public routines_command_64  {};       
 #else
-       #define RELOC_SIZE 2
        #define LC_SEGMENT_COMMAND              LC_SEGMENT
        #define LC_ROUTINES_COMMAND             LC_ROUTINES
-       struct macho_header                             : public mach_header  {};
        struct macho_segment_command    : public segment_command {};
        struct macho_section                    : public section  {};   
-       struct macho_nlist                              : public nlist  {};     
        struct macho_routines_command   : public routines_command  {};  
 #endif
 
-#if __x86_64__
-       #define POINTER_RELOC X86_64_RELOC_UNSIGNED
-#else
-       #define POINTER_RELOC GENERIC_RELOC_VANILLA
-#endif
-
-uint32_t ImageLoaderMachO::fgHintedBinaryTreeSearchs = 0;
-uint32_t ImageLoaderMachO::fgUnhintedBinaryTreeSearchs = 0;
-uint32_t ImageLoaderMachO::fgCountOfImagesWithWeakExports = 0;
-
-#if __i386__
-uint32_t ImageLoaderMachO::fgReadOnlyImportSpinLock = 0;
-#endif
+uint32_t ImageLoaderMachO::fgSymbolTableBinarySearchs = 0;
+uint32_t ImageLoaderMachO::fgSymbolTrieSearchs = 0;
 
-//#define LINKEDIT_USAGE_DEBUG 1
 
-#if LINKEDIT_USAGE_DEBUG
-       #include <set>
-       static std::set<uintptr_t> sLinkEditPageBuckets;
-
-       namespace dyld {
-               extern ImageLoader*     findImageContainingAddress(const void* addr);
-       };
-
-       static void noteAccessedLinkEditAddress(const void* addr)
-       {
-               uintptr_t page = ((uintptr_t)addr) & (-4096);
-               if ( sLinkEditPageBuckets.count(page) == 0 ) {
-                       ImageLoader* inImage = dyld::findImageContainingAddress(addr);
-                       dyld::log("dyld: accessing page 0x%016lX in __LINKEDIT of %s\n", page, inImage != NULL ? inImage->getPath() : "unknown" );
-               }
-               sLinkEditPageBuckets.insert(page);
-       }
-#endif
-
-// only way to share initialization in C++
-void ImageLoaderMachO::init()
-{
-       fMachOData              = NULL;
-       fLinkEditBase   = NULL;
-       fSymbolTable    = NULL;
-       fStrings                = NULL;
-       fDynamicInfo    = NULL;
-       fSlide                  = 0;
-       fTwoLevelHints  = NULL;
-       fDylibID                = NULL;
+ImageLoaderMachO::ImageLoaderMachO(const macho_header* mh, const char* path, unsigned int segCount, 
+                                                                                                                               uint32_t segOffsets[], unsigned int libCount)
+ : ImageLoader(path, libCount), fMachOData((uint8_t*)mh), fLinkEditBase(NULL), fSlide(0), 
+       fEHFrameSectionOffset(0), fUnwindInfoSectionOffset(0), fDylibIDOffset(0), 
+       fSegmentsCount(segCount), fIsSplitSeg(false), fInSharedCache(false),  
 #if TEXT_RELOC_SUPPORT
-       fTextSegmentWithFixups = NULL;
+       fTextSegmentRebases(false),
+       fTextSegmentBinds(false),
 #endif
 #if __i386__
-       fReadOnlyImportSegment = NULL;
-#endif
-       fIsSplitSeg             = false;
-       fInSharedCache  = false;
-#if __ppc64__
-       f4GBWritable    = false;
-#endif
-       fHasSubLibraries= false;
-       fHasSubUmbrella = false;
-       fInUmbrella     = false;
-       fHasDOFSections = false;
-       fHasDashInit    = false;
-       fHasInitializers= false;
-       fHasTerminators = false;
-#if IMAGE_NOTIFY_SUPPORT
-       fHasImageNotifySection = false;
+       fReadOnlyImportSegment(false),
 #endif
-}
-
-// create image for main executable
-ImageLoaderMachO::ImageLoaderMachO(const struct mach_header* mh, uintptr_t slide, const char* path, const LinkContext& context)
- : ImageLoader(path)
+       fHasSubLibraries(false), fHasSubUmbrella(false), fInUmbrella(false), fHasDOFSections(false), fHasDashInit(false),
+       fHasInitializers(false), fHasTerminators(false)
 {
-       // clean slate
-       this->init();
-
-       // temporary use this buffer until TEXT is mapped in
-       fMachOData = (const uint8_t*)mh;
-
-       // create segments
-       this->instantiateSegments((const uint8_t*)mh);
-               
-       // set slide for PIE programs
-       this->setSlide(slide);
-
-       // get pointers to interesting things 
-       this->parseLoadCmds();
+       fIsSplitSeg = ((mh->flags & MH_SPLIT_SEGS) != 0);        
 
-       // update segments to reference load commands in mapped in __TEXT segment
-       this->adjustSegments();
-
-#if __i386__
-       // kernel may have mapped in __IMPORT segment read-only, we need it read/write to do binding
-       if ( fReadOnlyImportSegment != NULL )
-               fReadOnlyImportSegment->tempWritable(context, this);
-#endif
-       
-       // for PIE record end of program, to know where to start loading dylibs
-       if ( mh->flags & MH_PIE )
-               Segment::fgNextPIEDylibAddress = (uintptr_t)this->getEnd();
-       
-       // notify state change
-       this->setMapped(context);
-       
-       if ( context.verboseMapping ) {
-               dyld::log("dyld: Main executable mapped %s\n", this->getPath());
-               for (ImageLoader::SegmentIterator it = this->beginSegments(); it != this->endSegments(); ++it ) {
-                       Segment* seg = *it;
-                       if ( (strcmp(seg->getName(), "__PAGEZERO") == 0) || (strcmp(seg->getName(), "__UNIXSTACK") == 0)  )
-                               dyld::log("%18s at 0x%08lX->0x%08lX\n", seg->getName(), seg->getPreferredLoadAddress(), seg->getPreferredLoadAddress()+seg->getSize());
-                       else
-                               dyld::log("%18s at 0x%08lX->0x%08lX\n", seg->getName(), seg->getActualLoadAddress(this), seg->getActualLoadAddress(this)+seg->getSize());
+       // construct SegmentMachO object for each LC_SEGMENT cmd using "placement new" to put 
+       // each SegmentMachO object in array at end of ImageLoaderMachO object
+       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, segIndex=0; i < cmd_count; ++i) {
+               if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
+                       const struct macho_segment_command* segCmd = (struct macho_segment_command*)cmd;
+                       // ignore zero-sized segments
+                       if ( segCmd->vmsize != 0 ) {
+                               // record offset of load command
+                               segOffsets[segIndex++] = (uint8_t*)segCmd - fMachOData;
+                       }
                }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
        }
+
 }
 
 
-// create image by copying an in-memory mach-o file
-ImageLoaderMachO::ImageLoaderMachO(const char* moduleName, const struct mach_header* mh, uint64_t len, const LinkContext& context)
: ImageLoader(moduleName)
+// 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)
 {
-       // clean slate
-       this->init();
-
-       // temporary use this buffer until TEXT is mapped in
-       fMachOData = (const uint8_t*)mh;
-
-       // create segments
-       this->instantiateSegments((const uint8_t*)mh);
-       
-       // map segments 
-       if ( mh->filetype == MH_EXECUTE ) {
-               throw "can't load another MH_EXECUTE";
-       }
-       else {
-               ImageLoader::mapSegments((const void*)mh, len, context);
+       *compressed = false;
+       *segCount = 0;
+       *libCount = 0;
+       const uint32_t cmd_count = mh->ncmds;
+       const struct load_command* const cmds    = (struct load_command*)(((uint8_t*)mh) + sizeof(macho_header));
+       const struct load_command* const endCmds = (struct load_command*)(((uint8_t*)mh) + sizeof(macho_header) + mh->sizeofcmds);
+       const struct load_command* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               switch (cmd->cmd) {
+                       case LC_DYLD_INFO:
+                       case LC_DYLD_INFO_ONLY:
+                               *compressed = true;
+                               break;
+                       case LC_SEGMENT_COMMAND:
+                               // ignore zero-sized segments
+                               if ( ((struct macho_segment_command*)cmd)->vmsize != 0 )
+                                       *segCount += 1;
+                               break;
+                       case LC_LOAD_DYLIB:
+                       case LC_LOAD_WEAK_DYLIB:
+                       case LC_REEXPORT_DYLIB:
+                               *libCount += 1;
+                               break;
+               }
+               uint32_t cmdLength = cmd->cmdsize;
+               cmd = (const struct load_command*)(((char*)cmd)+cmdLength);
+               if ( cmd > endCmds ) {
+                       dyld::throwf("malformed mach-o image: load command #%d length (%u) would exceed sizeofcmds (%u) in %s", 
+                                                       i, cmdLength, mh->sizeofcmds, path);
+               }
        }
-       
-       // for compatibility, never unload dylibs loaded from memory
-       this->setNeverUnload();
-
-       // get pointers to interesting things 
-       this->parseLoadCmds();
-
-       // update segments to reference load commands in mapped in __TEXT segment
-       this->adjustSegments();
-
-       // bundle loads need path copied
-       if ( moduleName != NULL ) 
-               this->setPath(moduleName);
-       
-       // notify state change
-       this->setMapped(context);
+       // fSegmentsArrayCount is only 8-bits
+       if ( *segCount > 255 )
+               dyld::throwf("malformed mach-o image: more than 255 segments in %s", path);
                
-}
-
-// create image by using cached mach-o file
-ImageLoaderMachO::ImageLoaderMachO(const struct mach_header* mh, const char* path, const struct stat& info, const LinkContext& context)
- : ImageLoader(path, 0, info)
-{
-       // clean slate
-       this->init();
-
-       // already mapped to mh address
-       fMachOData = (const uint8_t*)mh;
-
-       // usually a split seg
-       fIsSplitSeg = ((mh->flags & MH_SPLIT_SEGS) != 0);       
-       
-       // remember this is from shared cache and cannot be unloaded
-       fInSharedCache = true;
-       this->setNeverUnload();
+       // fSegmentsArrayCount is only 8-bits
+       if ( *libCount > 4095 )
+               dyld::throwf("malformed mach-o image: more than 4095 dependent libraries in %s", path);
 
-       // create segments
-       this->instantiateSegments((const uint8_t*)mh);
-               
-       // segments already mapped in cache
-       if ( context.verboseMapping ) {
-               dyld::log("dyld: Using shared cached for %s\n", path);
-               for (ImageLoader::SegmentIterator it = this->beginSegments(); it != this->endSegments(); ++it ) {
-                       Segment* seg = *it;
-                       dyld::log("%18s at 0x%08lX->0x%08lX\n", seg->getName(), seg->getActualLoadAddress(this), seg->getActualLoadAddress(this)+seg->getSize());
-               }
-       }
+       if ( needsAddedLibSystemDepency(*libCount, mh) )
+               *libCount = 1;
+}
 
-       // get pointers to interesting things 
-       this->parseLoadCmds();
 
-       // note: path is mapped into cache so no need for ImageLoader to make a copy
 
-       // notify state change
-       this->setMapped(context);
+// create image for main executable
+ImageLoader* ImageLoaderMachO::instantiateMainExecutable(const macho_header* mh, uintptr_t slide, const char* path, const LinkContext& context)
+{
+       //dyld::log("ImageLoader=%ld, ImageLoaderMachO=%ld, ImageLoaderMachOClassic=%ld, ImageLoaderMachOCompressed=%ld\n",
+       //      sizeof(ImageLoader), sizeof(ImageLoaderMachO), sizeof(ImageLoaderMachOClassic), sizeof(ImageLoaderMachOCompressed));
+       bool compressed;
+       unsigned int segCount;
+       unsigned int libCount;
+       sniffLoadCommands(mh, path, &compressed, &segCount, &libCount);
+       // instantiate concrete class based on content of load commands
+       if ( compressed ) 
+               return ImageLoaderMachOCompressed::instantiateMainExecutable(mh, slide, path, segCount, libCount, context);
+       else
+               return ImageLoaderMachOClassic::instantiateMainExecutable(mh, slide, path, segCount, libCount, context);
 }
 
 
 // create image by mapping in a mach-o file
-ImageLoaderMachO::ImageLoaderMachO(const char* path, int fd, const uint8_t firstPage[4096], uint64_t offsetInFat, 
+ImageLoader* ImageLoaderMachO::instantiateFromFile(const char* path, int fd, const uint8_t firstPage[4096], uint64_t offsetInFat, 
                                                                        uint64_t lenInFat, const struct stat& info, const LinkContext& context)
- : ImageLoader(path, offsetInFat, info)
-{      
-       // clean slate
-       this->init();
-
-       // read load commands
+{
+       // get load commands
        const unsigned int dataSize = sizeof(macho_header) + ((macho_header*)firstPage)->sizeofcmds;
        uint8_t buffer[dataSize];
        const uint8_t* fileData = firstPage;
@@ -311,990 +186,490 @@ ImageLoaderMachO::ImageLoaderMachO(const char* path, int fd, const uint8_t first
                memcpy(buffer, firstPage, 4096);
                pread(fd, &buffer[4096], dataSize-4096, offsetInFat+4096);
        }
-       
-       // temporary use this buffer until TEXT is mapped in
-       fMachOData = fileData;
-       
-       // the meaning of many fields changes in split seg mach-o files
-       fIsSplitSeg = ((((macho_header*)fileData)->flags & MH_SPLIT_SEGS) != 0) && (((macho_header*)fileData)->filetype == MH_DYLIB);   
-       
-       // create segments
-       this->instantiateSegments(fileData);
-       
-       // map segments, except for main executable which is already mapped in by kernel
-       if ( ((macho_header*)fileData)->filetype != MH_EXECUTE )
-               this->mapSegments(fd, offsetInFat, lenInFat, info.st_size, context);
-       
-       // get pointers to interesting things 
-       this->parseLoadCmds();
-       
-       // update segments to reference load commands in mapped in __TEXT segment
-       this->adjustSegments();
-       
-       // notify state change
-       this->setMapped(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 = getInstallPath();
-       if ( (installName != NULL) && (strcmp(installName, path) == 0) && (path[0] == '/') )
-               this->setPathUnowned(installName);
-       if ( path[0] != '/' ) {
-               // rdar://problem/5135363 turn relative paths into absolute paths so gdb, Symbolication can later find them
-               char realPath[MAXPATHLEN];
-               if ( realpath(path, realPath) != NULL )
-                       this->setPath(realPath);
-               else
-                       this->setPath(path);
-       }
-       else 
-               this->setPath(path);
-       
-       // tell kernel about pages we are going to need soon
-       if ( ! context.preFetchDisabled )
-               this->preFetch(fd, offsetInFat, context);
 
+       bool compressed;
+       unsigned int segCount;
+       unsigned int libCount;
+       sniffLoadCommands((const macho_header*)fileData, path, &compressed, &segCount, &libCount);
+       // instantiate concrete class based on content of load commands
+       if ( compressed ) 
+               return ImageLoaderMachOCompressed::instantiateFromFile(path, fd, fileData, offsetInFat, lenInFat, info, segCount, libCount, context);
+       else
+               return ImageLoaderMachOClassic::instantiateFromFile(path, fd, fileData, offsetInFat, lenInFat, info, segCount, libCount, 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)
+{
+       // instantiate right concrete class
+       bool compressed;
+       unsigned int segCount;
+       unsigned int libCount;
+       sniffLoadCommands(mh, path, &compressed, &segCount, &libCount);
+       // instantiate concrete class based on content of load commands
+       if ( compressed ) 
+               return ImageLoaderMachOCompressed::instantiateFromCache(mh, path, info, segCount, libCount, context);
+       else
+               return ImageLoaderMachOClassic::instantiateFromCache(mh, path, info, segCount, libCount, context);
+}
 
-
-ImageLoaderMachO::~ImageLoaderMachO()
-{
-       // keep count of images with weak exports
-       if ( this->hasCoalescedExports() )
-               --fgCountOfImagesWithWeakExports;
-
-       // keep count of images used in shared cache
-       if ( fInSharedCache )
-               --fgImagesUsedFromSharedCache;
-
-       // usually unmap image when done
-       if ( ! this->leaveMapped() && (this->getState() >= dyld_image_state_mapped) ) {
-               // first segment has load commands, so unmap last
-               Segment* firstSeg = *(this->beginSegments());
-               for(ImageLoader::SegmentIterator it = this->beginSegments(); it != this->endSegments(); ++it ) {
-                       Segment* seg = *it;
-                       if ( seg != firstSeg )
-                               seg->unmap(this);
-               }
-               firstSeg->unmap(this);
-       }
-       // free segment objects
-       free(fSegmentsArray);
+// create image by copying an in-memory mach-o file
+ImageLoader* ImageLoaderMachO::instantiateFromMemory(const char* moduleName, const macho_header* mh, uint64_t len, const LinkContext& context)
+{
+       bool compressed;
+       unsigned int segCount;
+       unsigned int libCount;
+       sniffLoadCommands(mh, moduleName, &compressed, &segCount, &libCount);
+       // instantiate concrete class based on content of load commands
+       if ( compressed ) 
+               return ImageLoaderMachOCompressed::instantiateFromMemory(moduleName, mh, len, segCount, libCount, context);
+       else
+               return ImageLoaderMachOClassic::instantiateFromMemory(moduleName, mh, len, segCount, libCount, context);
 }
 
 
 
-void ImageLoaderMachO::instantiateSegments(const uint8_t* fileData)
+void ImageLoaderMachO::parseLoadCmds()
 {
-       const uint32_t cmd_count = ((macho_header*)fileData)->ncmds;
-       const struct load_command* const cmds = (struct load_command*)&fileData[sizeof(macho_header)];
-
-       // count LC_SEGMENT cmd and reserve that many segment slots
-       uint32_t segCount = 0;
-       const struct load_command* cmd = cmds;
-       for (unsigned long i = 0; i < cmd_count; ++i) {
-               if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
-                       // ignore zero-sized segments
-                       if ( ((struct macho_segment_command*)cmd)->vmsize != 0 )
-                               ++segCount;
+       // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
+       for(unsigned int i=0; i < fSegmentsCount; ++i) {
+               // set up pointer to __LINKEDIT segment
+               if ( strcmp(segName(i),"__LINKEDIT") == 0 ) 
+                       fLinkEditBase = (uint8_t*)(segActualLoadAddress(i) - segFileOffset(i));
+#if TEXT_RELOC_SUPPORT
+               // __TEXT segment always starts at beginning of file and contains mach_header and load commands
+               if ( strcmp(segName(i),"__TEXT") == 0 ) {
+                       if ( segHasRebaseFixUps(i) )
+                               fTextSegmentRebases = true;
+                       if ( segHasBindFixUps(i) )
+                               fTextSegmentBinds = true;
+               }
+#endif
+#if __i386__
+               if ( segIsReadOnlyImport(i) )
+                       fReadOnlyImportSegment = true;
+#endif
+               // some segment always starts at beginning of file and contains mach_header and load commands
+               if ( (segFileOffset(i) == 0) && (segFileSize(i) != 0) ) {
+                       fMachOData = (uint8_t*)(segActualLoadAddress(i));
                }
-               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
        }
-       // fSegmentsArrayCount is only 8-bits
-       if ( segCount > 255 )
-               dyld::throwf("more than 255 segments in %s", this->getPath());
-               
-       // allocate array of segment objects in one call to malloc()
-       //fSegmentsArray = static_cast<SegmentMachO*>(operator new[](segCount*sizeof(SegmentMachO)));
-       fSegmentsArray = static_cast<SegmentMachO*>(malloc(segCount*sizeof(SegmentMachO)));
-       fSegmentsArrayCount = segCount;
        
-       // construct Segment object for each LC_SEGMENT cmd using "placment new"
-       uint32_t segIndex = 0;
-       cmd = cmds;
-       for (unsigned long i = 0; i < cmd_count; ++i) {
-               if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
-                       const struct macho_segment_command* segCmd = (struct macho_segment_command*)cmd;
-                       // ignore zero-sized segments
-                       if ( segCmd->vmsize != 0 ) 
-                               new (&fSegmentsArray[segIndex++]) SegmentMachO(segCmd);
-               }
-               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+       // keep count of prebound images with weak exports
+       if ( this->participatesInCoalescing() ) {
+               ++fgImagesRequiringCoalescing;
+               if ( this->hasCoalescedExports() ) 
+                       ++fgImagesHasWeakDefinitions;
        }
-}
 
+       // keep count of images used in shared cache
+       if ( fInSharedCache )
+               ++fgImagesUsedFromSharedCache;
 
-void ImageLoaderMachO::adjustSegments()
-{
-       // tell each segment where is load command is finally mapped
+       // walk load commands (mapped in at start of __TEXT segment)
+       const dyld_info_command* dyldInfo = NULL;
+       const macho_nlist* symbolTable = NULL;
+       const char* symbolTableStrings = NULL;
+       const dysymtab_command* dynSymbolTable = NULL;
        const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
        const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
-       uint32_t segIndex = 0;
        const struct load_command* cmd = cmds;
-       for (unsigned long i = 0; i < cmd_count; ++i) {
-               if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
-                       const struct macho_segment_command* segCmd = (struct macho_segment_command*)cmd;
-                       // ignore zero-sized segments
-                       if ( segCmd->vmsize != 0 ) {
-                               fSegmentsArray[segIndex].adjust(segCmd);
-                               ++segIndex;
-                       }
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               switch (cmd->cmd) {
+                       case LC_SYMTAB:
+                               {
+                                       const struct symtab_command* symtab = (struct symtab_command*)cmd;
+                                       symbolTableStrings = (const char*)&fLinkEditBase[symtab->stroff];
+                                       symbolTable = (macho_nlist*)(&fLinkEditBase[symtab->symoff]);
+                               }
+                               break;
+                       case LC_DYSYMTAB:
+                               dynSymbolTable = (struct dysymtab_command*)cmd;
+                               break;
+                       case LC_SUB_UMBRELLA:
+                               fHasSubUmbrella = true;
+                               break;
+                       case LC_SUB_FRAMEWORK:
+                               fInUmbrella = true;
+                               break;
+                       case LC_SUB_LIBRARY:
+                               fHasSubLibraries = true;
+                               break;
+                       case LC_ROUTINES_COMMAND:
+                               fHasDashInit = true;
+                               break;
+                       case LC_DYLD_INFO:
+                       case LC_DYLD_INFO_ONLY:
+                               dyldInfo = (struct dyld_info_command*)cmd;
+                               break;
+                       case LC_SEGMENT_COMMAND:
+                               {
+                                       const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
+                                       const bool isTextSeg = (strcmp(seg->segname, "__TEXT") == 0);
+                                       const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
+                                       const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
+                                       for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+                                               const uint8_t type = sect->flags & SECTION_TYPE;
+                                               if ( type == S_MOD_INIT_FUNC_POINTERS )
+                                                       fHasInitializers = true;
+                                               else if ( type == S_MOD_TERM_FUNC_POINTERS )
+                                                       fHasTerminators = true;
+                                               else if ( type == S_DTRACE_DOF )
+                                                       fHasDOFSections = true;
+                                               else if ( isTextSeg && (strcmp(sect->sectname, "__eh_frame") == 0) )
+                                                       fEHFrameSectionOffset = (uint8_t*)sect - fMachOData;
+                                               else if ( isTextSeg && (strcmp(sect->sectname, "__unwind_info") == 0) )
+                                                       fUnwindInfoSectionOffset = (uint8_t*)sect - fMachOData;;
+                                       }
+                               }
+                               break;
+                       case LC_TWOLEVEL_HINTS:
+                               // no longer supported
+                               break;
+                       case LC_ID_DYLIB:
+                               {
+                                       fDylibIDOffset = (uint8_t*)cmd - fMachOData;
+                               }
+                               break;
+                       case LC_RPATH:
+                       case LC_LOAD_WEAK_DYLIB:
+                   case LC_REEXPORT_DYLIB:
+                               // do nothing, just prevent LC_REQ_DYLD exception from occuring
+                               break;
+                       default:
+                               if ( (cmd->cmd & LC_REQ_DYLD) != 0 )
+                                       dyld::throwf("unknown required load command 0x%08X", cmd->cmd);
                }
                cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
        }
-}
-
-void ImageLoaderMachO::preFetch(int fd, uint64_t offsetInFat, const LinkContext& context)
-{
-       // always prefetch a subrange of __LINKEDIT pages
-       uintptr_t symbolTableOffset = (uintptr_t)fSymbolTable - (uintptr_t)fLinkEditBase;
-       uintptr_t stringTableOffset = (uintptr_t)fStrings - (uintptr_t)fLinkEditBase;
-       uintptr_t start;
-       // if image did not load at preferred address
-       if ( fSegmentsArray[0].getPreferredLoadAddress() != (uintptr_t)fMachOData ) {
-               // local relocations will be processed, so start pre-fetch at local symbols
-               start = offsetInFat + fDynamicInfo->locreloff;
-       }
-       else {
-               // otherwise start pre-fetch at global symbols section of symbol table
-               start = offsetInFat + symbolTableOffset + fDynamicInfo->iextdefsym * sizeof(macho_nlist);
-       }
-       // prefetch ends at end of last undefined string in string pool
-       uintptr_t end = offsetInFat + stringTableOffset;
-       if ( fDynamicInfo->nundefsym != 0 )
-               end += fSymbolTable[fDynamicInfo->iundefsym+fDynamicInfo->nundefsym-1].n_un.n_strx;
-       else if ( fDynamicInfo->nextdefsym != 0 )
-               end += fSymbolTable[fDynamicInfo->iextdefsym+fDynamicInfo->nextdefsym-1].n_un.n_strx;
        
-       radvisory advice;
-       advice.ra_offset = start & (-4096); // page align
-       advice.ra_count = (end-advice.ra_offset+4095) & (-4096);
-       fgTotalBytesPreFetched += advice.ra_count;
-       fcntl(fd, F_RDADVISE, &advice);
-       if ( context.verboseMapping ) {
-               dyld::log("%18s prefetching 0x%0llX -> 0x%0llX\n", 
-                       "__LINKEDIT", advice.ra_offset+(uintptr_t)fLinkEditBase-offsetInFat, advice.ra_offset+advice.ra_count+(uintptr_t)fLinkEditBase-offsetInFat);
-       }
+       if ( dyldInfo != NULL )
+               this->setDyldInfo(dyldInfo);
+       if ( symbolTable != NULL)
+               this->setSymbolTableInfo(symbolTable, symbolTableStrings, dynSymbolTable);
        
-       // prefetch __DATA/__OBJC pages during launch, but not for dynamically loaded code
-       if ( context.linkingMainExecutable ) {
-               for (ImageLoader::SegmentIterator it = this->beginSegments(); it != this->endSegments(); ++it ) {
-                       Segment* seg = *it;
-                       if ( seg->writeable() && (seg->getFileSize() > 0) ) {
-                               // prefetch writable segment that have mmap'ed regions
-                               advice.ra_offset = offsetInFat + seg->getFileOffset();
-                               advice.ra_count = seg->getFileSize();
-                               // limit prefetch to 1MB (256 pages)
-                               if ( advice.ra_count > 1024*1024 )
-                                       advice.ra_count = 1024*1024;
-                               fgTotalBytesPreFetched += advice.ra_count;
-                               fcntl(fd, F_RDADVISE, &advice);
-                               if ( context.verboseMapping ) {
-                                       dyld::log("%18s prefetching 0x%0lX -> 0x%0lX\n", 
-                                               seg->getName(), seg->getActualLoadAddress(this), seg->getActualLoadAddress(this)+advice.ra_count-1);
-                               }
-                       }
-               }
-       }
 }
 
-bool ImageLoaderMachO::segmentsMustSlideTogether() const 
+// don't do this work in destructor because we need object to be full subclass
+// for UnmapSegments() to work
+void ImageLoaderMachO::destroy()
 {
-       return true;
+       // keep count of images with weak exports
+       if ( this->participatesInCoalescing() ) {
+               --fgImagesRequiringCoalescing;
+               if ( this->hasCoalescedExports() ) 
+                       --fgImagesHasWeakDefinitions;
+       }
+
+       // keep count of images used in shared cache
+       if ( fInSharedCache )
+               --fgImagesUsedFromSharedCache;
+               
+       // unmap image when done
+       UnmapSegments();
 }
 
-bool ImageLoaderMachO::segmentsCanSlide() const 
+
+unsigned int ImageLoaderMachO::segmentCount() const
 {
-       const macho_header* mh = (macho_header*)fMachOData;
-       return ( (mh->filetype == MH_DYLIB) || (mh->filetype == MH_BUNDLE) );
+       return fSegmentsCount;
 }
 
-bool ImageLoaderMachO::isBundle() const 
+
+const macho_segment_command* ImageLoaderMachO::segLoadCommand(unsigned int segIndex) const
 {
-       const macho_header* mh = (macho_header*)fMachOData;
-       return ( mh->filetype == MH_BUNDLE );
+       uint32_t* lcOffsets = this->segmentCommandOffsets();
+       uint32_t lcOffset =     lcOffsets[segIndex];
+       return (macho_segment_command*)(&fMachOData[lcOffset]);
 }
 
-bool ImageLoaderMachO::isDylib() const 
+const char*    ImageLoaderMachO::segName(unsigned int segIndex) const
 {
-       const macho_header* mh = (macho_header*)fMachOData;
-       return ( mh->filetype == MH_DYLIB );
+       return segLoadCommand(segIndex)->segname;
 }
 
-bool ImageLoaderMachO::forceFlat() const 
+
+uintptr_t ImageLoaderMachO::segSize(unsigned int segIndex) const
 {
-       const macho_header* mh = (macho_header*)fMachOData;
-       return ( (mh->flags & MH_FORCE_FLAT) != 0 );
+       return segLoadCommand(segIndex)->vmsize;
 }
 
-bool ImageLoaderMachO::usesTwoLevelNameSpace() const
+
+uintptr_t ImageLoaderMachO::segFileSize(unsigned int segIndex) const
 {
-       const macho_header* mh = (macho_header*)fMachOData;
-       return ( (mh->flags & MH_TWOLEVEL) != 0 );
+       return segLoadCommand(segIndex)->filesize;
 }
 
-bool ImageLoaderMachO::isPrebindable() const 
+
+bool ImageLoaderMachO::segHasTrailingZeroFill(unsigned int segIndex)
 {
-       const macho_header* mh = (macho_header*)fMachOData;
-       return ( (mh->flags & MH_PREBOUND) != 0 );
+       return ( segWriteable(segIndex) && (segSize(segIndex) > segFileSize(segIndex)) );
 }
 
-bool ImageLoaderMachO::hasCoalescedExports() const 
+
+uintptr_t ImageLoaderMachO::segFileOffset(unsigned int segIndex) const
 {
-       const macho_header* mh = (macho_header*)fMachOData;
-       return ( (mh->flags & MH_WEAK_DEFINES) != 0 );
+       return segLoadCommand(segIndex)->fileoff;
 }
 
-bool ImageLoaderMachO::needsCoalescing() const 
+
+bool ImageLoaderMachO::segReadable(unsigned int segIndex) const
 {
-       const macho_header* mh = (macho_header*)fMachOData;
-       return ( (mh->flags & MH_BINDS_TO_WEAK) != 0 );
+       return ( (segLoadCommand(segIndex)->initprot & VM_PROT_READ) != 0);
 }
 
 
+bool ImageLoaderMachO::segWriteable(unsigned int segIndex) const
+{
+       return ( (segLoadCommand(segIndex)->initprot & VM_PROT_WRITE) != 0);
+}
 
 
+bool ImageLoaderMachO::segExecutable(unsigned int segIndex) const
+{
+       return ( (segLoadCommand(segIndex)->initprot & VM_PROT_EXECUTE) != 0);
+}
 
 
-// hack until kernel headers and glue are in system
-struct _shared_region_mapping_np {
-    mach_vm_address_t   address;
-    mach_vm_size_t      size;
-    mach_vm_offset_t    file_offset;
-       vm_prot_t               max_prot;   /* read/write/execute/COW/ZF */
-       vm_prot_t               init_prot;  /* read/write/execute/COW/ZF */
-};
-struct _shared_region_range_np {
-    mach_vm_address_t   address;
-    mach_vm_size_t      size;
-};
-               
-#if SPLIT_SEG_SHARED_REGION_SUPPORT    
-// Called by dyld.  
-// Requests the kernel to map a number of regions from the fd into the
-// shared sections address range (0x90000000-0xAFFFFFFF).
-// If shared_region_make_private_np() has not been called by this process, 
-// the file mapped in is seen in the address space of all processes that
-// participate in using the shared region. 
-// If shared_region_make_private_np() _has_ been called by this process, 
-// the file mapped in is only seen by this process.
-// If the slide parameter is not NULL and then regions cannot be mapped
-// as requested, the kernel will try to map the file in at a different
-// address in the shared region and return the distance slid. 
-// If the mapping requesting cannot be fulfilled, returns non-zero.
-static int 
-_shared_region_map_file_np(
-       int fd,                                                 // file descriptor to map into shared region
-       unsigned int regionCount,               // number of entres in array of regions
-       const _shared_region_mapping_np regions[],      // the array of regions to map
-       uint64_t* slide)                                        // the amount all regions were slid,  NULL means don't attempt to slide
-{
-       //dyld::log("%s(%i, %u, %8p, %8p)\n", __func__, fd, regionCount, regions, slide);
-       //for ( unsigned int i=0; i < regionCount; ++i) {
-       //      dyld::log("\taddress=0x%08llX, size=0x%08llX\n", regions[i].address, regions[i].size);
-       //}
-       int r = syscall(299, fd, regionCount, regions, slide);
-//     if(0 != r)
-//             dyld::log("%s(%i, %u, %8p, %8p) errno=%i (%s)\n", __func__, fd, regionCount, regions, slide, errno, strerror(errno));
-    return r;
-}
-// Called by dyld if shared_region_map_file() fails.
-// Requests the kernel to take this process out of using the shared region.
-// The specified ranges are created as private copies from the shared region for this process.
-static int 
-_shared_region_make_private_np(
-       unsigned int rangeCount,                                // number of entres in array of msrp_range
-       const _shared_region_range_np ranges[]) // the array of shared regions to make private
-{
-       //dyld::log("%s(%u, %8p)\n", __func__, rangeCount, ranges);
-       int r = syscall(300, rangeCount, ranges);
-//     if(0 != r)
-//             dyld::log("%s(%u, %8p) errno=%i (%s)\n", __func__, rangeCount, ranges, errno, strerror(errno));
-    return r;
-}
-#define KERN_SHREG_PRIVATIZABLE        54
-
-
-static int 
-_shared_region_map_file_with_mmap(
-       int fd,                                                 // file descriptor to map into shared region
-       unsigned int regionCount,               // number of entres in array of regions
-       const _shared_region_mapping_np regions[])      // the array of regions to map
-{
-       // map in each region
-       for(unsigned int i=0; i < regionCount; ++i) {
-               void* mmapAddress = (void*)(uintptr_t)(regions[i].address);
-               size_t size = regions[i].size;
-               if ( (regions[i].init_prot & VM_PROT_ZF) != 0 ) {
-                       // do nothing already vm_allocate() which zero fills
-               }
-               else {
-                       int protection = 0;
-                       if ( regions[i].init_prot & VM_PROT_EXECUTE )
-                               protection   |= PROT_EXEC;
-                       if ( regions[i].init_prot & VM_PROT_READ )
-                               protection   |= PROT_READ;
-                       if ( regions[i].init_prot & VM_PROT_WRITE )
-                               protection   |= PROT_WRITE;
-                       off_t offset = regions[i].file_offset;
-                       //dyld::log("mmap(%p, 0x%08lX, block=0x%08X, %s\n", mmapAddress, size, biggestDiff, fPath);
-                       mmapAddress = mmap(mmapAddress, size, protection, MAP_FIXED | MAP_PRIVATE, fd, offset);
-                       if ( mmapAddress == ((void*)(-1)) )
-                               throw "mmap error";
-               }
-       }
-       
-       return 0;
+bool ImageLoaderMachO::segUnaccessible(unsigned int segIndex) const
+{
+       return (segLoadCommand(segIndex)->initprot == 0);
 }
 
-
-static
-bool
-hasSharedRegionMapFile(void)
+bool ImageLoaderMachO::segHasPreferredLoadAddress(unsigned int segIndex) const
 {
-       int     mib[CTL_MAXNAME];
-       int     value = 0;
-       size_t  size;
+       return (segLoadCommand(segIndex)->vmaddr != 0);
+}
 
-       mib[0] = CTL_KERN;
-       mib[1] = KERN_SHREG_PRIVATIZABLE;
-       size = sizeof (int);
-       if (sysctl(mib, 2, &value, &size, NULL, 0) != 0) {
-               value = 0;
-       }
+uintptr_t ImageLoaderMachO::segPreferredLoadAddress(unsigned int segIndex) const
+{
+       return segLoadCommand(segIndex)->vmaddr;
+}
 
-       return 0 != value;
+uintptr_t ImageLoaderMachO::segActualLoadAddress(unsigned int segIndex) const
+{
+       return segLoadCommand(segIndex)->vmaddr + fSlide;
 }
 
-#endif // SPLIT_SEG_SHARED_REGION_SUPPORT      
 
+uintptr_t ImageLoaderMachO::segActualEndAddress(unsigned int segIndex) const
+{
+       return segActualLoadAddress(segIndex) + segSize(segIndex);
+}
 
-#if SPLIT_SEG_DYLIB_SUPPORT    
-unsigned int
-ImageLoaderMachO::getExtraZeroFillEntriesCount()
+bool ImageLoaderMachO::segHasRebaseFixUps(unsigned int segIndex) const
 {
-       // calculate mapping entries
-       unsigned int extraZeroFillEntries = 0;
-       for(ImageLoader::SegmentIterator it = this->beginSegments(); it != this->endSegments(); ++it ) {
-               Segment* seg = *it;
-               if ( seg->hasTrailingZeroFill() )
-                       ++extraZeroFillEntries;
-       }
-       
-       return extraZeroFillEntries;
-}
-
-void
-ImageLoaderMachO::initMappingTable(uint64_t offsetInFat,
-                                                                  _shared_region_mapping_np *mappingTable)
-{
-       unsigned int segmentCount = fSegmentsArrayCount;
-       for(unsigned int segIndex=0,entryIndex=0; segIndex < segmentCount; ++segIndex, ++entryIndex){
-               Segment* seg = &fSegmentsArray[segIndex];
-               _shared_region_mapping_np* entry = &mappingTable[entryIndex];
-               entry->address                  = seg->getActualLoadAddress(this);
-               entry->size                             = seg->getFileSize();
-               entry->file_offset              = seg->getFileOffset() + offsetInFat;
-               entry->init_prot                = VM_PROT_NONE;
-               if ( !seg->unaccessible() ) {
-                       if ( seg->executable() )
-                               entry->init_prot   |= VM_PROT_EXECUTE;
-                       if ( seg->readable() )
-                               entry->init_prot   |= VM_PROT_READ;
-                       if ( seg->writeable() )
-                               entry->init_prot   |= VM_PROT_WRITE | VM_PROT_COW;
-               }
-               entry->max_prot                 = entry->init_prot;
-               if ( seg->hasTrailingZeroFill() ) {
-                       _shared_region_mapping_np* zfentry = &mappingTable[++entryIndex];
-                       zfentry->address                = entry->address + seg->getFileSize();
-                       zfentry->size                   = seg->getSize() - seg->getFileSize();
-                       zfentry->file_offset    = 0;
-                       zfentry->init_prot              = entry->init_prot | VM_PROT_COW | VM_PROT_ZF;
-                       zfentry->max_prot               = zfentry->init_prot;
-               }
+       // scan sections for fix-up bit
+       const macho_segment_command* segCmd = segLoadCommand(segIndex);
+       const struct macho_section* const sectionsStart = (struct macho_section*)((char*)segCmd + sizeof(struct macho_segment_command));
+       const struct macho_section* const sectionsEnd = &sectionsStart[segCmd->nsects];
+       for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+               if ( (sect->flags & S_ATTR_LOC_RELOC) != 0 )
+                       return true;
        }
+       return false;
 }
 
-int
-ImageLoaderMachO::sharedRegionMapFilePrivateOutside(int fd,
-                                                                                                       uint64_t offsetInFat,
-                                                                                                       uint64_t lenInFat,
-                                                                                                       uint64_t fileLen,
-                                                                                                       const LinkContext& context)
+bool ImageLoaderMachO::segHasBindFixUps(unsigned int segIndex) const
 {
-       static uintptr_t sNextAltLoadAddress 
-       #if __ppc_
-               = 0xC0000000;
-       #else
-               = 0;
-       #endif
+       // scan sections for fix-up bit
+       const macho_segment_command* segCmd = segLoadCommand(segIndex);
+       const struct macho_section* const sectionsStart = (struct macho_section*)((char*)segCmd + sizeof(struct macho_segment_command));
+       const struct macho_section* const sectionsEnd = &sectionsStart[segCmd->nsects];
+       for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+               if ( (sect->flags & S_ATTR_EXT_RELOC) != 0 )
+                       return true;
+       }
+       return false;
+}
 
-       const unsigned int segmentCount = fSegmentsArrayCount;
-       const unsigned int extraZeroFillEntries = getExtraZeroFillEntriesCount();
-       const unsigned int regionCount = segmentCount+extraZeroFillEntries;
-       _shared_region_mapping_np regions[regionCount];
-       initMappingTable(offsetInFat, regions);
-       int r = -1;
-               // find space somewhere to allocate split seg
-               bool foundRoom = false;
-               vm_size_t biggestDiff = 0;
-               while ( ! foundRoom ) {
-                       foundRoom = true;
-                       for(unsigned int i=0; i < regionCount; ++i) {
-                               vm_address_t addr = sNextAltLoadAddress + regions[i].address - regions[0].address;
-                               vm_size_t size = regions[i].size ;
-                               r = vm_allocate(mach_task_self(), &addr, size, false /*only this range*/);
-                               if ( 0 != r ) {
-                                       // no room here, deallocate what has succeeded so far
-                                       for(unsigned int j=0; j < i; ++j) {
-                                               vm_address_t addr = sNextAltLoadAddress + regions[j].address - regions[0].address;
-                                               vm_size_t size = regions[j].size ;
-                                               (void)vm_deallocate(mach_task_self(), addr, size);
-                                       }
-                                       sNextAltLoadAddress += 0x00100000;  // skip ahead 1MB and try again
-                                       if ( (sNextAltLoadAddress & 0xF0000000) == 0x90000000 )
-                                               sNextAltLoadAddress = 0xB0000000;
-                                       if ( (sNextAltLoadAddress & 0xF0000000) == 0xF0000000 )
-                                               throw "can't map split seg anywhere";
-                                       foundRoom = false;
-                                       break;
-                               }
-                               vm_size_t high = (regions[i].address + size - regions[0].address) & 0x0FFFFFFF;
-                               if ( high > biggestDiff )
-                                       biggestDiff = high;
-                       }
-               }
-               
-               // map in each region
-               uintptr_t slide = sNextAltLoadAddress - regions[0].address;
-               this->setSlide(slide);
-               for(unsigned int i=0; i < regionCount; ++i) {
-                       if ( ((regions[i].init_prot & VM_PROT_ZF) != 0) || (regions[i].size == 0) ) {
-                               // nothing to mmap for zero-fills areas, they are just vm_allocated 
-                       }
-                       else {
-                               void* mmapAddress = (void*)(uintptr_t)(regions[i].address + slide);
-                               size_t size = regions[i].size;
-                               int protection = 0;
-                               if ( regions[i].init_prot & VM_PROT_EXECUTE )
-                                       protection   |= PROT_EXEC;
-                               if ( regions[i].init_prot & VM_PROT_READ )
-                                       protection   |= PROT_READ;
-                               if ( regions[i].init_prot & VM_PROT_WRITE )
-                                       protection   |= PROT_WRITE;
-                               off_t offset = regions[i].file_offset;
-                               //dyld::log("mmap(%p, 0x%08lX, block=0x%08X, %s\n", mmapAddress, size, biggestDiff, fPath);
-                               mmapAddress = mmap(mmapAddress, size, protection, MAP_FIXED | MAP_PRIVATE, fd, offset);
-                               if ( mmapAddress == ((void*)(-1)) )
-                                       throw "mmap error";
-                       }
-               }
-               // set so next maps right after this one
-               sNextAltLoadAddress += biggestDiff; 
-               sNextAltLoadAddress = (sNextAltLoadAddress + 4095) & (-4096);
-               
-               // logging
-               if ( context.verboseMapping ) {
-                       dyld::log("dyld: Mapping split-seg outside shared region, slid by 0x%08lX %s\n", this->fSlide, this->getPath());
-                       for(unsigned int segIndex=0,entryIndex=0; segIndex < segmentCount; ++segIndex, ++entryIndex){
-                               Segment* seg = &fSegmentsArray[segIndex];
-                               const _shared_region_mapping_np* entry = &regions[entryIndex];
-                               if ( (entry->init_prot & VM_PROT_ZF) == 0 ) 
-                                       dyld::log("%18s at 0x%08lX->0x%08lX\n",
-                                                       seg->getName(), seg->getActualLoadAddress(this), seg->getActualLoadAddress(this)+seg->getFileSize()-1);
-                               if ( entryIndex < (regionCount-1) ) {
-                                       const _shared_region_mapping_np* nextEntry = &regions[entryIndex+1];
-                                       if ( (nextEntry->init_prot & VM_PROT_ZF) != 0 ) {
-                                               uint64_t segOffset = nextEntry->address - entry->address;
-                                               dyld::log("%18s at 0x%08lX->0x%08lX (zerofill)\n",
-                                                               seg->getName(), (uintptr_t)(seg->getActualLoadAddress(this) + segOffset), (uintptr_t)(seg->getActualLoadAddress(this) + segOffset + nextEntry->size - 1));
-                                               ++entryIndex;
-                                       }
-                               }
-                       }
-               }
-               
-               return r;
+#if __i386__
+bool ImageLoaderMachO::segIsReadOnlyImport(unsigned int segIndex) const
+{
+       const macho_segment_command* segCmd = segLoadCommand(segIndex);
+       return (    (segCmd->initprot & VM_PROT_EXECUTE) 
+                       && ((segCmd->initprot & VM_PROT_WRITE) == 0) 
+                       && (strcmp(segCmd->segname, "__IMPORT") == 0) );
 }
+#endif
 
 
-void ImageLoaderMachO::mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context)
+void ImageLoaderMachO::UnmapSegments()
 {
-       // non-split segment libraries handled by super class
-       if ( !fIsSplitSeg )
-               return ImageLoader::mapSegments(fd, offsetInFat, lenInFat, fileLen, context);
-
-#if SPLIT_SEG_SHARED_REGION_SUPPORT    
-       enum SharedRegionState
-       {
-               kSharedRegionStartState = 0,
-               kSharedRegionMapFileState,
-               kSharedRegionMapFilePrivateState,
-               kSharedRegionMapFilePrivateMMapState,
-               kSharedRegionMapFilePrivateOutsideState,
-       };
-       static SharedRegionState sSharedRegionState = kSharedRegionStartState;
-
-       if ( kSharedRegionStartState == sSharedRegionState ) {
-               if ( hasSharedRegionMapFile() ) {
-                       if ( context.sharedRegionMode == kUsePrivateSharedRegion ) { 
-                               sharedRegionMakePrivate(context);
-                               sSharedRegionState = kSharedRegionMapFilePrivateState;
-                       }
-                       else if ( context.sharedRegionMode == kDontUseSharedRegion ) {
-                               sSharedRegionState = kSharedRegionMapFilePrivateOutsideState;
-                       }
-                       else if ( context.sharedRegionMode == kSharedRegionIsSharedCache ) {
-                               sSharedRegionState = kSharedRegionMapFilePrivateOutsideState;
+       // usually unmap image when done
+       if ( ! this->leaveMapped() && (this->getState() >= dyld_image_state_mapped) ) {
+               // unmap TEXT segment last because it contains load command being inspected
+               unsigned int textSegmentIndex = 0;
+               for(unsigned int i=0; i < fSegmentsCount; ++i) {
+                       //dyld::log("unmap %s at 0x%08lX\n", seg->getName(), seg->getActualLoadAddress(this));
+                       if ( strcmp(segName(i), "__TEXT") == 0 ) {
+                               textSegmentIndex = i;
                        }
                        else {
-                               sSharedRegionState = kSharedRegionMapFileState;
+                               // update stats
+                               --ImageLoader::fgTotalSegmentsMapped;
+                               ImageLoader::fgTotalBytesMapped -= segSize(i);
+                               munmap((void*)segActualLoadAddress(i), segSize(i));
                        }
                }
-               else {
-                       sSharedRegionState = kSharedRegionMapFilePrivateOutsideState;
-               }
-       }
-       
-       if ( kSharedRegionMapFileState == sSharedRegionState ) {
-               if ( 0 != sharedRegionMapFile(fd, offsetInFat, lenInFat, fileLen, context) ) {
-                       sharedRegionMakePrivate(context);
-                       sSharedRegionState = kSharedRegionMapFilePrivateState;
-               }
+               // now unmap TEXT
+               --ImageLoader::fgTotalSegmentsMapped;
+               ImageLoader::fgTotalBytesMapped -= segSize(textSegmentIndex);
+               munmap((void*)segActualLoadAddress(textSegmentIndex), segSize(textSegmentIndex));
        }
-       
-       if ( (kSharedRegionMapFilePrivateState == sSharedRegionState) || (kSharedRegionMapFilePrivateMMapState == sSharedRegionState) ) {
-               if ( 0 != sharedRegionMapFilePrivate(fd, offsetInFat, lenInFat, fileLen, context, (kSharedRegionMapFilePrivateMMapState == sSharedRegionState)) ) {
-                       sSharedRegionState = kSharedRegionMapFilePrivateOutsideState;
-               }
-       }
-       
-       if ( kSharedRegionMapFilePrivateOutsideState == sSharedRegionState ) {
-               if ( 0 != sharedRegionMapFilePrivateOutside(fd, offsetInFat, lenInFat, fileLen, context) ) {
-                       throw "mapping error";
+}
+
+
+// prefetch __DATA/__OBJC pages during launch, but not for dynamically loaded code
+void ImageLoaderMachO::preFetchDATA(int fd, uint64_t offsetInFat, const LinkContext& context)
+{
+       if ( context.linkingMainExecutable ) {
+               for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
+                       if ( segWriteable(i) && (segFileSize(i) > 0) ) {
+                               // prefetch writable segment that have mmap'ed regions
+                               radvisory advice;
+                               advice.ra_offset = offsetInFat + segFileOffset(i);
+                               advice.ra_count = segFileSize(i);
+                               // limit prefetch to 1MB (256 pages)
+                               if ( advice.ra_count > 1024*1024 )
+                                       advice.ra_count = 1024*1024;
+                               // don't prefetch single pages, let them fault in
+                               fgTotalBytesPreFetched += advice.ra_count;
+                               fcntl(fd, F_RDADVISE, &advice);
+                               if ( context.verboseMapping ) {
+                                       dyld::log("%18s prefetching 0x%0lX -> 0x%0lX\n", 
+                                               segName(i), segActualLoadAddress(i), segActualLoadAddress(i)+advice.ra_count-1);
+                               }
+                       }
                }
        }
-#else
-       // support old split-seg dylibs by mapping them where ever we find space
-       if ( sharedRegionMapFilePrivateOutside(fd, offsetInFat, lenInFat, fileLen, context) != 0 ) {
-               throw "mapping error";
-       }
-#endif
 }
-#endif // SPLIT_SEG_DYLIB_SUPPORT
 
 
-#if SPLIT_SEG_SHARED_REGION_SUPPORT    
-int ImageLoaderMachO::sharedRegionMakePrivate(const LinkContext& context)
+bool ImageLoaderMachO::segmentsMustSlideTogether() const 
 {
-       if ( context.verboseMapping )
-               dyld::log("dyld: making shared regions private\n");
-
-       // shared mapping failed, so make private copy of shared region and try mapping private
-       MappedRegion allRegions[context.imageCount()*8]; // assume average of less that eight segments per image
-       MappedRegion* end = context.getAllMappedRegions(allRegions);
-       _shared_region_range_np splitSegRegions[end-allRegions];
-       _shared_region_range_np* sp = splitSegRegions;
-       for (MappedRegion* p=allRegions; p < end; ++p) {
-               uint8_t highByte = p->address >> 28;
-               if ( (highByte == 9) || (highByte == 0xA) ) {
-                       _shared_region_range_np splitRegion;
-                       splitRegion.address = p->address;
-                       splitRegion.size = p->size;
-                       *sp++ = splitRegion;
-               }
-       }
-       int result = _shared_region_make_private_np(sp-splitSegRegions, splitSegRegions);
-       // notify gdb or other lurkers that this process is no longer using the shared region
-       dyld_all_image_infos.processDetachedFromSharedRegion = true;
-       return result;
+       return true;
 }
 
-int
-ImageLoaderMachO::sharedRegionMapFile(int fd,
-                                         uint64_t offsetInFat,
-                                         uint64_t lenInFat,
-                                         uint64_t fileLen,
-                                         const LinkContext& context)
-{
-       // build table of segments to map
-       const unsigned int segmentCount = fSegmentsArrayCount;
-       const unsigned int extraZeroFillEntries = getExtraZeroFillEntriesCount();
-       const unsigned int mappingTableCount = segmentCount+extraZeroFillEntries;
-       _shared_region_mapping_np mappingTable[mappingTableCount];
-       initMappingTable(offsetInFat, mappingTable);
-//     uint64_t slide;
-       uint64_t *slidep = NULL;
-
-       // try to map it in shared
-       int r = _shared_region_map_file_np(fd, mappingTableCount, mappingTable, slidep);
-       if ( 0 == r ) {
-               if(NULL != slidep && 0 != *slidep) {
-                       // update with actual load addresses
-               }
-               this->setNeverUnload();
-               if ( context.verboseMapping ) {
-                       dyld::log("dyld: Mapping split-seg shared %s\n", this->getPath());
-                       for(unsigned int segIndex=0,entryIndex=0; segIndex < segmentCount; ++segIndex, ++entryIndex){
-                               Segment* seg = &fSegmentsArray[segIndex];
-                               const _shared_region_mapping_np* entry = &mappingTable[entryIndex];
-                               if ( (entry->init_prot & VM_PROT_ZF) == 0 ) 
-                                       dyld::log("%18s at 0x%08lX->0x%08lX\n",
-                                                       seg->getName(), seg->getActualLoadAddress(this), seg->getActualLoadAddress(this)+seg->getFileSize()-1);
-                               if ( entryIndex < (mappingTableCount-1) ) {
-                                       const _shared_region_mapping_np* nextEntry = &mappingTable[entryIndex+1];
-                                       if ( (nextEntry->init_prot & VM_PROT_ZF) != 0 ) {
-                                               uint64_t segOffset = nextEntry->address - entry->address;
-                                               dyld::log("%18s at 0x%08lX->0x%08lX\n",
-                                                               seg->getName(), (uintptr_t)(seg->getActualLoadAddress(this) + segOffset), (uintptr_t)(seg->getActualLoadAddress(this) + segOffset + nextEntry->size - 1));
-                                               ++entryIndex;
-                                       }
-                               }
-                       }
-               }
-       }
-       return r;
+bool ImageLoaderMachO::segmentsCanSlide() const 
+{
+       return (this->isDylib() || this->isBundle() || this->isPositionIndependentExecutable());
 }
 
-
-int
-ImageLoaderMachO::sharedRegionMapFilePrivate(int fd,
-                                                                                        uint64_t offsetInFat,
-                                                                                        uint64_t lenInFat,
-                                                                                        uint64_t fileLen,
-                                                                                        const LinkContext& context,
-                                                                                        bool usemmap)
+bool ImageLoaderMachO::isBundle() const 
 {
-       const unsigned int segmentCount = fSegmentsArrayCount;
+       const macho_header* mh = (macho_header*)fMachOData;
+       return ( mh->filetype == MH_BUNDLE );
+}
 
-       // build table of segments to map
-       const unsigned int extraZeroFillEntries = getExtraZeroFillEntriesCount();
-       const unsigned int mappingTableCount = segmentCount+extraZeroFillEntries;
-       _shared_region_mapping_np mappingTable[mappingTableCount];
-       initMappingTable(offsetInFat, mappingTable);
-       uint64_t slide = 0;
+bool ImageLoaderMachO::isDylib() const 
+{
+       const macho_header* mh = (macho_header*)fMachOData;
+       return ( mh->filetype == MH_DYLIB );
+}
 
-       // try map it in privately (don't allow sliding if we pre-calculated the load address to pack dylibs)
-       int r;
-       if ( usemmap )
-               r = _shared_region_map_file_with_mmap(fd, mappingTableCount, mappingTable);
-       else
-               r = _shared_region_map_file_np(fd, mappingTableCount, mappingTable, &slide);
-       if ( 0 == r ) {
-               if ( 0 != slide ) {
-                       slide = (slide) & (-4096); // round down to page boundary
-                       this->setSlide(slide);
-               }
-               this->setNeverUnload();
-               if ( context.verboseMapping ) {
-                       if ( slide == 0 )
-                               dyld::log("dyld: Mapping split-seg un-shared %s\n", this->getPath());
-                       else
-                               dyld::log("dyld: Mapping split-seg un-shared slid by 0x%08llX %s\n", slide, this->getPath());
-                       for(unsigned int segIndex=0,entryIndex=0; segIndex < segmentCount; ++segIndex, ++entryIndex){
-                               Segment* seg = &fSegmentsArray[segIndex];
-                               const _shared_region_mapping_np* entry = &mappingTable[entryIndex];
-                               if ( (entry->init_prot & VM_PROT_ZF) == 0 ) 
-                                       dyld::log("%18s at 0x%08lX->0x%08lX\n",
-                                                       seg->getName(), seg->getActualLoadAddress(this), seg->getActualLoadAddress(this)+seg->getFileSize()-1);
-                               if ( entryIndex < (mappingTableCount-1) ) {
-                                       const _shared_region_mapping_np* nextEntry = &mappingTable[entryIndex+1];
-                                       if ( (nextEntry->init_prot & VM_PROT_ZF) != 0 ) {
-                                               uint64_t segOffset = nextEntry->address - entry->address;
-                                               dyld::log("%18s at 0x%08lX->0x%08lX (zerofill)\n",
-                                                               seg->getName(), (uintptr_t)(seg->getActualLoadAddress(this) + segOffset), (uintptr_t)(seg->getActualLoadAddress(this) + segOffset + nextEntry->size - 1));
-                                               ++entryIndex;
-                                       }
-                               }
-                       }
-               }
-       }
-       if ( r != 0 )
-               dyld::throwf("can't rebase split-seg dylib %s because shared_region_map_file_np() returned %d", this->getPath(), r);
-       
-       return r;
-}
-
-void
-ImageLoaderMachO::initMappingTable(uint64_t offsetInFat,
-                                                                  sf_mapping *mappingTable,
-                                                                  uintptr_t baseAddress)
-{
-       unsigned int segmentCount = fSegmentsArrayCount;
-       for(unsigned int segIndex=0,entryIndex=0; segIndex < segmentCount; ++segIndex, ++entryIndex){
-               Segment* seg = &fSegmentsArray[segIndex];
-               sf_mapping* entry = &mappingTable[entryIndex];
-               entry->mapping_offset   = seg->getPreferredLoadAddress() - baseAddress;
-               entry->size                             = seg->getFileSize();
-               entry->file_offset              = seg->getFileOffset() + offsetInFat;
-               entry->protection               = VM_PROT_NONE;
-               if ( !seg->unaccessible() ) {
-                       if ( seg->executable() )
-                               entry->protection   |= VM_PROT_EXECUTE;
-                       if ( seg->readable() )
-                               entry->protection   |= VM_PROT_READ;
-                       if ( seg->writeable() )
-                               entry->protection   |= VM_PROT_WRITE | VM_PROT_COW;
-               }
-               
-               entry->cksum                    = 0;
-               if ( seg->hasTrailingZeroFill() ) {
-                       sf_mapping* zfentry = &mappingTable[++entryIndex];
-                       zfentry->mapping_offset = entry->mapping_offset + seg->getFileSize();
-                       zfentry->size                   = seg->getSize() - seg->getFileSize();
-                       zfentry->file_offset    = 0;
-                       zfentry->protection             = entry->protection | VM_PROT_COW | VM_PROT_ZF;
-                       zfentry->cksum                  = 0;
-               }
-       }
+bool ImageLoaderMachO::isExecutable() const 
+{
+       const macho_header* mh = (macho_header*)fMachOData;
+       return ( mh->filetype == MH_EXECUTE );
 }
 
-#endif // SPLIT_SEG_SHARED_REGION_SUPPORT      
+bool ImageLoaderMachO::isPositionIndependentExecutable() const 
+{
+       const macho_header* mh = (macho_header*)fMachOData;
+       return ( (mh->filetype == MH_EXECUTE) && ((mh->flags & MH_PIE) != 0) );
+}
 
 
+bool ImageLoaderMachO::forceFlat() const 
+{
+       const macho_header* mh = (macho_header*)fMachOData;
+       return ( (mh->flags & MH_FORCE_FLAT) != 0 );
+}
 
-void ImageLoaderMachO::setSlide(intptr_t slide)
+bool ImageLoaderMachO::usesTwoLevelNameSpace() const
 {
-       fSlide = slide;
+       const macho_header* mh = (macho_header*)fMachOData;
+       return ( (mh->flags & MH_TWOLEVEL) != 0 );
 }
 
-void ImageLoaderMachO::parseLoadCmds()
+bool ImageLoaderMachO::isPrebindable() const 
 {
-       // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
-       for (ImageLoader::SegmentIterator it = this->beginSegments(); it != this->endSegments(); ++it ) {
-               Segment* seg = *it;
-               // set up pointer to __LINKEDIT segment
-               if ( strcmp(seg->getName(),"__LINKEDIT") == 0 ) 
-                       fLinkEditBase = (uint8_t*)(seg->getActualLoadAddress(this) - seg->getFileOffset());
-#if TEXT_RELOC_SUPPORT
-               // __TEXT segment always starts at beginning of file and contains mach_header and load commands
-               if ( strcmp(seg->getName(),"__TEXT") == 0 ) {
-                       if ( ((SegmentMachO*)seg)->hasFixUps() )
-                               fTextSegmentWithFixups = (SegmentMachO*)seg;
-               }
-#endif
-#if __i386__
-               if ( seg->readOnlyImportStubs() )
-                       fReadOnlyImportSegment = (SegmentMachO*)seg;
-#endif
-               // some segment always starts at beginning of file and contains mach_header and load commands
-               if ( (seg->getFileOffset() == 0) && (seg->getFileSize() != 0) ) {
-                       fMachOData = (uint8_t*)(seg->getActualLoadAddress(this));
-               }
-       #if __ppc64__
-               // in 10.5 to support images that span 4GB (including pagezero) switch meaning of r_address
-               if ( ((seg->getPreferredLoadAddress() + seg->getSize() - fSegmentsArray[0].getPreferredLoadAddress()) > 0x100000000) 
-                && seg->writeable() )
-                       f4GBWritable = true;
-       #endif
-       }
-       
-       // keep count of prebound images with weak exports
-       if ( this->hasCoalescedExports() )
-               ++fgCountOfImagesWithWeakExports;
+       const macho_header* mh = (macho_header*)fMachOData;
+       return ( (mh->flags & MH_PREBOUND) != 0 );
+}
 
-       // keep count of images used in shared cache
-       if ( fInSharedCache )
-               ++fgImagesUsedFromSharedCache;
+bool ImageLoaderMachO::hasCoalescedExports() const 
+{
+       const macho_header* mh = (macho_header*)fMachOData;
+       return ( (mh->flags & MH_WEAK_DEFINES) != 0 );
+}
 
-       // walk load commands (mapped in at start of __TEXT segment)
-       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_SYMTAB:
-                               {
-                                       const struct symtab_command* symtab = (struct symtab_command*)cmd;
-                                       fStrings = (const char*)&fLinkEditBase[symtab->stroff];
-                                       fSymbolTable = (struct macho_nlist*)(&fLinkEditBase[symtab->symoff]);
-                               }
-                               break;
-                       case LC_DYSYMTAB:
-                               fDynamicInfo = (struct dysymtab_command*)cmd;
-                               break;
-                       case LC_SUB_UMBRELLA:
-                               fHasSubUmbrella = true;
-                               break;
-                       case LC_SUB_FRAMEWORK:
-                               fInUmbrella = true;
-                               break;
-                       case LC_SUB_LIBRARY:
-                               fHasSubLibraries = true;
-                               break;
-                       case LC_ROUTINES_COMMAND:
-                               fHasDashInit = true;
-                               break;
-                       case LC_SEGMENT_COMMAND:
-                               {
-                                       const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
-#if IMAGE_NOTIFY_SUPPORT
-                                       const bool isDataSeg = (strcmp(seg->segname, "__DATA") == 0);
-#endif
-                                       const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
-                                       const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
-                                       for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
-                                               const uint8_t type = sect->flags & SECTION_TYPE;
-                                               if ( type == S_MOD_INIT_FUNC_POINTERS )
-                                                       fHasInitializers = true;
-                                               else if ( type == S_MOD_TERM_FUNC_POINTERS )
-                                                       fHasTerminators = true;
-                                               else if ( type == S_DTRACE_DOF )
-                                                       fHasDOFSections = true;
-#if IMAGE_NOTIFY_SUPPORT
-                                               else if ( isDataSeg && (strcmp(sect->sectname, "__image_notify") == 0) )
-                                                       fHasImageNotifySection = true;
-#endif
-                                       }
-                               }
-                               break;
-                       case LC_TWOLEVEL_HINTS:
-                               fTwoLevelHints = (struct twolevel_hints_command*)cmd;
-                               break;
-                       case LC_ID_DYLIB:
-                               {
-                                       fDylibID = (struct dylib_command*)cmd;
-                               }
-                               break;
-                       case LC_RPATH:
-                       case LC_LOAD_WEAK_DYLIB:
-                   case LC_REEXPORT_DYLIB:
-                               // do nothing, just prevent LC_REQ_DYLD exception from occuring
-                               break;
-                       default:
-                               if ( (cmd->cmd & LC_REQ_DYLD) != 0 )
-                                       dyld::throwf("unknown required load command 0x%08X", cmd->cmd);
-               }
-               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
-       }
+bool ImageLoaderMachO::hasReferencesToWeakSymbols() const 
+{
+       const macho_header* mh = (macho_header*)fMachOData;
+       return ( (mh->flags & MH_BINDS_TO_WEAK) != 0 );
 }
 
+bool ImageLoaderMachO::participatesInCoalescing() const 
+{
+       const macho_header* mh = (macho_header*)fMachOData;
+       // if image is loaded with RTLD_LOCAL, then its symbols' visibility
+       // is reduced and it can't coalesce with other images
+       if ( this->hasHiddenExports() )
+               return false;
+       return ( (mh->flags & (MH_WEAK_DEFINES|MH_BINDS_TO_WEAK)) != 0 );
+}
 
 
 
-const char* ImageLoaderMachO::getInstallPath() const
+void ImageLoaderMachO::setSlide(intptr_t slide)
 {
-       if ( fDylibID != NULL ) {
-               return (char*)fDylibID + fDylibID->dylib.name.offset;
-       }
-       return NULL;
+       fSlide = slide;
 }
 
-// test if this image is re-exported through parent (the image that loaded this one)
-bool ImageLoaderMachO::isSubframeworkOf(const LinkContext& context, const ImageLoader* parent) const
+#if CODESIGNING_SUPPORT
+void ImageLoaderMachO::loadCodeSignature(const uint8_t* fileData, int fd,  uint64_t offsetInFatFile)
 {
-       if ( fInUmbrella ) {
-               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) {
-                       if (cmd->cmd == LC_SUB_FRAMEWORK) {
-                               const struct sub_framework_command* subf = (struct sub_framework_command*)cmd;
-                               const char* exportThruName = (char*)cmd + subf->umbrella.offset;
-                               // need to match LC_SUB_FRAMEWORK string against the leaf name of the install location of parent...
-                               const char* parentInstallPath = parent->getInstallPath();
-                               if ( parentInstallPath != NULL ) {
-                                       const char* lastSlash = strrchr(parentInstallPath, '/');
-                                       if ( lastSlash != NULL ) {
-                                               if ( strcmp(&lastSlash[1], exportThruName) == 0 )
-                                                       return true;
-                                               if ( context.imageSuffix != NULL ) {
-                                                       // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end
-                                                       char reexportAndSuffix[strlen(context.imageSuffix)+strlen(exportThruName)+1];
-                                                       strcpy(reexportAndSuffix, exportThruName);
-                                                       strcat(reexportAndSuffix, context.imageSuffix);
-                                                       if ( strcmp(&lastSlash[1], reexportAndSuffix) == 0 )
-                                                               return true;
-                                               }
-                                       }
+       // 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;
                                }
                        }
-                       cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+                       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);
        }
-       return false;
 }
+#endif
 
-// test if child is re-exported 
-bool ImageLoaderMachO::hasSubLibrary(const LinkContext& context, const ImageLoader* child) const
-{
-       if ( fHasSubLibraries ) {
-               // need to match LC_SUB_LIBRARY string against the leaf name (without extension) of the install location of child...
-               const char* childInstallPath = child->getInstallPath();
-               if ( childInstallPath != NULL ) {
-                       const char* lastSlash = strrchr(childInstallPath, '/');
-                       if ( lastSlash != NULL ) {
-                               const char* firstDot = strchr(lastSlash, '.');
-                               int len;
-                               if ( firstDot == NULL )
-                                       len = strlen(lastSlash);
-                               else
-                                       len = firstDot-lastSlash-1;
-                               char childLeafName[len+1];
-                               strncpy(childLeafName, &lastSlash[1], len);
-                               childLeafName[len] = '\0';
-                               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_SUB_LIBRARY:
-                                                       {
-                                                               const struct sub_library_command* lib = (struct sub_library_command*)cmd;
-                                                               const char* aSubLibName = (char*)cmd + lib->sub_library.offset;
-                                                               if ( strcmp(aSubLibName, childLeafName) == 0 )
-                                                                       return true;
-                                                               if ( context.imageSuffix != NULL ) {
-                                                                       // when DYLD_IMAGE_SUFFIX is used, childLeafName string needs imageSuffix removed from end
-                                                                       char aSubLibNameAndSuffix[strlen(context.imageSuffix)+strlen(aSubLibName)+1];
-                                                                       strcpy(aSubLibNameAndSuffix, aSubLibName);
-                                                                       strcat(aSubLibNameAndSuffix, context.imageSuffix);
-                                                                       if ( strcmp(aSubLibNameAndSuffix, childLeafName) == 0 )
-                                                                               return true;
-                                                               }
-                                                       }
-                                                       break;
-                                       }
-                                       cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
-                               }
-                       }
-               }
-       }
-       if ( fHasSubUmbrella ) {
-               // need to match LC_SUB_UMBRELLA string against the leaf name of install location of child...
-               const char* childInstallPath = child->getInstallPath();
-               if ( childInstallPath != NULL ) {
-                       const char* lastSlash = strrchr(childInstallPath, '/');
-                       if ( lastSlash != NULL ) {
-                               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_SUB_UMBRELLA:
-                                                       {
-                                                               const struct sub_umbrella_command* um = (struct sub_umbrella_command*)cmd;
-                                                               const char* aSubUmbrellaName = (char*)cmd + um->sub_umbrella.offset;
-                                                               if ( strcmp(aSubUmbrellaName, &lastSlash[1]) == 0 )
-                                                                       return true;
-                                                               if ( context.imageSuffix != NULL ) {
-                                                                       // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end
-                                                                       char umbrellaAndSuffix[strlen(context.imageSuffix)+strlen(aSubUmbrellaName)+1];
-                                                                       strcpy(umbrellaAndSuffix, aSubUmbrellaName);
-                                                                       strcat(umbrellaAndSuffix, context.imageSuffix);
-                                                                       if ( strcmp(umbrellaAndSuffix, &lastSlash[1]) == 0 )
-                                                                               return true;
-                                                               }
-                                                       }
-                                                       break;
-                                       }
-                                       cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
-                               }
-                       }
-               }
+
+const char* ImageLoaderMachO::getInstallPath() const
+{
+       if ( fDylibIDOffset != 0 ) {
+               const dylib_command* dylibID = (dylib_command*)(&fMachOData[fDylibIDOffset]);
+               return (char*)dylibID + dylibID->dylib.name.offset;
        }
-       return false;
+       return NULL;
 }
 
 
@@ -1304,7 +679,7 @@ void* ImageLoaderMachO::getMain() const
        const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
        const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
        const struct load_command* cmd = cmds;
-       for (unsigned long i = 0; i < cmd_count; ++i) {
+       for (uint32_t i = 0; i < cmd_count; ++i) {
                switch (cmd->cmd) {
                        case LC_UNIXTHREAD:
                        {
@@ -1320,6 +695,9 @@ void* ImageLoaderMachO::getMain() const
                        #elif __x86_64__
                                const x86_thread_state64_t* registers = (x86_thread_state64_t*)(((char*)cmd) + 16);
                                return (void*)(registers->rip + fSlide);
+                       #elif __arm__
+                               const arm_thread_state_t* registers = (arm_thread_state_t*)(((char*)cmd) + 16);
+                               return (void*)(registers->__pc + fSlide);
                        #else
                                #warning need processor specific code
                        #endif
@@ -1331,61 +709,90 @@ void* ImageLoaderMachO::getMain() const
        return NULL;
 }
 
-
-uint32_t ImageLoaderMachO::doGetDependentLibraryCount()
+bool ImageLoaderMachO::needsAddedLibSystemDepency(unsigned int libCount, const macho_header* mh)
 {
-       const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
-       const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
-       uint32_t count = 0;
+       // <rdar://problem/6357561> ensure that every image depends on something which depends on libSystem
+       if ( libCount > 1 )
+               return false;
+               
+       // <rdar://problem/6409800> dyld implicit-libSystem breaks valgrind
+       if ( mh->filetype == MH_EXECUTE ) 
+               return false;
+       
+       bool isNonOSdylib = 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 (unsigned long i = 0; i < cmd_count; ++i) {
+       for (uint32_t i = 0; i < cmd_count; ++i) {
                switch (cmd->cmd) {
                        case LC_LOAD_DYLIB:
                        case LC_LOAD_WEAK_DYLIB:
                        case LC_REEXPORT_DYLIB:
-                               ++count;
+                               return false;
+                       case LC_ID_DYLIB:
+                               {
+                               const dylib_command* dylibID = (dylib_command*)cmd;
+                               const char* installPath = (char*)cmd + dylibID->dylib.name.offset;
+                               // It is OK for OS dylibs (libSystem or libmath or Rosetta shims) to have no dependents
+                               // but all other dylibs must depend on libSystem for initialization to initialize libSystem first
+                               // <rdar://problem/6497528> rosetta circular dependency spew
+                               isNonOSdylib = ( (strncmp(installPath, "/usr/lib/", 9) != 0) && (strncmp(installPath, "/usr/libexec/oah/Shims", 9) != 0) );
+                               }
                                break;
                }
                cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
        }
-       return count;
+       return isNonOSdylib;
 }
 
+
 void ImageLoaderMachO::doGetDependentLibraries(DependentLibraryInfo libs[])
 {
-       uint32_t index = 0;
-       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 (unsigned long i = 0; i < cmd_count; ++i) {
-               switch (cmd->cmd) {
-                       case LC_LOAD_DYLIB:
-                       case LC_LOAD_WEAK_DYLIB:
-                       case LC_REEXPORT_DYLIB:
-                       {
-                               const struct dylib_command* dylib = (struct dylib_command*)cmd;
-                               DependentLibraryInfo* lib = &libs[index++];
-                               lib->name = (char*)cmd + dylib->dylib.name.offset;
-                               //lib->name = strdup((char*)cmd + dylib->dylib.name.offset);
-                               lib->info.checksum = dylib->dylib.timestamp;
-                               lib->info.minVersion = dylib->dylib.compatibility_version;
-                               lib->info.maxVersion = dylib->dylib.current_version;
-                               lib->required = (cmd->cmd != LC_LOAD_WEAK_DYLIB);
-                               lib->reExported = (cmd->cmd == LC_REEXPORT_DYLIB);
+       if ( needsAddedLibSystemDepency(libraryCount(), (macho_header*)fMachOData) ) {
+               DependentLibraryInfo* lib = &libs[0];
+               lib->name = "/usr/lib/libSystem.B.dylib";
+               lib->info.checksum = 0;
+               lib->info.minVersion = 0;
+               lib->info.maxVersion = 0;
+               lib->required = false;
+               lib->reExported = false;
+       }
+       else {
+               uint32_t index = 0;
+               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_LOAD_DYLIB:
+                               case LC_LOAD_WEAK_DYLIB:
+                               case LC_REEXPORT_DYLIB:
+                               {
+                                       const struct dylib_command* dylib = (struct dylib_command*)cmd;
+                                       DependentLibraryInfo* lib = &libs[index++];
+                                       lib->name = (char*)cmd + dylib->dylib.name.offset;
+                                       //lib->name = strdup((char*)cmd + dylib->dylib.name.offset);
+                                       lib->info.checksum = dylib->dylib.timestamp;
+                                       lib->info.minVersion = dylib->dylib.compatibility_version;
+                                       lib->info.maxVersion = dylib->dylib.current_version;
+                                       lib->required = (cmd->cmd != LC_LOAD_WEAK_DYLIB);
+                                       lib->reExported = (cmd->cmd == LC_REEXPORT_DYLIB);
+                               }
+                               break;
                        }
-                       break;
+                       cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
                }
-               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
        }
 }
 
 ImageLoader::LibraryInfo ImageLoaderMachO::doGetLibraryInfo()
 {
        LibraryInfo info;
-       if ( fDylibID != NULL ) {
-               info.minVersion = fDylibID->dylib.compatibility_version;
-               info.maxVersion = fDylibID->dylib.current_version;
-               info.checksum = fDylibID->dylib.timestamp;
+       if ( fDylibIDOffset != 0 ) {
+               const dylib_command* dylibID = (dylib_command*)(&fMachOData[fDylibIDOffset]);
+               info.minVersion = dylibID->dylib.compatibility_version;
+               info.maxVersion = dylibID->dylib.current_version;
+               info.checksum = dylibID->dylib.timestamp;
        }
        else {
                info.minVersion = 0;
@@ -1400,13 +807,13 @@ void ImageLoaderMachO::getRPaths(const LinkContext& context, std::vector<const c
        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 (unsigned long i = 0; i < cmd_count; ++i) {
+       for (uint32_t i = 0; i < cmd_count; ++i) {
                switch (cmd->cmd) {
                        case LC_RPATH:
                                const char* path = (char*)cmd + ((struct rpath_command*)cmd)->path.offset;
                                if ( strncmp(path, "@loader_path/", 13) == 0 ) {
-                                       if ( issetugid() && (context.mainExecutable == this) ) {
-                                               dyld::warn("LC_RPATH %s in %s being ignored in setuid program because of @loader_path\n", path, this->getPath());
+                                       if ( context.processIsRestricted  && (context.mainExecutable == this) ) {
+                                               dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @loader_path\n", path, this->getPath());
                                                break;
                                        }
                                        char resolvedPath[PATH_MAX];
@@ -1422,8 +829,8 @@ void ImageLoaderMachO::getRPaths(const LinkContext& context, std::vector<const c
                                        }
                                }
                                else if ( strncmp(path, "@executable_path/", 17) == 0 ) {
-                                       if ( issetugid() ) {
-                                               dyld::warn("LC_RPATH %s in %s being ignored in setuid program because of @executable_path\n", path, this->getPath());
+                                       if ( context.processIsRestricted ) {
+                                               dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @executable_path\n", path, this->getPath());
                                                break;
                                        }
                                        char resolvedPath[PATH_MAX];
@@ -1438,108 +845,59 @@ void ImageLoaderMachO::getRPaths(const LinkContext& context, std::vector<const c
                                                path = strdup(newRealPath);
                                        }
                                }
-                               else if ( (path[0] != '/') && issetugid() ) {
-                                       dyld::warn("LC_RPATH %s in %s being ignored in setuid program because it is a relative path\n", path, this->getPath());
+                               else if ( (path[0] != '/') && context.processIsRestricted ) {
+                                       dyld::warn("LC_RPATH %s in %s being ignored in restricted program because it is a relative path\n", path, this->getPath());
                                        break;
                                }
-                               else {
-                                       // make copy so that all elements of 'paths' can be freed
-                                       path = strdup(path);
-                               }
-                               paths.push_back(path);
-                               break;
-               }
-               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
-       }
-}
-
-uintptr_t ImageLoaderMachO::getFirstWritableSegmentAddress()
-{
-       // in split segment libraries r_address is offset from first writable segment
-       for(ImageLoader::SegmentIterator it = this->beginSegments(); it != this->endSegments(); ++it ) {
-               Segment* seg = *it;
-               if ( seg->writeable() ) 
-                       return seg->getActualLoadAddress(this);
-       }
-       throw "no writable segment";
-}
-
-uintptr_t ImageLoaderMachO::getRelocBase()
-{
-       // r_address is either an offset from the first segment address
-       // or from the first writable segment address
-#if __ppc__ || __i386__
-       if ( fIsSplitSeg )
-               return getFirstWritableSegmentAddress();
-       else
-               return fSegmentsArray[0].getActualLoadAddress(this);
-#elif __ppc64__
-       if ( f4GBWritable )
-               return getFirstWritableSegmentAddress();
-       else
-               return fSegmentsArray[0].getActualLoadAddress(this);
-#elif __x86_64__
-       return getFirstWritableSegmentAddress();
-#endif
-}
-
-
-#if __ppc__
-static inline void otherRelocsPPC(uintptr_t* locationToFix, uint8_t relocationType, uint16_t otherHalf, uintptr_t slide)
-{
-       // low 16 bits of 32-bit ppc instructions need fixing
-       struct ppcInstruction { uint16_t opcode; int16_t immediateValue; };
-       ppcInstruction* instruction = (ppcInstruction*)locationToFix;
-       //uint32_t before = *((uint32_t*)locationToFix);
-       switch ( relocationType )
-       {
-               case PPC_RELOC_LO16: 
-                       instruction->immediateValue = ((otherHalf << 16) | instruction->immediateValue) + slide;
-                       break;
-               case PPC_RELOC_HI16: 
-                       instruction->immediateValue = ((((instruction->immediateValue << 16) | otherHalf) + slide) >> 16);
-                       break;
-               case PPC_RELOC_HA16: 
-                       int16_t signedOtherHalf = (int16_t)(otherHalf & 0xffff);
-                       uint32_t temp = (instruction->immediateValue << 16) + signedOtherHalf + slide;
-                       if ( (temp & 0x00008000) != 0 )
-                               temp += 0x00008000;
-                       instruction->immediateValue = temp >> 16;
+                               else if ( (path[0] == '/') && (context.rootPaths != NULL) ) {
+                                       // <rdar://problem/5869973> DYLD_ROOT_PATH should apply to LC_RPATH rpaths
+                                       // DYLD_ROOT_PATH can be a list of paths, but at this point we can only support one, so use first combination that exists
+                                       bool found = false;
+                                       for(const char** rp = context.rootPaths; *rp != NULL; ++rp) {
+                                               char newPath[PATH_MAX];
+                                               strcpy(newPath, *rp);
+                                               strcat(newPath, path);
+                                               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);
+                                                       found = true;
+                                                       break;
+                                               }
+                                       }
+                                       if ( ! found ) {
+                                               // make copy so that all elements of 'paths' can be freed
+                                               path = strdup(path);
+                                       }
+                               }
+                               else {
+                                       // make copy so that all elements of 'paths' can be freed
+                                       path = strdup(path);
+                               }
+                               paths.push_back(path);
+                               break;
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
        }
-       //uint32_t after = *((uint32_t*)locationToFix);
-       //dyld::log("dyld: ppc fixup %0p type %d from 0x%08X to 0x%08X\n", locationToFix, relocationType, before, after);
 }
-#endif
 
-#if __ppc__ || __i386__
-void ImageLoaderMachO::resetPreboundLazyPointers(const LinkContext& context, uintptr_t relocBase)
-{
-       // loop through all local (internal) relocation records looking for pre-bound-lazy-pointer values
-       register const uintptr_t slide = this->fSlide;
-       const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->locreloff]);
-       const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nlocrel];
-       for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
-               if ( (reloc->r_address & R_SCATTERED) != 0 ) {
-                       const struct scattered_relocation_info* sreloc = (struct scattered_relocation_info*)reloc;
-                       if (sreloc->r_length == RELOC_SIZE) {
-                               uintptr_t* locationToFix = (uintptr_t*)(sreloc->r_address + relocBase);
-                               switch(sreloc->r_type) {
-               #if __ppc__ 
-                                       case PPC_RELOC_PB_LA_PTR:
-                                               *locationToFix = sreloc->r_value + slide;
-                                               break;
-               #endif
-               #if __i386__
-                                       case GENERIC_RELOC_PB_LA_PTR:
-                                               *locationToFix = sreloc->r_value + slide;
-                                               break;
-               #endif
-                               }
-                       }
+bool ImageLoaderMachO::getUUID(uuid_t uuid) const
+{
+       const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
+       const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
+       const struct load_command* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               switch (cmd->cmd) {
+                       case LC_UUID:
+                               uuid_command* uc = (uuid_command*)cmd;
+                               memcpy(uuid, uc->uuid, 16);
+                               return true;
                }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
        }
+       bzero(uuid, 16);
+       return false;
 }
-#endif
 
 void ImageLoaderMachO::doRebase(const LinkContext& context)
 {
@@ -1549,7 +907,7 @@ void ImageLoaderMachO::doRebase(const LinkContext& context)
                ++fgImagesWithUsedPrebinding; // bump totals for statistics
                return;
        }
-       
+
        // print why prebinding was not used
        if ( context.verbosePrebinding ) {
                if ( !this->isPrebindable() ) {
@@ -1569,375 +927,141 @@ void ImageLoaderMachO::doRebase(const LinkContext& context)
                }
        }
 
-       // cache values that are used in the following loop
-       const uintptr_t relocBase = this->getRelocBase();
-       register const uintptr_t slide = this->fSlide;
-
        //dyld::log("slide=0x%08lX for %s\n", slide, this->getPath());
 
-#if __ppc__ || __i386__
+#if PREBOUND_IMAGE_SUPPORT
        // if prebound and we got here, then prebinding is not valid, so reset all lazy pointers
        // if this image is in the shared cache, do not reset, they will be bound in doBind()
        if ( this->isPrebindable() && !fInSharedCache )
-               this->resetPreboundLazyPointers(context, relocBase);
+               this->resetPreboundLazyPointers(context);
 #endif
 
-       // if in shared cache and got here, then we depend on something not in the shared cache
-       if ( fInSharedCache ) 
-               context.notifySharedCacheInvalid();
-
        // if loaded at preferred address, no rebasing necessary
-       if ( slide == 0 ) 
+       if ( this->fSlide == 0 ) 
                return;
 
 #if TEXT_RELOC_SUPPORT
        // if there are __TEXT fixups, temporarily make __TEXT writable
-       if ( fTextSegmentWithFixups != NULL ) 
-               fTextSegmentWithFixups->tempWritable(context, this);
+       if ( fTextSegmentRebases ) 
+               this->makeTextSegmentWritable(context, true);
 #endif
-       // loop through all local (internal) relocation records
-       const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->locreloff]);
-       const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nlocrel];
-       for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
-#if LINKEDIT_USAGE_DEBUG
-               noteAccessedLinkEditAddress(reloc);
-#endif
-       #if __x86_64__
-               // only one kind of local relocation supported for x86_64
-               if ( reloc->r_length != 3 ) 
-                       throw "bad local relocation length";
-               if ( reloc->r_type != X86_64_RELOC_UNSIGNED ) 
-                       throw "unknown local relocation type";
-               if ( reloc->r_pcrel != 0 ) 
-                       throw "bad local relocation pc_rel";
-               if ( reloc->r_extern != 0 ) 
-                       throw "extern relocation found with local relocations";
-               *((uintptr_t*)(reloc->r_address + relocBase)) += slide;
-       #else   
-               if ( (reloc->r_address & R_SCATTERED) == 0 ) {
-                       if ( reloc->r_symbolnum == R_ABS ) {
-                               // ignore absolute relocations
-                       }
-                       else if (reloc->r_length == RELOC_SIZE) {
-                               switch(reloc->r_type) {
-                                       case GENERIC_RELOC_VANILLA:
-                                               *((uintptr_t*)(reloc->r_address + relocBase)) += slide;
-                                               break;
-               #if __ppc__
-                                       case PPC_RELOC_HI16: 
-                                       case PPC_RELOC_LO16: 
-                                       case PPC_RELOC_HA16: 
-                                               // some tools leave object file relocations in linked images
-                                               otherRelocsPPC((uintptr_t*)(reloc->r_address + relocBase), reloc->r_type, reloc[1].r_address, slide);
-                                               ++reloc; // these relocations come in pairs, skip next
-                                               break;
-               #endif
-                                       default:
-                                               throw "unknown local relocation type";
-                               }
-                       }
-                       else {
-                               throw "bad local relocation length";
-                       }
-               }
-               else {
-                       const struct scattered_relocation_info* sreloc = (struct scattered_relocation_info*)reloc;
-                       if (sreloc->r_length == RELOC_SIZE) {
-                               uintptr_t* locationToFix = (uintptr_t*)(sreloc->r_address + relocBase);
-                               switch(sreloc->r_type) {
-                                       case GENERIC_RELOC_VANILLA:
-                                               *locationToFix += slide;
-                                               break;
-               #if __ppc__
-                                       case PPC_RELOC_HI16: 
-                                       case PPC_RELOC_LO16: 
-                                       case PPC_RELOC_HA16: 
-                                               // Metrowerks compiler sometimes leaves object file relocations in linked images???
-                                               ++reloc; // these relocations come in pairs, get next one
-                                               otherRelocsPPC(locationToFix, sreloc->r_type, reloc->r_address, slide);
-                                               break;
-                                       case PPC_RELOC_PB_LA_PTR:
-                                               // do nothing
-                                               break;
-               #elif __ppc64__
-                                       case PPC_RELOC_PB_LA_PTR:
-                                               // needed for compatibility with ppc64 binaries built with the first ld64
-                                               // which used PPC_RELOC_PB_LA_PTR relocs instead of GENERIC_RELOC_VANILLA for lazy pointers
-                                               *locationToFix += slide;
-                                               break;
-               #elif __i386__
-                                       case GENERIC_RELOC_PB_LA_PTR:
-                                               // do nothing
-                                               break;
-               #endif
-                                       default:
-                                               throw "unknown local scattered relocation type";
-                               }
-                       }
-                       else {
-                               throw "bad local scattered relocation length";
-                       }
-               }
-       #endif // x86_64
-       }
-       
+
+       // do actual rebasing
+       this->rebase(context);
+                       
 #if TEXT_RELOC_SUPPORT
        // if there were __TEXT fixups, restore write protection
-       if ( fTextSegmentWithFixups != NULL ) {
-               fTextSegmentWithFixups->setPermissions(context,this);
-               sys_icache_invalidate((void*)fTextSegmentWithFixups->getActualLoadAddress(this), fTextSegmentWithFixups->getSize());
-       }
+       if ( fTextSegmentRebases ) 
+               this->makeTextSegmentWritable(context, false);
+       
 #endif 
-       // update stats
-       fgTotalRebaseFixups += fDynamicInfo->nlocrel;
 }
 
-
-const struct macho_nlist* ImageLoaderMachO::binarySearchWithToc(const char* key, const char stringPool[], const struct macho_nlist symbols[], 
-                                                                                               const struct dylib_table_of_contents toc[], uint32_t symbolCount, uint32_t hintIndex) const
+#if TEXT_RELOC_SUPPORT
+void ImageLoaderMachO::makeTextSegmentWritable(const LinkContext& context, bool writeable)
 {
-       int32_t high = symbolCount-1;
-       int32_t mid = hintIndex;
-       
-       // handle out of range hint
-       if ( mid >= (int32_t)symbolCount ) {
-               mid = symbolCount/2;
-               ++ImageLoaderMachO::fgUnhintedBinaryTreeSearchs;
-       }
-       else {
-               ++ImageLoaderMachO::fgHintedBinaryTreeSearchs;
-       }
-       ++fgTotalBindImageSearches;     
-
-       //dyld::log("dyld: binarySearchWithToc for %s in %s\n", key, this->getShortName());
-
-       for (int32_t low = 0; low <= high; mid = (low+high)/2) {
-               const uint32_t index = toc[mid].symbol_index;
-               const struct macho_nlist* pivot = &symbols[index];
-               const char* pivotStr = &stringPool[pivot->n_un.n_strx];
-#if LINKEDIT_USAGE_DEBUG
-               noteAccessedLinkEditAddress(&toc[mid]);
-               noteAccessedLinkEditAddress(pivot);
-               noteAccessedLinkEditAddress(pivotStr);
-#endif
-               int cmp = astrcmp(key, pivotStr);
-               if ( cmp == 0 )
-                       return pivot;
-               if ( cmp > 0 ) {
-                       // key > pivot 
-                       low = mid + 1;
-               }
-               else {
-                       // key < pivot 
-                       high = mid - 1;
+       int textSegmentIndex = 0;
+       for(unsigned int i=0; i < fSegmentsCount; ++i) {
+               if ( strcmp(segName(i), "__TEXT") == 0 ) {
+                       textSegmentIndex = i;
+                       break;
                }
        }
-       return NULL;
-}
 
-const struct macho_nlist* ImageLoaderMachO::binarySearch(const char* key, const char stringPool[], const struct macho_nlist symbols[], uint32_t symbolCount) const
-{
-       // update stats
-       ++fgTotalBindImageSearches;     
-       ++ImageLoaderMachO::fgUnhintedBinaryTreeSearchs;
-       
-       //dyld::log("dyld: binarySearch for %s in %s, stringpool=%p, symbols=%p, symbolCount=%u\n", 
-       //                              key, this->getShortName(), stringPool, symbols, symbolCount);
-
-       const struct macho_nlist* base = symbols;
-       for (uint32_t n = symbolCount; n > 0; n /= 2) {
-               const struct macho_nlist* pivot = &base[n/2];
-               const char* pivotStr = &stringPool[pivot->n_un.n_strx];
-#if LINKEDIT_USAGE_DEBUG
-               noteAccessedLinkEditAddress(pivot);
-               noteAccessedLinkEditAddress(pivotStr);
-#endif
-               int cmp = astrcmp(key, pivotStr);
-               if ( cmp == 0 )
-                       return pivot;
-               if ( cmp > 0 ) {
-                       // key > pivot 
-                       // move base to symbol after pivot
-                       base = &pivot[1];
-                       --n; 
-               }
-               else {
-                       // key < pivot 
-                       // keep same base
-               }
+       if ( writeable ) {
+               segMakeWritable(textSegmentIndex, context);
+       }
+       else {
+               segProtect(textSegmentIndex, context);
+               sys_icache_invalidate((void*)segActualLoadAddress(textSegmentIndex), segSize(textSegmentIndex));
        }
-       return NULL;
 }
+#endif
 
-const ImageLoader::Symbol* ImageLoaderMachO::findExportedSymbol(const char* name, const void* hint, bool searchReExports, const ImageLoader** foundIn) const
+const ImageLoader::Symbol* ImageLoaderMachO::findExportedSymbol(const char* name, bool searchReExports, const ImageLoader** foundIn) const
 {
-       const struct macho_nlist* sym = NULL;
-       const struct twolevel_hint* theHint = (struct twolevel_hint*)hint;
-       if ( fDynamicInfo->tocoff == 0 )
-               sym = binarySearch(name, fStrings, &fSymbolTable[fDynamicInfo->iextdefsym], fDynamicInfo->nextdefsym);
-       else {
-               uint32_t start = fDynamicInfo->nextdefsym;
-               if ( theHint != NULL )
-                        start = theHint->itoc;
-               if ( (theHint == NULL) || (theHint->isub_image == 0) ) {
-                       sym = binarySearchWithToc(name, fStrings, fSymbolTable, (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff], 
-                                                                               fDynamicInfo->ntoc, start);
-               }
-       }
-       if ( sym != NULL ) {
-               if ( foundIn != NULL )
-                       *foundIn = (ImageLoader*)this;          
-                       
-               return (const Symbol*)sym;
-       }
+       // look in this image first
+       const ImageLoader::Symbol* result = this->findExportedSymbol(name, foundIn);
+       if ( result != NULL )
+               return result;
        
        if ( searchReExports ) {
-               // hint might tell us to try a particular subimage
-               if ( (theHint != NULL) && (theHint->isub_image > 0) && (theHint->isub_image <= fLibrariesCount) ) {
-                       // isub_image is an index into a list that is sorted non-rexported images first
-                       uint32_t index = 0;
-                       ImageLoader* target = NULL;
-                       // pass one, only look at sub-frameworks
-                       for (uint32_t i=0; i < fLibrariesCount; ++i) {
-                               DependentLibrary& libInfo =  fLibraries[i];
-                               if ( libInfo.isSubFramework && (libInfo.image != NULL)) {
-                                       if ( ++index == theHint->isub_image ) {
-                                               target = libInfo.image;
-                                               break;
-                                       }
-                               }
-                       }
-                       if (target != NULL) {
-                               // pass two, only look at non-sub-framework-reexports
-                               for (uint32_t i=0; i < fLibrariesCount; ++i) {
-                                       DependentLibrary& libInfo =  fLibraries[i];
-                                       if ( libInfo.isReExported && !libInfo.isSubFramework && (libInfo.image != NULL) ) {
-                                               if ( ++index == theHint->isub_image ) {
-                                                       target = libInfo.image;
-                                                       break;
-                                               }
-                                       }
+               for(unsigned int i=0; i < libraryCount(); ++i){
+                       if ( libReExported(i) ) {
+                               ImageLoader* image = libImage(i);
+                               if ( image != NULL ) {
+                                       const Symbol* result = image->findExportedSymbol(name, searchReExports, foundIn);
+                                       if ( result != NULL )
+                                               return result;
                                }
                        }
-                       if (target != NULL) {
-                               const Symbol* result = target->findExportedSymbol(name, NULL, searchReExports, foundIn);
-                               if ( result != NULL )
-                                       return result;
-                       }
-               }
-               
-               // hint failed, try all sub images
-               // pass one, only look at sub-frameworks
-               for(unsigned int i=0; i < fLibrariesCount; ++i){
-                       DependentLibrary& libInfo =  fLibraries[i];
-                       if ( (libInfo.image != NULL) && libInfo.isSubFramework ) {
-                               const Symbol* result = libInfo.image->findExportedSymbol(name, NULL, searchReExports, foundIn);
-                               if ( result != NULL )
-                                       return result;
-                       }
-               }
-               // pass two, only look at non-sub-framework-reexports
-               for(unsigned int i=0; i < fLibrariesCount; ++i){
-                       DependentLibrary& libInfo =  fLibraries[i];
-                       if ( (libInfo.image != NULL) && libInfo.isReExported && !libInfo.isSubFramework ) {
-                               const Symbol* result = libInfo.image->findExportedSymbol(name, NULL, searchReExports, foundIn);
-                               if ( result != NULL )
-                                       return result;
-                       }
                }
        }
        
-       // last change: the hint is wrong (non-zero but actually in this image)
-       if ( (theHint != NULL) && (theHint->isub_image != 0) ) {
-               sym = binarySearchWithToc(name, fStrings, fSymbolTable, (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff], 
-                                                                               fDynamicInfo->ntoc, fDynamicInfo->nextdefsym);
-               if ( sym != NULL ) {
-                       if ( foundIn != NULL ) 
-                               *foundIn = (ImageLoader*)this;
-                       return (const Symbol*)sym;
-               }
-       }
-
 
        return NULL;
 }
 
 
 
-
 uintptr_t ImageLoaderMachO::getExportedSymbolAddress(const Symbol* sym, const LinkContext& context, const ImageLoader* requestor) const
 {
-       return this->getSymbolAddress((const struct macho_nlist*)sym, requestor, context);
+       return this->getSymbolAddress(sym, requestor, context);
 }
 
-uintptr_t ImageLoaderMachO::getSymbolAddress(const struct macho_nlist* sym, const ImageLoader* requestor, const LinkContext& context) const
+uintptr_t ImageLoaderMachO::getSymbolAddress(const Symbol* sym, const ImageLoader* requestor, const LinkContext& context) const
 {
-       uintptr_t result = sym->n_value + fSlide;
+       uintptr_t result = exportedSymbolAddress(sym);
        return result;
 }
 
 ImageLoader::DefinitionFlags ImageLoaderMachO::getExportedSymbolInfo(const Symbol* sym) const
 {
-       const struct macho_nlist* nlistSym = (const struct macho_nlist*)sym;
-       if ( (nlistSym->n_desc & N_WEAK_DEF) != 0 )
+       if ( exportedSymbolIsWeakDefintion(sym) )
                return kWeakDefinition;
-       return kNoDefinitionOptions;
+       else
+               return kNoDefinitionOptions;
 }
 
 const char* ImageLoaderMachO::getExportedSymbolName(const Symbol* sym) const
 {
-       const struct macho_nlist* nlistSym = (const struct macho_nlist*)sym;
-       return &fStrings[nlistSym->n_un.n_strx];
+       return exportedSymbolName(sym);
 }
 
 uint32_t ImageLoaderMachO::getExportedSymbolCount() const
 {
-       return fDynamicInfo->nextdefsym;
+       return exportedSymbolCount();
 }
 
 
 const ImageLoader::Symbol* ImageLoaderMachO::getIndexedExportedSymbol(uint32_t index) const
 {
-       if ( index < fDynamicInfo->nextdefsym ) {
-               const struct macho_nlist* sym = &fSymbolTable[fDynamicInfo->iextdefsym + index];
-               return (const ImageLoader::Symbol*)sym;
-       }
-       return NULL;
+       return exportedSymbolIndexed(index);
 }
 
 
 uint32_t ImageLoaderMachO::getImportedSymbolCount() const
 {
-       return fDynamicInfo->nundefsym;
+       return importedSymbolCount();
 }
 
 
 const ImageLoader::Symbol* ImageLoaderMachO::getIndexedImportedSymbol(uint32_t index) const
 {
-       if ( index < fDynamicInfo->nundefsym ) {
-               const struct macho_nlist* sym = &fSymbolTable[fDynamicInfo->iundefsym + index];
-               return (const ImageLoader::Symbol*)sym;
-       }
-       return NULL;
+       return importedSymbolIndexed(index);
 }
 
 
-ImageLoader::ReferenceFlags ImageLoaderMachO::geImportedSymbolInfo(const ImageLoader::Symbol* sym) const
+ImageLoader::ReferenceFlags ImageLoaderMachO::getImportedSymbolInfo(const ImageLoader::Symbol* sym) const
 {
-       const struct macho_nlist* nlistSym = (const struct macho_nlist*)sym;
        ImageLoader::ReferenceFlags flags = kNoReferenceOptions;
-       if ( ((nlistSym->n_type & N_TYPE) == N_UNDF) && (nlistSym->n_value != 0) )
-               flags |= ImageLoader::kTentativeDefinition;
-       if ( (nlistSym->n_desc & N_WEAK_REF) != 0 )
-               flags |= ImageLoader::kWeakReference;
        return flags;
 }
 
 
 const char* ImageLoaderMachO::getImportedSymbolName(const ImageLoader::Symbol* sym) const
 {
-       const struct macho_nlist* nlistSym = (const struct macho_nlist*)sym;
-       return &fStrings[nlistSym->n_un.n_strx];
+       return importedSymbolName(sym);
 }
 
 
@@ -1965,638 +1089,151 @@ bool ImageLoaderMachO::getSectionContent(const char* segmentName, const char* se
                }
                cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
        }
+       *start = NULL;
+       *length = 0;
        return false;
 }
 
-
-bool ImageLoaderMachO::findSection(const void* imageInterior, const char** segmentName, const char** sectionName, size_t* sectionOffset)
-{
-       const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
-       const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
-       const struct load_command* cmd = cmds;
-       const uintptr_t unslidInteriorAddress = (uintptr_t)imageInterior - this->getSlide();
-       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;
-                                       if ( (unslidInteriorAddress >= seg->vmaddr) && (unslidInteriorAddress < (seg->vmaddr+seg->vmsize)) ) {
-                                               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->addr <= unslidInteriorAddress) && (unslidInteriorAddress < (sect->addr+sect->size))) {
-                                                               if ( segmentName != NULL )
-                                                                       *segmentName = sect->segname;
-                                                               if ( sectionName != NULL )
-                                                                       *sectionName = sect->sectname;
-                                                               if ( sectionOffset != NULL )
-                                                                       *sectionOffset = unslidInteriorAddress - sect->addr;
-                                                               return true;
-                                                       }
-                                               }
-                                       }
-                               }
-                               break;
-               }
-               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
-       }
-       return false;
-}
-
-
-bool ImageLoaderMachO::symbolRequiresCoalescing(const struct macho_nlist* symbol)
-{
-       // if a define and weak ==> coalesced 
-       if ( ((symbol->n_type & N_TYPE) == N_SECT) && ((symbol->n_desc & N_WEAK_DEF) != 0) ) 
-               return true;
-       // if an undefine and not referencing a weak symbol ==> coalesced
-       if ( ((symbol->n_type & N_TYPE) != N_SECT) && ((symbol->n_desc & N_REF_TO_WEAK) != 0) )
-               return true;
-       
-       // regular symbol
-       return false;
-}
-
-
-static void __attribute__((noreturn)) throwSymbolNotFound(const char* symbol, const char* referencedFrom, const char* expectedIn)
-{
-       dyld::throwf("Symbol not found: %s\n  Referenced from: %s\n  Expected in: %s\n", symbol, referencedFrom, expectedIn); 
-}
-
-uintptr_t ImageLoaderMachO::resolveUndefined(const LinkContext& context, const struct macho_nlist* undefinedSymbol, bool twoLevel, const ImageLoader** foundIn)
-{
-       ++fgTotalBindSymbolsResolved;
-       const char* symbolName = &fStrings[undefinedSymbol->n_un.n_strx];
-
-#if LINKEDIT_USAGE_DEBUG
-       noteAccessedLinkEditAddress(undefinedSymbol);
-       noteAccessedLinkEditAddress(symbolName);
-#endif
-       if ( context.bindFlat || !twoLevel ) {
-               // 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, this, context);
-                       *foundIn = this;
-                       return addr;
-               }
-               const Symbol* sym;
-               if ( context.flatExportFinder(symbolName, &sym, foundIn) ) {
-                       if ( (*foundIn != this) && !(*foundIn)->neverUnload() )
-                                       this->addDynamicReference(*foundIn);
-                       return (*foundIn)->getExportedSymbolAddress(sym, context, this);
-               }
-               // 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->findExportedSymbol(symbolName, NULL, false, foundIn);
-                       if ( sym != NULL )
-                               return (*foundIn)->getExportedSymbolAddress(sym, context, this);
-               }
-               if ( (undefinedSymbol->n_desc & N_WEAK_REF) != 0 ) {
-                       // definition can't be found anywhere
-                       // if reference is weak_import, then it is ok, just return 0
-                       return 0;
-               }
-               throwSymbolNotFound(symbolName, this->getPath(), "flat namespace");
-       }
-       else {
-               // symbol requires searching images with coalesced symbols (not done during prebinding)
-               if ( !context.prebinding && this->needsCoalescing() && symbolRequiresCoalescing(undefinedSymbol) ) {
-                       const Symbol* sym;
-                       if ( context.coalescedExportFinder(symbolName, &sym, foundIn) ) {
-                               if ( (*foundIn != this) && !(*foundIn)->neverUnload() )
-                                       this->addDynamicReference(*foundIn);
-                               return (*foundIn)->getExportedSymbolAddress(sym, context, this);
-                       }
-                       //throwSymbolNotFound(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, this, context);
-                       *foundIn = this;
-                       return addr;
-               }
-
-               // two level lookup
-               void* hint = NULL;
-               ImageLoader* target = NULL;
-               uint8_t ord = GET_LIBRARY_ORDINAL(undefinedSymbol->n_desc);
-               if ( ord == EXECUTABLE_ORDINAL ) {
-                       target = context.mainExecutable;
-               }
-               else if ( ord == SELF_LIBRARY_ORDINAL ) {
-                       target = this;
-               }
-               else if ( ord == DYNAMIC_LOOKUP_ORDINAL ) {
-                       // rnielsen: HACKHACK
-                       // flat lookup
-                       const Symbol* sym;
-                       if ( context.flatExportFinder(symbolName, &sym, foundIn) )
-                               return (*foundIn)->getExportedSymbolAddress(sym, context, this);
-                       // no image has exports this symbol
-                       // either report error or hope ZeroLink can just-in-time load an image
-                       context.undefinedHandler(symbolName);
-                       // try looking again
-                       if ( context.flatExportFinder(symbolName, &sym, foundIn) )
-                               return (*foundIn)->getExportedSymbolAddress(sym, context, this);
-                       
-                       throwSymbolNotFound(symbolName, this->getPath(), "dynamic lookup");
-               }
-               else if ( ord <= fLibrariesCount ) {
-                       DependentLibrary& libInfo = fLibraries[ord-1];
-                       target = libInfo.image;
-                       if ( (target == NULL) && (((undefinedSymbol->n_desc & N_WEAK_REF) != 0) || !libInfo.required) ) {
-                               // if target library not loaded and reference is weak or library is weak return 0
-                               return 0;
-                       }
-               }
-               else {
-                       dyld::throwf("bad mach-o binary, library ordinal (%u) too big (max %u) for symbol %s in %s",
-                               ord, fLibrariesCount, symbolName, this->getPath());
-               }
-               
-               if ( target == NULL ) {
-                       //dyld::log("resolveUndefined(%s) in %s\n", symbolName, this->getPath());
-                       throw "symbol not found";
-               }
-               
-               // interpret hint
-               if ( fTwoLevelHints != NULL ) {
-                       uint32_t symIndex = undefinedSymbol - fSymbolTable;
-                       int32_t undefinedIndex = symIndex - fDynamicInfo->iundefsym;
-                       if ( (undefinedIndex >= 0) && ((uint32_t)undefinedIndex < fDynamicInfo->nundefsym) ) {
-                               const struct twolevel_hint* hints = (struct twolevel_hint*)(&fLinkEditBase[fTwoLevelHints->offset]);
-                               const struct twolevel_hint* theHint = &hints[undefinedIndex];
-                               hint = (void*)theHint;
-                       }
-               }
-               
-               const Symbol* sym = target->findExportedSymbol(symbolName, hint, true, foundIn);
-               if ( sym!= NULL ) {
-                       return (*foundIn)->getExportedSymbolAddress(sym, context, this);
-               }
-               else if ( (undefinedSymbol->n_type & N_PEXT) != 0 ) {
-                       // don't know why the static linker did not eliminate the internal reference to a private extern definition
-                       *foundIn = this;
-                       return this->getSymbolAddress(undefinedSymbol, this, context);
-               }
-               else if ( (undefinedSymbol->n_desc & N_WEAK_REF) != 0 ) {
-                       // if definition not found and reference is weak return 0
-                       return 0;
-               }
-               
-               // nowhere to be found
-               throwSymbolNotFound(symbolName, this->getPath(), target->getPath());
-       }
-}
-
-// returns if 'addr' is within the address range of section 'sectionIndex'
-// fSlide is not used.  'addr' is assumed to be a prebound address in this image 
-bool ImageLoaderMachO::isAddrInSection(uintptr_t addr, uint8_t sectionIndex)
-{
-       uint8_t currentSectionIndex = 1;
-       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 (unsigned long i = 0; i < cmd_count; ++i) {
-               if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
-                       const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
-                       if ( (currentSectionIndex <= sectionIndex) && (sectionIndex < currentSectionIndex+seg->nsects) ) {
-                               // 'sectionIndex' is in this segment, get section info
-                               const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
-                               const struct macho_section* const section = &sectionsStart[sectionIndex-currentSectionIndex];
-                               return ( (section->addr <= addr) && (addr < section->addr+section->size) );
-                       }
-                       else {
-                               // 'sectionIndex' not in this segment, skip to next segment
-                               currentSectionIndex += seg->nsects;
-                       }
-               }
-               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
-       }
-       
-       return false;
-}
-
-void ImageLoaderMachO::doBindExternalRelocations(const LinkContext& context, bool onlyCoalescedSymbols)
-{
-       const uintptr_t relocBase = this->getRelocBase();
-       const bool twoLevel = this->usesTwoLevelNameSpace();
-       const bool prebound = this->isPrebindable();
-       
-#if TEXT_RELOC_SUPPORT
-       // if there are __TEXT fixups, temporarily make __TEXT writable
-       if ( fTextSegmentWithFixups != NULL ) 
-               fTextSegmentWithFixups->tempWritable(context, this);
-#endif
-       // cache last lookup
-       const struct macho_nlist*       lastUndefinedSymbol = NULL;
-       uintptr_t                                       symbolAddr = 0;
-       const ImageLoader*                      image = NULL;
-       
-       // loop through all external relocation records and bind each
-       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:
-                                       {
-                                               const struct macho_nlist* undefinedSymbol = &fSymbolTable[reloc->r_symbolnum];
-                                               // if only processing coalesced symbols and this one does not require coalesceing, skip to next
-                                               if ( onlyCoalescedSymbols && !symbolRequiresCoalescing(undefinedSymbol) )
-                                                       continue;
-                                               uintptr_t* location = ((uintptr_t*)(reloc->r_address + relocBase));
-                                               uintptr_t value = *location;
-                                               bool symbolAddrCached = true;
-                                       #if __i386__
-                                               if ( reloc->r_pcrel ) {
-                                                       value += (uintptr_t)location + 4 - fSlide;
-                                               }
-                                       #endif
-                                               if ( prebound ) {
-                                                       // we are doing relocations, so prebinding was not usable
-                                                       // in a prebound executable, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound
-                                                       // so, subtracting that gives the initial displacement which we need to add to the newly found symbol address
-                                                       // if mach-o relocation structs had an "addend" field this complication would not be necessary.
-                                                       if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_WEAK_DEF) != 0) ) {
-                                                               // weak symbols need special casing, since *location may have been prebound to a definition in another image.
-                                                               // If *location is currently prebound to somewhere in the same section as the weak definition, we assume 
-                                                               // that we can subtract off the weak symbol address to get the addend.
-                                                               // If prebound elsewhere, we've lost the addend and have to assume it is zero.
-                                                               // The prebinding to elsewhere only happens with 10.4+ update_prebinding which only operates on a small set of Apple dylibs
-                                                               if ( (value == undefinedSymbol->n_value) || this->isAddrInSection(value, undefinedSymbol->n_sect) )
-                                                                       value -= undefinedSymbol->n_value;
-                                                               else
-                                                                       value = 0;
-                                                       } 
-                                                       else {
-                                                               // is undefined or non-weak symbol, so do subtraction to get addend
-                                                               value -= undefinedSymbol->n_value;
-                                                       }
-                                               }
-                                               // if undefinedSymbol is same as last time, then symbolAddr and image will resolve to the same too
-                                               if ( undefinedSymbol != lastUndefinedSymbol ) {
-                                                       symbolAddr = this->resolveUndefined(context, undefinedSymbol, twoLevel, &image);
-                                                       lastUndefinedSymbol = undefinedSymbol;
-                                                       symbolAddrCached = false;
-                                               }
-                                               if ( context.verboseBind ) {
-                                                       const char *path = NULL;
-                                                       if ( image != NULL ) {
-                                                               path = image->getShortName();
-                                                       }
-                                                       const char* cachedString = "(cached)";
-                                                       if ( !symbolAddrCached ) 
-                                                               cachedString = "";
-                                                       if ( value == 0 ) {
-                                                               dyld::log("dyld: bind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX%s\n",
-                                                                               this->getShortName(), (uintptr_t)location,
-                                                                               path, &fStrings[undefinedSymbol->n_un.n_strx], (uintptr_t)location, symbolAddr, cachedString);
-                                                       }
-                                                       else {
-                                                               dyld::log("dyld: bind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX%s + %ld\n",
-                                                                               this->getShortName(), (uintptr_t)location,
-                                                                               path, &fStrings[undefinedSymbol->n_un.n_strx], (uintptr_t)location, symbolAddr, cachedString, value);
-                                                       }
-                                               }
-                                               value += symbolAddr;
-                                       #if __i386__
-                                               if ( reloc->r_pcrel ) {
-                                                       *location = value - ((uintptr_t)location + 4);
-                                               }
-                                               else {
-                                                       // don't dirty page if prebound value was correct
-                                                       if ( !prebound || (*location != value) )
-                                                               *location = value; 
-                                               }
-                                       #else
-                                               // don't dirty page if prebound value was correct
-                                               if ( !prebound || (*location != value) )
-                                                       *location = value; 
-                                       #endif
-                                               // update stats
-                                               ++fgTotalBindFixups;
-                                       }
-                                       break;
-                               default:
-                                       throw "unknown external relocation type";
-                       }
-               }
-               else {
-                       throw "bad external relocation length";
-               }
-       }
-       
-#if TEXT_RELOC_SUPPORT
-       // if there were __TEXT fixups, restore write protection
-       if ( fTextSegmentWithFixups != NULL ) {
-               fTextSegmentWithFixups->setPermissions(context, this);
-               sys_icache_invalidate((void*)fTextSegmentWithFixups->getActualLoadAddress(this), fTextSegmentWithFixups->getSize());
-       }
-#endif
-}
-
-const mach_header* ImageLoaderMachO::machHeader() const
-{
-       return (mach_header*)fMachOData;
-}
-
-uintptr_t ImageLoaderMachO::getSlide() const
-{
-       return fSlide;
-}
-
-// hmm. maybe this should be up in ImageLoader??
-const void* ImageLoaderMachO::getEnd() const
-{
-       uintptr_t lastAddress = 0;
-       for (ImageLoader::SegmentIterator it = this->beginSegments(); it != this->endSegments(); ++it ) {
-               Segment* seg = *it;
-               uintptr_t segEnd = seg->getActualLoadAddress(this) + seg->getSize();
-               if ( segEnd > lastAddress )
-                       lastAddress = segEnd;
-       }
-       return (const void*)lastAddress;
-}
-
-uintptr_t ImageLoaderMachO::bindIndirectSymbol(uintptr_t* ptrToBind, const struct macho_section* sect, const char* symbolName, uintptr_t targetAddr, const ImageLoader* targetImage, const LinkContext& context)
+void ImageLoaderMachO::getUnwindInfo(dyld_unwind_sections* info)
 {
-       if ( context.verboseBind ) {
-               const char* path = NULL;
-               if ( targetImage != NULL )
-                       path = targetImage->getShortName();
-               dyld::log("dyld: bind: %s:%s$%s = %s:%s, *0x%08lx = 0x%08lx\n",
-                               this->getShortName(), symbolName, (((sect->flags & SECTION_TYPE)==S_NON_LAZY_SYMBOL_POINTERS) ? "non_lazy_ptr" : "lazy_ptr"),
-                               path, symbolName, (uintptr_t)ptrToBind, targetAddr);
+       info->mh = this->machHeader();
+       info->dwarf_section = 0;
+       info->dwarf_section_length = 0;
+       info->compact_unwind_section = 0;
+       info->compact_unwind_section_length = 0;
+       if ( fEHFrameSectionOffset != 0 ) {
+               const macho_section* sect = (macho_section*)&fMachOData[fEHFrameSectionOffset];
+               info->dwarf_section = (void*)(sect->addr + fSlide);
+               info->dwarf_section_length = sect->size;
        }
-       if ( context.bindingHandler != NULL ) {
-               const char* path = NULL;
-               if ( targetImage != NULL )
-                       path = targetImage->getShortName();
-               targetAddr = (uintptr_t)context.bindingHandler(path, symbolName, (void *)targetAddr);
-       }
-#if __i386__
-       // i386 has special self-modifying stubs that change from "CALL rel32" to "JMP rel32"
-       if ( ((sect->flags & SECTION_TYPE) == S_SYMBOL_STUBS) && ((sect->flags & S_ATTR_SELF_MODIFYING_CODE) != 0) && (sect->reserved2 == 5) ) {
-               uint32_t rel32 = targetAddr - (((uint32_t)ptrToBind)+5);
-               // re-write instruction in a thread-safe manner
-               // use 8-byte compare-and-swap to alter 5-byte jump table entries
-               // loop is required in case the extra three bytes that cover the next entry are altered by another thread
-               bool done = false;
-               while ( !done ) {
-                       volatile int64_t* jumpPtr = (int64_t*)ptrToBind;
-                       int pad = 0;
-                       // By default the three extra bytes swapped follow the 5-byte JMP.
-                       // But, if the 5-byte jump is up against the end of the __IMPORT segment
-                       // We don't want to access bytes off the end of the segment, so we shift
-                       // the extra bytes to precede the 5-byte JMP.
-                       if ( (((uint32_t)ptrToBind + 8) & 0x00000FFC) == 0x00000000 ) {
-                               jumpPtr = (int64_t*)((uint32_t)ptrToBind - 3);
-                               pad = 3;
-                       }
-                       int64_t oldEntry = *jumpPtr;
-                       union {
-                               int64_t int64;
-                               uint8_t bytes[8];
-                       } newEntry;
-                       newEntry.int64 = oldEntry;
-                       newEntry.bytes[pad+0] = 0xE9; // JMP rel32
-                       newEntry.bytes[pad+1] = rel32 & 0xFF;
-                       newEntry.bytes[pad+2] = (rel32 >> 8) & 0xFF;
-                       newEntry.bytes[pad+3] = (rel32 >> 16) & 0xFF;
-                       newEntry.bytes[pad+4] = (rel32 >> 24) & 0xFF;
-                       done = OSAtomicCompareAndSwap64Barrier(oldEntry, newEntry.int64, (int64_t*)jumpPtr);
-               }
+       if ( fUnwindInfoSectionOffset != 0 ) {
+               const macho_section* sect = (macho_section*)&fMachOData[fUnwindInfoSectionOffset];
+               info->compact_unwind_section = (void*)(sect->addr + fSlide);
+               info->compact_unwind_section_length = sect->size;
        }
-       else
-#endif
-       *ptrToBind = targetAddr;
-       return targetAddr;
 }
 
 
-uintptr_t ImageLoaderMachO::doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context)
+bool ImageLoaderMachO::findSection(const void* imageInterior, const char** segmentName, const char** sectionName, size_t* sectionOffset)
 {
-       // scan for all non-lazy-pointer sections
-       const bool twoLevel = this->usesTwoLevelNameSpace();
        const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
        const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
        const struct load_command* cmd = cmds;
-       const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff];
+       const uintptr_t unslidInteriorAddress = (uintptr_t)imageInterior - this->getSlide();
        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;
-                                               uint32_t symbolIndex = INDIRECT_SYMBOL_LOCAL;
-                                               if ( type == S_LAZY_SYMBOL_POINTERS ) {
-                                                       const uint32_t pointerCount = sect->size / sizeof(uintptr_t);
-                                                       uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + fSlide);
-                                                       if ( (lazyPointer >= symbolPointers) && (lazyPointer < &symbolPointers[pointerCount]) ) {
-                                                               const uint32_t indirectTableOffset = sect->reserved1;
-                                                               const uint32_t lazyIndex = lazyPointer - symbolPointers;
-                                                               symbolIndex = indirectTable[indirectTableOffset + lazyIndex];
-                                                       }
-                                               }
-                                       #if __i386__
-                                               else if ( (type == S_SYMBOL_STUBS) && (sect->flags & S_ATTR_SELF_MODIFYING_CODE) && (sect->reserved2 == 5) ) {
-                                                       // 5 bytes stubs on i386 are new "fast stubs"
-                                                       uint8_t* const jmpTableBase = (uint8_t*)(sect->addr + fSlide);
-                                                       uint8_t* const jmpTableEnd = jmpTableBase + sect->size;
-                                                       // initial CALL instruction in jump table leaves pointer to next entry, so back up
-                                                       uint8_t* const jmpTableEntryToPatch = ((uint8_t*)lazyPointer) - 5;  
-                                                       lazyPointer = (uintptr_t*)jmpTableEntryToPatch; 
-                                                       if ( (jmpTableEntryToPatch >= jmpTableBase) && (jmpTableEntryToPatch < jmpTableEnd) ) {
-                                                               const uint32_t indirectTableOffset = sect->reserved1;
-                                                               const uint32_t entryIndex = (jmpTableEntryToPatch - jmpTableBase)/5;
-                                                               symbolIndex = indirectTable[indirectTableOffset + entryIndex];
+                                       if ( (unslidInteriorAddress >= seg->vmaddr) && (unslidInteriorAddress < (seg->vmaddr+seg->vmsize)) ) {
+                                               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->addr <= unslidInteriorAddress) && (unslidInteriorAddress < (sect->addr+sect->size))) {
+                                                               if ( segmentName != NULL )
+                                                                       *segmentName = sect->segname;
+                                                               if ( sectionName != NULL )
+                                                                       *sectionName = sect->sectname;
+                                                               if ( sectionOffset != NULL )
+                                                                       *sectionOffset = unslidInteriorAddress - sect->addr;
+                                                               return true;
                                                        }
                                                }
-                                       #endif
-                                               if ( symbolIndex != INDIRECT_SYMBOL_ABS && symbolIndex != INDIRECT_SYMBOL_LOCAL ) {
-                                                       const char* symbolName = &fStrings[fSymbolTable[symbolIndex].n_un.n_strx];
-                                                       const ImageLoader* image = NULL;
-                                                       uintptr_t symbolAddr = this->resolveUndefined(context, &fSymbolTable[symbolIndex],  twoLevel, &image);
-                                       #if __i386__
-                                                       this->makeImportSegmentWritable(context);
-                                       #endif
-                                                       symbolAddr = this->bindIndirectSymbol(lazyPointer, sect, symbolName, symbolAddr, image,  context);
-                                                       ++fgTotalLazyBindFixups;
-                                       #if __i386__
-                                                       this->makeImportSegmentReadOnly(context);
-                                       #endif
-                                                       return symbolAddr;
-                                               }
                                        }
                                }
                                break;
                }
                cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
        }
-       dyld::throwf("lazy pointer not found at address %p in image %s", lazyPointer, this->getPath());
+       return false;
 }
 
 
-#if __i386__
-//
-// For security the __IMPORT segments in the shared cache are normally not writable.
-// Any image can also be linked with -read_only_stubs to make their __IMPORT segments normally not writable.
-// For these images, dyld must change the page protection before updating them.
-// The spin lock is required because lazy symbol binding is done without taking the global dyld lock.
-// It keeps only one __IMPORT segment writable at a time.
-// Pre-main(), the shared cache __IMPORT segments are always writable, so we don't need to change the protection.
-//
-void ImageLoaderMachO::makeImportSegmentWritable(const LinkContext& context)
-{
-       if ( fReadOnlyImportSegment != NULL ) {
-               if ( fInSharedCache ) {
-                       if ( context.startedInitializingMainExecutable ) {
-                               _spin_lock(&fgReadOnlyImportSpinLock);
-                               context.makeSharedCacheImportSegmentsWritable(true);
-                       }
-               }
-               else {
-                       _spin_lock(&fgReadOnlyImportSpinLock);
-                       fReadOnlyImportSegment->tempWritable(context, this);
-               }
-       }
+void __attribute__((noreturn)) ImageLoaderMachO::throwSymbolNotFound(const char* symbol, const char* referencedFrom, const char* expectedIn)
+{
+       dyld::throwf("Symbol not found: %s\n  Referenced from: %s\n  Expected in: %s\n", symbol, referencedFrom, expectedIn); 
 }
 
-void ImageLoaderMachO::makeImportSegmentReadOnly(const LinkContext& context)
+const mach_header* ImageLoaderMachO::machHeader() const
 {
-       if ( fReadOnlyImportSegment != NULL ) {
-               if ( fInSharedCache ) {
-                       if ( context.startedInitializingMainExecutable ) {
-                               context.makeSharedCacheImportSegmentsWritable(false);
-                               _spin_unlock(&fgReadOnlyImportSpinLock);
-                       }
-               }
-               else {
-                       fReadOnlyImportSegment->setPermissions(context, this);
-                       _spin_unlock(&fgReadOnlyImportSpinLock);
+       return (mach_header*)fMachOData;
+}
+
+uintptr_t ImageLoaderMachO::getSlide() const
+{
+       return fSlide;
+}
+
+// hmm. maybe this should be up in ImageLoader??
+const void* ImageLoaderMachO::getEnd() const
+{
+       uintptr_t lastAddress = 0;
+       for(unsigned int i=0; i < fSegmentsCount; ++i) {
+               uintptr_t segEnd = segActualEndAddress(i);
+               if ( strcmp(segName(i), "__UNIXSTACK") != 0 ) {
+                       if ( segEnd > lastAddress )
+                               lastAddress = segEnd;
                }
        }
+       return (const void*)lastAddress;
 }
-#endif
 
-void ImageLoaderMachO::doBindIndirectSymbolPointers(const LinkContext& context, bool bindNonLazys, bool bindLazys, bool onlyCoalescedSymbols)
+
+uintptr_t ImageLoaderMachO::bindLocation(const LinkContext& context, uintptr_t location, uintptr_t value, 
+                                                                               const ImageLoader* targetImage, uint8_t type, const char* symbolName, 
+                                                                               intptr_t addend, const char* msg)
 {
-#if __i386__
-       this->makeImportSegmentWritable(context);
-#endif
-       // scan for all non-lazy-pointer sections 
-       const bool twoLevel = this->usesTwoLevelNameSpace();
-       const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
-       const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
-       const struct load_command* cmd = cmds;
-       const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff];
-       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;
-                                               uint32_t elementSize = sizeof(uintptr_t);
-                                               uint32_t elementCount = sect->size / elementSize;
-                                               if ( type == S_NON_LAZY_SYMBOL_POINTERS ) {
-                                                       if ( ! bindNonLazys )
-                                                               continue;
-                                               }
-                                               else if ( type == S_LAZY_SYMBOL_POINTERS ) {
-                                                       // process each symbol pointer in this section
-                                                       fgTotalPossibleLazyBindFixups += elementCount;
-                                                       if ( ! bindLazys )
-                                                               continue;
-                                               }
-                               #if __i386__
-                                               else if ( (type == S_SYMBOL_STUBS) && (sect->flags & S_ATTR_SELF_MODIFYING_CODE) && (sect->reserved2 == 5) ) {
-                                                       // process each jmp entry in this section
-                                                       elementCount = sect->size / 5;
-                                                       elementSize = 5;
-                                                       fgTotalPossibleLazyBindFixups += elementCount;
-                                                       if ( ! bindLazys )
-                                                               continue;
-                                               }
-                               #endif
-                                               else {
-                                                       continue;
-                                               }
-                                               const uint32_t indirectTableOffset = sect->reserved1;
-                                               uint8_t* ptrToBind = (uint8_t*)(sect->addr + fSlide);
-                                               for (uint32_t j=0; j < elementCount; ++j, ptrToBind += elementSize) {
-                               #if LINKEDIT_USAGE_DEBUG
-                                                       noteAccessedLinkEditAddress(&indirectTable[indirectTableOffset + j]);
-                               #endif
-                                                       uint32_t symbolIndex = indirectTable[indirectTableOffset + j];
-                                                       if ( symbolIndex == INDIRECT_SYMBOL_LOCAL) {
-                                                               *((uintptr_t*)ptrToBind) += this->fSlide;
-                                                       }
-                                                       else if ( symbolIndex == INDIRECT_SYMBOL_ABS) {
-                                                               // do nothing since already has absolute address
-                                                       }
-                                                       else {
-                                                               const struct macho_nlist* sym = &fSymbolTable[symbolIndex];
-                                                               if ( symbolIndex == 0 ) {
-                                                                       // This could be rdar://problem/3534709 
-                                                                       if ( ((const macho_header*)fMachOData)->filetype == MH_EXECUTE ) {
-                                                                               static bool alreadyWarned = false;
-                                                                               if ( (sym->n_type & N_TYPE) != N_UNDF ) {
-                                                                                       // The indirect table parallels the (non)lazy pointer sections.  For
-                                                                                       // instance, to find info about the fifth lazy pointer you look at the
-                                                                                       // fifth entry in the indirect table.  (try otool -Iv on a file).
-                                                                                       // The entry in the indirect table contains an index into the symbol table.
-
-                                                                                       // The bug in ld caused the entry in the indirect table to be zero
-                                                                                       // (instead of a magic value that means a local symbol).  So, if the
-                                                                                       // symbolIndex == 0, we may be encountering the bug, or 0 may be a valid
-                                                                                       // symbol table index. The check I put in place is to see if the zero'th
-                                                                                       // symbol table entry is an import entry (usually it is a local symbol
-                                                                                       // definition).
-                                                                                       if ( context.verboseWarnings && !alreadyWarned ) {
-                                                                                               dyld::log("dyld: malformed executable '%s', skipping indirect symbol to %s\n",
-                                                                                                               this->getPath(), &fStrings[sym->n_un.n_strx]);
-                                                                                               alreadyWarned = true;
-                                                                                       }
-                                                                                       continue;
-                                                                               }
-                                                                       }
-                                                               }
-                                                               const ImageLoader* image = NULL;
-                                                               // if only processing coalesced symbols and this one does not require coalesceing, skip to next
-                                                               if ( onlyCoalescedSymbols && !symbolRequiresCoalescing(sym) )
-                                                                       continue;
-                                                               uintptr_t symbolAddr;
-                                                                       symbolAddr = resolveUndefined(context, sym, twoLevel, &image);
-                                                                       
-                                                               // update pointer
-                                                               symbolAddr = this->bindIndirectSymbol((uintptr_t*)ptrToBind, sect, &fStrings[sym->n_un.n_strx], symbolAddr, image,  context);
-                                                               // update stats
-                                                               ++fgTotalBindFixups;
-                                                       }
-                                               }
-                                       }
-                               }
-                               break;
-               }
-               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+       // log
+       if ( context.verboseBind ) {
+               if ( addend != 0 )
+                       dyld::log("dyld: %sbind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX + %ld\n",
+                                               msg, this->getShortName(), (uintptr_t)location,
+                                               ((targetImage != NULL) ? targetImage->getShortName() : "<weak_import-missing>"),
+                                               symbolName, (uintptr_t)location, value, addend);
+               else
+                       dyld::log("dyld: %sbind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX\n",
+                                               msg, this->getShortName(), (uintptr_t)location,
+                                               ((targetImage != NULL) ? targetImage->getShortName() : "<weak>import-missing>"),
+                                                symbolName, (uintptr_t)location, value);
        }
-#if __i386__
-       this->makeImportSegmentReadOnly(context);
-#endif
+       
+       // do actual update
+       uintptr_t* locationToFix = (uintptr_t*)location;
+       uint32_t* loc32;
+       uintptr_t newValue = value+addend;
+       uint32_t value32;
+       switch (type) {
+               case BIND_TYPE_POINTER:
+                       // test first so we don't needless dirty pages
+                       if ( *locationToFix != newValue )
+                               *locationToFix = newValue;
+                       break;
+               case BIND_TYPE_TEXT_ABSOLUTE32:
+                       loc32 = (uint32_t*)locationToFix;
+                       value32 = (uint32_t)newValue;
+                       if ( *loc32 != value32 )
+                               *loc32 = value32;
+                       break;
+               case BIND_TYPE_TEXT_PCREL32:
+                       loc32 = (uint32_t*)locationToFix;
+                       value32 = (uint32_t)newValue - (((uintptr_t)locationToFix) + 4);
+                       if ( *loc32 != value32 )
+                               *loc32 = value32;
+                       break;
+               default:
+                       dyld::throwf("bad bind type %d", type);
+       }
+       
+       // update statistics
+       ++fgTotalBindFixups;
+       
+       return newValue;
 }
 
+
+
+
+
 #if SUPPORT_OLD_CRT_INITIALIZATION
 // first 16 bytes of "start" in crt1.o
 #if __ppc__
@@ -2616,7 +1253,6 @@ struct DATAdyld {
 // These are defined in dyldStartup.s
 extern "C" void stub_binding_helper();
 extern "C" bool dyld_func_lookup(const char* name, uintptr_t* address);
-extern "C" void fast_stub_binding_helper_interface();
 
 
 void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext& context)
@@ -2672,81 +1308,17 @@ void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext& context)
                                                                }
                                                        }
                                                }
-                                       }
-                               }
-                       }
-                       cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
-               }
-       }
-#if __i386__
-       if ( ! this->usablePrebinding(context) ) {
-               // reset all "fast" stubs
-               this->makeImportSegmentWritable(context);
-               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_SYMBOL_STUBS) && (sect->flags & S_ATTR_SELF_MODIFYING_CODE) && (sect->reserved2 == 5) ) {
-                                                       // reset each jmp entry in this section
-                                                       const uint32_t indirectTableOffset = sect->reserved1;
-                                                       const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff];
-                                                       uint8_t* start = (uint8_t*)(sect->addr + this->fSlide);
-                                                       uint8_t* end = start + sect->size;
-                                                       uintptr_t dyldHandler = (uintptr_t)&fast_stub_binding_helper_interface;
-                                                       uint32_t entryIndex = 0;
-                                                       for (uint8_t* entry = start; entry < end; entry += 5, ++entryIndex) {
-                                                               bool installLazyHandler = true;
-                                                               // jump table entries that cross a (64-byte) cache line boundary have the potential to cause crashes
-                                                               // if the instruction is updated by one thread while being executed by another
-                                                               if ( ((uint32_t)entry & 0xFFFFFFC0) != ((uint32_t)entry+4 & 0xFFFFFFC0) ) {
-                                                                       // need to bind this now to avoid a potential problem if bound lazily
-                                                                       uint32_t symbolIndex = indirectTable[indirectTableOffset + entryIndex];
-                                                                       // the latest linker marks 64-byte crossing stubs with INDIRECT_SYMBOL_ABS so they are not used
-                                                                       if ( symbolIndex != INDIRECT_SYMBOL_ABS ) {
-                                                                               const char* symbolName = &fStrings[fSymbolTable[symbolIndex].n_un.n_strx];
-                                                                               const ImageLoader* image = NULL;
-                                                                               try {
-                                                                                       uintptr_t symbolAddr = this->resolveUndefined(context, &fSymbolTable[symbolIndex], this->usesTwoLevelNameSpace(), &image);
-                                                                                       symbolAddr = this->bindIndirectSymbol((uintptr_t*)entry, sect, symbolName, symbolAddr, image, context);
-                                                                                       ++fgTotalBindFixups;
-                                                                                       uint32_t rel32 = symbolAddr - (((uint32_t)entry)+5);
-                                                                                       entry[0] = 0xE9; // JMP rel32
-                                                                                       entry[1] = rel32 & 0xFF;
-                                                                                       entry[2] = (rel32 >> 8) & 0xFF;
-                                                                                       entry[3] = (rel32 >> 16) & 0xFF;
-                                                                                       entry[4] = (rel32 >> 24) & 0xFF;
-                                                                                       installLazyHandler = false;
-                                                                               } 
-                                                                               catch (const char* msg) {
-                                                                                       // ignore errors when binding symbols early
-                                                                                       // maybe the function is never called, and therefore erroring out now would be a regression
-                                                                               }
-                                                                       }
-                                                               }
-                                                               if ( installLazyHandler ) {
-                                                                       uint32_t rel32 = dyldHandler - (((uint32_t)entry)+5);
-                                                                       entry[0] = 0xE8; // CALL rel32
-                                                                       entry[1] = rel32 & 0xFF;
-                                                                       entry[2] = (rel32 >> 8) & 0xFF;
-                                                                       entry[3] = (rel32 >> 16) & 0xFF;
-                                                                       entry[4] = (rel32 >> 24) & 0xFF;
-                                                               }
-                                                       }
+                                               else if ( (strcmp(sect->sectname, "__program_vars" ) == 0) && (mh->filetype == MH_EXECUTE) ) {
+                                                       // this is a Mac OS X 10.6 or later main executable 
+                                                       struct ProgramVars* pv = (struct ProgramVars*)(sect->addr + fSlide);
+                                                       context.setNewProgramVars(*pv);
                                                }
                                        }
                                }
                        }
                        cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
                }
-               this->makeImportSegmentReadOnly(context);
        }
-#endif
 }
 
                                                                        
@@ -2759,22 +1331,22 @@ void ImageLoaderMachO::lookupProgramVars(const LinkContext& context) const
        vars.mh = (macho_header*)fMachOData;
        
        // lookup _NXArgc
-       sym = this->findExportedSymbol("_NXArgc", NULL, false, NULL);
+       sym = this->findExportedSymbol("_NXArgc", false, NULL);
        if ( sym != NULL )
                vars.NXArgcPtr = (int*)this->getExportedSymbolAddress(sym, context, this);
                
        // lookup _NXArgv
-       sym = this->findExportedSymbol("_NXArgv", NULL, false, NULL);
+       sym = this->findExportedSymbol("_NXArgv", false, NULL);
        if ( sym != NULL )
                vars.NXArgvPtr = (const char***)this->getExportedSymbolAddress(sym, context, this);
                
        // lookup _environ
-       sym = this->findExportedSymbol("_environ", NULL, false, NULL);
+       sym = this->findExportedSymbol("_environ", false, NULL);
        if ( sym != NULL )
                vars.environPtr = (const char***)this->getExportedSymbolAddress(sym, context, this);
                
        // lookup __progname
-       sym = this->findExportedSymbol("___progname", NULL, false, NULL);
+       sym = this->findExportedSymbol("___progname", false, NULL);
        if ( sym != NULL )
                vars.__prognamePtr = (const char**)this->getExportedSymbolAddress(sym, context, this);
                
@@ -2806,50 +1378,6 @@ bool ImageLoaderMachO::usablePrebinding(const LinkContext& context) const
        return false;
 }
 
-void ImageLoaderMachO::doBindJustLazies(const LinkContext& context)
-{
-       // some API called requested that all lazy pointers in this image be force bound
-       this->doBindIndirectSymbolPointers(context, false, true, false);
-}
-
-void ImageLoaderMachO::doBind(const LinkContext& context, bool forceLazysBound)
-{
-       // set dyld entry points in image
-       this->setupLazyPointerHandler(context);
-
-       // 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) ) {
-               // if image has coalesced symbols, then these need to be rebound, unless this is the only image with weak symbols
-               if ( this->needsCoalescing() && (fgCountOfImagesWithWeakExports > 1) ) {
-                       this->doBindExternalRelocations(context, true);
-                       this->doBindIndirectSymbolPointers(context, true, true, true);
-               }
-               else {
-                       ++fgImagesRequiringNoFixups;
-               }
-               
-               // skip binding because prebound and prebinding not disabled
-               return;
-       }
-       
-       // values bound by name are stored two different ways in mach-o:
-       
-       // 1) external relocations are used for data initialized to external symbols
-       this->doBindExternalRelocations(context, false);
-       
-       // 2) "indirect symbols" are used for code references to external symbols
-       // if this image is in the shared cache, there is noway to reset the lazy pointers, so bind them now
-       this->doBindIndirectSymbolPointers(context, true, forceLazysBound || fInSharedCache, false);
-}
-
-void ImageLoaderMachO::doUpdateMappingPermissions(const LinkContext& context)
-{
-#if __i386__
-       if ( (fReadOnlyImportSegment != NULL) && !fInSharedCache )
-               fReadOnlyImportSegment->setPermissions(context, this);
-#endif
-}
 
 void ImageLoaderMachO::doImageInit(const LinkContext& context)
 {
@@ -2857,7 +1385,7 @@ void ImageLoaderMachO::doImageInit(const LinkContext& context)
                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 (unsigned long i = 0; i < cmd_count; ++i) {
+               for (uint32_t i = 0; i < cmd_count; ++i) {
                        switch (cmd->cmd) {
                                case LC_ROUTINES_COMMAND:
                                        Initializer func = (Initializer)(((struct macho_routines_command*)cmd)->init_address + fSlide);
@@ -2877,7 +1405,7 @@ void ImageLoaderMachO::doModInitFunctions(const LinkContext& context)
                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 (unsigned long i = 0; i < cmd_count; ++i) {
+               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));
@@ -2904,6 +1432,8 @@ void ImageLoaderMachO::doModInitFunctions(const LinkContext& context)
 
 
 
+
+
 void ImageLoaderMachO::doGetDOFSections(const LinkContext& context, std::vector<ImageLoader::DOFInfo>& dofs)
 {
        if ( fHasDOFSections ) {
@@ -2954,12 +1484,6 @@ bool ImageLoaderMachO::needsTermination()
        return fHasTerminators;
 }
 
-#if IMAGE_NOTIFY_SUPPORT
-bool ImageLoaderMachO::hasImageNotification()
-{
-       return fHasImageNotifySection;
-}
-#endif
 
 void ImageLoaderMachO::doTermination(const LinkContext& context)
 {
@@ -2967,7 +1491,7 @@ void ImageLoaderMachO::doTermination(const LinkContext& context)
                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 (unsigned long i = 0; i < cmd_count; ++i) {
+               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));
@@ -2980,7 +1504,7 @@ void ImageLoaderMachO::doTermination(const LinkContext& context)
                                                for (uint32_t i=count; i > 0; --i) {
                                                        Terminator func = terms[i-1];
                                                        if ( context.verboseInit )
-                                                               dyld::log("dyld: calling terminaton function %p in %s\n", func, this->getPath());
+                                                               dyld::log("dyld: calling termination function %p in %s\n", func, this->getPath());
                                                        func();
                                                }
                                        }
@@ -2991,169 +1515,203 @@ void ImageLoaderMachO::doTermination(const LinkContext& context)
        }
 }
 
-#if IMAGE_NOTIFY_SUPPORT
-void ImageLoaderMachO::doNotification(enum dyld_image_mode mode, uint32_t infoCount, const struct dyld_image_info info[])
-{
-       if ( fHasImageNotifySection ) {
-               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 (unsigned long i = 0; i < cmd_count; ++i) {
-                       if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
-                               const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
-                               if ( strcmp(seg->segname, "__DATA") == 0 ) {
-                                       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 ( strcmp(sect->sectname, "__image_notify") == 0 ) {
-                                                       dyld_image_notifier* notes = (dyld_image_notifier*)(sect->addr + fSlide);
-                                                       const uint32_t count = sect->size / sizeof(uintptr_t);
-                                                       for (uint32_t i=count; i > 0; --i) {
-                                                               dyld_image_notifier func = notes[i-1];
-                                                               func(mode, infoCount, info);
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-                       cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
-               }
-       }
-}
-#endif
 
 void ImageLoaderMachO::printStatistics(unsigned int imageCount)
 {
        ImageLoader::printStatistics(imageCount);
-       //dyld::log("total hinted binary tree searches:    %d\n", fgHintedBinaryTreeSearchs);
-       //dyld::log("total unhinted binary tree searches:  %d\n", fgUnhintedBinaryTreeSearchs);
-       dyld::log("total images with weak exports:  %d\n", fgCountOfImagesWithWeakExports);
-       
-#if LINKEDIT_USAGE_DEBUG
-       dyld::log("linkedit pages accessed (%lu):\n", sLinkEditPageBuckets.size());
-#endif 
-}
-
-
-ImageLoader::SegmentIterator   ImageLoaderMachO::beginSegments() const
-{
-       return SegmentIterator(fSegmentsArray);
-}
-
-ImageLoader::SegmentIterator   ImageLoaderMachO::endSegments() const
-{
-       return SegmentIterator(&fSegmentsArray[fSegmentsArrayCount]);
-}
-
-SegmentMachO::SegmentMachO(const struct macho_segment_command* cmd)
- : fSegmentLoadCommand(cmd)
-{
-}
-
-SegmentMachO::~SegmentMachO()
-{
-}
-
-void SegmentMachO::adjust(const struct macho_segment_command* cmd)
-{
-       fSegmentLoadCommand = cmd;
-}
-
-void SegmentMachO::unmap(const ImageLoader* image)
-{
-       // update stats
-       --ImageLoader::fgTotalSegmentsMapped;
-       ImageLoader::fgTotalBytesMapped -= fSegmentLoadCommand->vmsize;
-       munmap((void*)(this->getActualLoadAddress(image)), fSegmentLoadCommand->vmsize);
-}
-
-
-const char* SegmentMachO::getName()
-{
-       return fSegmentLoadCommand->segname;
-}
-
-uintptr_t SegmentMachO::getSize()
-{
-       return fSegmentLoadCommand->vmsize;
-}
-
-uintptr_t SegmentMachO::getFileSize()
-{
-       return fSegmentLoadCommand->filesize;
+       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);
+}
+
+
+intptr_t ImageLoaderMachO::assignSegmentAddresses(const LinkContext& context)
+{
+       // preflight and calculate slide if needed
+       const bool inPIE = (fgNextPIEDylibAddress != 0);
+       intptr_t slide = 0;
+       if ( this->segmentsCanSlide() && this->segmentsMustSlideTogether() ) {
+               bool needsToSlide = false;
+               bool imageHasPreferredLoadAddress = segHasPreferredLoadAddress(0);
+               uintptr_t lowAddr = (unsigned long)(-1);
+               uintptr_t highAddr = 0;
+               for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
+                       const uintptr_t segLow = segPreferredLoadAddress(i);
+                       const uintptr_t segHigh = (segLow + segSize(i) + 4095) & -4096;
+                       if ( segLow < lowAddr )
+                               lowAddr = segLow;
+                       if ( segHigh > highAddr )
+                               highAddr = segHigh;
+                               
+                       if ( needsToSlide || !imageHasPreferredLoadAddress || inPIE || !reserveAddressRange(segPreferredLoadAddress(i), segSize(i)) )
+                               needsToSlide = true;
+               }
+               if ( needsToSlide ) {
+                       // find a chunk of address space to hold all segments
+                       uintptr_t addr = reserveAnAddressRange(highAddr-lowAddr, context);
+                       slide = addr - lowAddr;
+               }
+       } 
+       else if ( ! this->segmentsCanSlide() ) {
+               for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
+                       if ( strcmp(segName(i), "__PAGEZERO") == 0 )
+                               continue;
+                       if ( !reserveAddressRange(segPreferredLoadAddress(i), segSize(i)) )
+                               throw "can't map";
+               }
+       }
+       else {
+               throw "mach-o does not support independently sliding segments";
+       }
+       return slide;
 }
 
-uintptr_t SegmentMachO::getFileOffset()
-{
-       return fSegmentLoadCommand->fileoff;
-}
 
-bool SegmentMachO::readable()
+uintptr_t ImageLoaderMachO::reserveAnAddressRange(size_t length, const ImageLoader::LinkContext& context)
 {
-       return ( (fSegmentLoadCommand->initprot & VM_PROT_READ) != 0);
+       vm_address_t addr = 0;
+       vm_size_t size = length;
+       // in PIE programs, load initial dylibs after main executable so they don't have fixed addresses either
+       if ( fgNextPIEDylibAddress != 0 ) {
+               addr = fgNextPIEDylibAddress + (arc4random() & 0x3) * 4096; // add small random padding between dylibs
+               kern_return_t r = vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_FIXED);
+               if ( r == KERN_SUCCESS ) {
+                       fgNextPIEDylibAddress = addr + size;
+                       return addr;
+               }
+               fgNextPIEDylibAddress = 0;
+       }
+       kern_return_t r = vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE);
+       if ( r != KERN_SUCCESS ) 
+               throw "out of address space";
+       
+       return addr;
 }
 
-bool SegmentMachO::writeable()
+bool ImageLoaderMachO::reserveAddressRange(uintptr_t start, size_t length)
 {
-       return ((fSegmentLoadCommand->initprot & VM_PROT_WRITE) != 0);
+       vm_address_t addr = start;
+       vm_size_t size = length;
+       kern_return_t r = vm_allocate(mach_task_self(), &addr, size, false /*only this range*/);
+       if ( r != KERN_SUCCESS ) 
+               return false;
+       return true;
 }
 
-bool SegmentMachO::executable()
-{
-       return ((fSegmentLoadCommand->initprot & VM_PROT_EXECUTE) != 0);
-}
 
-bool SegmentMachO::unaccessible()
-{
-       return (fSegmentLoadCommand->initprot == 0);
-}
 
-#if TEXT_RELOC_SUPPORT
-bool SegmentMachO::hasFixUps()
+void ImageLoaderMachO::mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context)
 {
-       // scan sections for fix-up bit
-       const struct macho_section* const sectionsStart = (struct macho_section*)((char*)fSegmentLoadCommand + sizeof(struct macho_segment_command));
-       const struct macho_section* const sectionsEnd = &sectionsStart[fSegmentLoadCommand->nsects];
-       for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
-               if ( (sect->flags & (S_ATTR_EXT_RELOC | S_ATTR_LOC_RELOC)) != 0 )
-                       return true;
+       // find address range for image
+       intptr_t slide = this->assignSegmentAddresses(context);
+       if ( context.verboseMapping )
+               dyld::log("dyld: Mapping %s\n", this->getPath());
+       // map in all segments
+       for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
+               vm_offset_t fileOffset = segFileOffset(i) + offsetInFat;
+               vm_size_t size = segFileSize(i);
+               void* requestedLoadAddress = (void*)(segPreferredLoadAddress(i) + slide);
+               int protection = 0;
+               if ( !segUnaccessible(i) ) {
+                       if ( segExecutable(i) )
+                               protection   |= PROT_EXEC;
+                       if ( segReadable(i) )
+                               protection   |= PROT_READ;
+                       if ( segWriteable(i) )
+                               protection   |= PROT_WRITE;
+               }
+       #if __i386__
+               // initially map __IMPORT segments R/W so dyld can update them
+               if ( segIsReadOnlyImport(i) )
+                       protection |= PROT_WRITE;
+       #endif
+               // wholly zero-fill segments have nothing to mmap() in
+               if ( size > 0 ) {
+                       if ( (fileOffset+size) > fileLen ) {
+                               dyld::throwf("truncated mach-o error: segment %s extends to %llu which is past end of file %llu", 
+                                                               segName(i), (uint64_t)(fileOffset+size), fileLen);
+                       }
+                       void* loadAddress = mmap(requestedLoadAddress, size, protection, MAP_FIXED | MAP_PRIVATE, fd, fileOffset);
+                       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());
+                       }
+               }
+               // 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),
+                               (protection & PROT_READ) ? 'r' : '.',  (protection & PROT_WRITE) ? 'w' : '.',  (protection & PROT_EXEC) ? 'x' : '.' );
        }
-       return false;
+       // update slide to reflect load location                        
+       this->setSlide(slide);
 }
-#endif
 
-#if __i386__
-bool SegmentMachO::readOnlyImportStubs()
-{
-       return (    (fSegmentLoadCommand->initprot & VM_PROT_EXECUTE) 
-                       && ((fSegmentLoadCommand->initprot & VM_PROT_WRITE) == 0) 
-                       && (strcmp(fSegmentLoadCommand->segname, "__IMPORT") == 0) );
-}
-#endif
-       
-uintptr_t SegmentMachO::getActualLoadAddress(const ImageLoader* inImage)
+void ImageLoaderMachO::mapSegments(const void* memoryImage, uint64_t imageLen, const LinkContext& context)
 {
-       return fSegmentLoadCommand->vmaddr + inImage->getSlide();
+       // find address range for image
+       intptr_t slide = this->assignSegmentAddresses(context);
+       if ( context.verboseMapping )
+               dyld::log("dyld: Mapping memory %p\n", memoryImage);
+       // map in all segments
+       for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
+               vm_address_t loadAddress = segPreferredLoadAddress(i) + slide;
+               vm_address_t srcAddr = (uintptr_t)memoryImage + segFileOffset(i);
+               vm_size_t size = segFileSize(i);
+               kern_return_t r = vm_copy(mach_task_self(), srcAddr, size, loadAddress);
+               if ( r != KERN_SUCCESS ) 
+                       throw "can't map segment";
+               if ( context.verboseMapping )
+                       dyld::log("%18s at 0x%08lX->0x%08lX\n", segName(i), (uintptr_t)loadAddress, (uintptr_t)loadAddress+size-1);
+       }
+       // update slide to reflect load location                        
+       this->setSlide(slide);
+       // set R/W permissions on all segments at slide location
+       for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
+               segProtect(i, context);         
+       }
 }
 
-uintptr_t SegmentMachO::getPreferredLoadAddress()
-{
-       return fSegmentLoadCommand->vmaddr;
-}
 
-bool SegmentMachO::hasPreferredLoadAddress()
+void ImageLoaderMachO::segProtect(unsigned int segIndex, const ImageLoader::LinkContext& context)
 {
-       return (fSegmentLoadCommand->vmaddr != 0);
-}
-
+       vm_prot_t protection = 0;
+       if ( !segUnaccessible(segIndex) ) {
+               if ( segExecutable(segIndex) )
+                       protection   |= PROT_EXEC;
+               if ( segReadable(segIndex) )
+                       protection   |= PROT_READ;
+               if ( segWriteable(segIndex) )
+                       protection   |= PROT_WRITE;
+       }
+       vm_address_t addr = segActualLoadAddress(segIndex);
+       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 ( 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' : '.' );
+       }
+}      
 
-Segment* SegmentMachO::next(Segment* location)
-{
-       return &((SegmentMachO*)location)[1];
+void ImageLoaderMachO::segMakeWritable(unsigned int segIndex, const ImageLoader::LinkContext& context)
+{
+       vm_address_t addr = segActualLoadAddress(segIndex);
+       vm_size_t size = segSize(segIndex);
+       const bool setCurrentPermissions = false;
+       vm_prot_t protection = VM_PROT_WRITE | VM_PROT_READ;
+       if ( segExecutable(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 ( 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 e28f672573c41b77a87d7497b77e14b990a634cd..5d735bfc764a9b03a0b80578939ea461b4e0c4cb 100644 (file)
 #define __IMAGELOADERMACHO__
 
 #include <stdint.h> 
+#include <mach-o/loader.h> 
+#include <mach-o/nlist.h> 
 
 #include "ImageLoader.h"
 #include "mach-o/dyld_images.h"
 
-struct sf_mapping;
-struct _shared_region_mapping_np;
-
 
 //
-// ImageLoaderMachO is the concrete subclass of ImageLoader which loads mach-o format files.
-// The class is written to be 64-bit clean and support both 32-bit and 64-bit executables in
-// mach-o.
+// ImageLoaderMachO is a subclass of ImageLoader which loads mach-o format files.
 //
 //
 class ImageLoaderMachO : public ImageLoader {
 public:
-                                                                               ImageLoaderMachO(const char* path, int fd, const uint8_t firstPage[4096], uint64_t offset, uint64_t len, const struct stat& info, const LinkContext& context);
-                                                                               ImageLoaderMachO(const char* moduleName, const struct mach_header* mh, uint64_t len, const LinkContext& context);
-                                                                               ImageLoaderMachO(const struct mach_header* mh, const char* path, const struct stat& info, const LinkContext& context);
-                                                                               ImageLoaderMachO(const struct mach_header* executableHeader, uintptr_t executableSlide, const char* path, const LinkContext& context);
-       virtual                                                         ~ImageLoaderMachO();
+       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*                                     instantiateFromMemory(const char* moduleName, const macho_header* mh, uint64_t len, const LinkContext& context);
+
 
        const char*                                                     getInstallPath() const;
        virtual void*                                           getMain() const;
@@ -55,7 +53,7 @@ public:
        virtual uintptr_t                                       getSlide() const;
        virtual const void*                                     getEnd() const;
        virtual bool                                            hasCoalescedExports() const;
-       virtual const Symbol*                           findExportedSymbol(const char* name, const void* hint, bool searchReExports, const ImageLoader** foundIn) 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 DefinitionFlags                         getExportedSymbolInfo(const Symbol* sym) const;
        virtual const char*                                     getExportedSymbolName(const Symbol* sym) const;
@@ -63,122 +61,148 @@ public:
        virtual const Symbol*                           getIndexedExportedSymbol(uint32_t index) const;
        virtual uint32_t                                        getImportedSymbolCount() const;
        virtual const Symbol*                           getIndexedImportedSymbol(uint32_t index) const;
-       virtual ReferenceFlags                          geImportedSymbolInfo(const Symbol* sym) const;
+       virtual ReferenceFlags                          getImportedSymbolInfo(const Symbol* sym) const;
        virtual const char*                                     getImportedSymbolName(const Symbol* sym) const;
        virtual bool                                            isBundle() const;
        virtual bool                                            isDylib() const;
+       virtual bool                                            isExecutable() const;
+       virtual bool                                            isPositionIndependentExecutable() const;
        virtual bool                                            forceFlat() const;
-       virtual uintptr_t                                       doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context);
+       virtual bool                                            participatesInCoalescing() const;
+       virtual const char*                                     findClosestSymbol(const void* addr, const void** closestAddr) const = 0;
+       virtual void                                            initializeCoalIterator(CoalIterator&, unsigned int loadOrder) = 0;
+       virtual bool                                            incrementCoalIterator(CoalIterator&) = 0;
+       virtual uintptr_t                                       getAddressCoalIterator(CoalIterator&, const LinkContext& contex) = 0;
+       virtual void                                            updateUsesCoalIterator(CoalIterator&, uintptr_t newAddr, ImageLoader* target, const LinkContext& context) = 0;
+       virtual uintptr_t                                       doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context) = 0;
+       virtual uintptr_t                                       doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context) = 0;
        virtual void                                            doTermination(const LinkContext& context);
-#if IMAGE_NOTIFY_SUPPORT
-       virtual void                                            doNotification(enum dyld_image_mode mode, uint32_t infoCount, const struct dyld_image_info info[]);
-#endif
        virtual bool                                            needsInitialization();
-#if IMAGE_NOTIFY_SUPPORT
-       virtual bool                                            hasImageNotification();
-#endif
        virtual bool                                            getSectionContent(const char* segmentName, const char* sectionName, void** start, size_t* length);
+       virtual void                                            getUnwindInfo(dyld_unwind_sections* info);
        virtual bool                                            findSection(const void* imageInterior, const char** segmentName, const char** sectionName, size_t* sectionOffset);
        virtual bool                                            usablePrebinding(const LinkContext& context) const;
+       virtual unsigned int                            segmentCount() const;
+       virtual const char*                                     segName(unsigned int) const;
+       virtual uintptr_t                                       segSize(unsigned int) const;
+       virtual uintptr_t                                       segFileSize(unsigned int) const;
+       virtual bool                                            segHasTrailingZeroFill(unsigned int);
+       virtual uintptr_t                                       segFileOffset(unsigned int) const;
+       virtual bool                                            segReadable(unsigned int) const;
+       virtual bool                                            segWriteable(unsigned int) const;
+       virtual bool                                            segExecutable(unsigned int) const;
+       virtual bool                                            segUnaccessible(unsigned int) const;
+       virtual bool                                            segHasPreferredLoadAddress(unsigned int) const;
+       virtual uintptr_t                                       segActualLoadAddress(unsigned int) const;
+       virtual uintptr_t                                       segPreferredLoadAddress(unsigned int) const;
+       virtual uintptr_t                                       segActualEndAddress(unsigned int) const;
                        
        
        static void                                                     printStatistics(unsigned int imageCount);
        
 protected:
                                                ImageLoaderMachO(const ImageLoaderMachO&);
+                                               ImageLoaderMachO(const macho_header* mh, const char* path, unsigned int segCount,
+                                                                                                                                       uint32_t segOffsets[], unsigned int libCount);
+       virtual                         ~ImageLoaderMachO() {}
+
        void                            operator=(const ImageLoaderMachO&);
 
-       virtual uint32_t        doGetDependentLibraryCount();
+       virtual void                                            setDyldInfo(const dyld_info_command*) = 0;
+       virtual void                                            setSymbolTableInfo(const macho_nlist*, const char*, const dysymtab_command*) = 0;
+       virtual bool                                            isSubframeworkOf(const LinkContext& context, const ImageLoader* image) const = 0;
+       virtual bool                                            hasSubLibrary(const LinkContext& context, const ImageLoader* child) const = 0;
+       virtual uint32_t*                                       segmentCommandOffsets() const = 0;
+       virtual void                                            rebase(const LinkContext& context) = 0;
+       virtual const ImageLoader::Symbol*      findExportedSymbol(const char* name, const ImageLoader** foundIn) const = 0;
+       virtual bool                                            containsSymbol(const void* addr) const = 0;
+       virtual uintptr_t                                       exportedSymbolAddress(const Symbol* symbol) const = 0;
+       virtual bool                                            exportedSymbolIsWeakDefintion(const Symbol* symbol) const = 0;
+       virtual const char*                                     exportedSymbolName(const Symbol* symbol) const = 0;
+       virtual unsigned int                            exportedSymbolCount() const = 0;
+       virtual const ImageLoader::Symbol*      exportedSymbolIndexed(unsigned int) const = 0;
+       virtual unsigned int                            importedSymbolCount() const = 0;
+       virtual const ImageLoader::Symbol*      importedSymbolIndexed(unsigned int) const = 0;
+       virtual const char*                                     importedSymbolName(const Symbol* symbol) const = 0;
+#if PREBOUND_IMAGE_SUPPORT
+       virtual void                                            resetPreboundLazyPointers(const LinkContext& context) = 0;
+#endif
+       
+
        virtual void            doGetDependentLibraries(DependentLibraryInfo libs[]);
        virtual LibraryInfo doGetLibraryInfo();
        virtual void            getRPaths(const LinkContext& context, std::vector<const char*>&) const;
+       virtual bool            getUUID(uuid_t) const;
        virtual void            doRebase(const LinkContext& context);
-       virtual void            doBind(const LinkContext& context, bool forceLazysBound);
-       virtual void            doBindJustLazies(const LinkContext& context);
-       virtual void            doUpdateMappingPermissions(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 void            doGetDOFSections(const LinkContext& context, std::vector<ImageLoader::DOFInfo>& dofs);
        virtual bool            needsTermination();
-       virtual void            instantiateSegments(const uint8_t* fileData);
        virtual bool            segmentsMustSlideTogether() const;      
        virtual bool            segmentsCanSlide() const;                       
        virtual void            setSlide(intptr_t slide);               
        virtual bool            usesTwoLevelNameSpace() const;
-       virtual bool            isSubframeworkOf(const LinkContext& context, const ImageLoader* image) const;
-       virtual bool            hasSubLibrary(const LinkContext& context, const ImageLoader* child) const;
        virtual bool            isPrebindable() const;
-       virtual SegmentIterator beginSegments() const;
-       virtual SegmentIterator endSegments() const;
 
-#if SPLIT_SEG_DYLIB_SUPPORT
-       virtual void            mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context);
-#endif 
                
-private:
-       friend class SegmentMachO;
+protected:
 
-                       void            init();
+                       void            destroy();
+       static void                     sniffLoadCommands(const macho_header* mh, const char* path, bool* compressed,
+                                                                                       unsigned int* segCount, unsigned int* libCount);
+       static bool                     needsAddedLibSystemDepency(unsigned int libCount, const macho_header* mh);
+#if CODESIGNING_SUPPORT
+                       void            loadCodeSignature(const uint8_t* fileData, int fd, uint64_t offsetInFatFile);
+#endif
+                       const struct macho_segment_command* segLoadCommand(unsigned int segIndex) const;
                        void            parseLoadCmds();
-                       uintptr_t       bindIndirectSymbol(uintptr_t* ptrToBind, const struct macho_section* sect, const char* symbolName, uintptr_t targetAddr, const ImageLoader* targetImage, const LinkContext& context);
-                       void            doBindIndirectSymbolPointers(const LinkContext& context, bool bindNonLazys, bool bindLazys, bool onlyCoalescedSymbols);
-                       void            doBindExternalRelocations(const LinkContext& context, bool onlyCoalescedSymbols);
-                       uintptr_t       resolveUndefined(const LinkContext& context, const struct macho_nlist* symbol, bool twoLevel, const ImageLoader **foundIn);
-                       uintptr_t       getRelocBase();
-                       uintptr_t       getFirstWritableSegmentAddress();
-                       void            resetPreboundLazyPointers(const LinkContext& context, uintptr_t relocBase);
+                       bool            segHasRebaseFixUps(unsigned int) const;
+                       bool            segHasBindFixUps(unsigned int) const;
+                       void            segProtect(unsigned int segIndex, const ImageLoader::LinkContext& context);
+                       void            segMakeWritable(unsigned int segIndex, const ImageLoader::LinkContext& context);
+#if __i386__
+                       bool            segIsReadOnlyImport(unsigned int) const;
+#endif
+                       intptr_t        assignSegmentAddresses(const LinkContext& context);
+                       uintptr_t       reserveAnAddressRange(size_t length, const ImageLoader::LinkContext& context);
+                       bool            reserveAddressRange(uintptr_t start, size_t length);
+                       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            doImageInit(const LinkContext& context);
                        void            doModInitFunctions(const LinkContext& context);
                        void            setupLazyPointerHandler(const LinkContext& context);
                        void            lookupProgramVars(const LinkContext& context) const;
-#if SPLIT_SEG_DYLIB_SUPPORT    
-                       unsigned int getExtraZeroFillEntriesCount();
-                       void            initMappingTable(uint64_t offsetInFat, _shared_region_mapping_np *mappingTable);
-                       int                     sharedRegionMapFilePrivateOutside(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context);
-#endif
-#if SPLIT_SEG_SHARED_REGION_SUPPORT
-                       int                     sharedRegionLoadFile(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context);
-                       int                     sharedRegionMapFile(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context);
-                       int                     sharedRegionMakePrivate(const LinkContext& context);
-                       int                     sharedRegionMapFilePrivate(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context, bool usemmap);
-                       void            initMappingTable(uint64_t offsetInFat, sf_mapping *mappingTable, uintptr_t baseAddress);
-#endif
-                       bool            needsCoalescing() const;
-                       bool            isAddrInSection(uintptr_t addr, uint8_t sectionIndex);
-                       void            adjustSegments();
-                       uintptr_t       getSymbolAddress(const struct macho_nlist* sym, const ImageLoader* requestor, const LinkContext& context) const;
-                       void            preFetch(int fd, uint64_t offsetInFat, const LinkContext& context);
-#if __i386__
-                       void            makeImportSegmentWritable(const LinkContext& context);
-                       void            makeImportSegmentReadOnly(const LinkContext& context);
-#endif
+                       uintptr_t       bindLocation(const LinkContext& context, uintptr_t location, uintptr_t value, 
+                                                                               const ImageLoader* targetImage, uint8_t type, const char* symbolName, 
+                                                                               intptr_t addend, const char* msg);
                        
-       static  bool                            symbolRequiresCoalescing(const struct macho_nlist* symbol); 
-       static uintptr_t                        bindLazySymbol(const mach_header*, uintptr_t* lazyPointer);
-       const struct macho_nlist*  binarySearch(const char* key, const char stringPool[], const struct macho_nlist symbols[], uint32_t symbolCount) const;
-       const struct macho_nlist*  binarySearchWithToc(const char* key, const char stringPool[], const struct macho_nlist symbols[], 
-                                                                                               const struct dylib_table_of_contents toc[], uint32_t symbolCount, uint32_t hintIndex) const;
+                       void            makeTextSegmentWritable(const LinkContext& context, bool writeable);
+                       void            preFetchDATA(int fd, uint64_t offsetInFat, const LinkContext& context);
+
+
+                       bool            hasReferencesToWeakSymbols() const;
+                       uintptr_t       getSymbolAddress(const Symbol* sym, const ImageLoader* requestor, const LinkContext& context) const;
                        
+       static uintptr_t                        bindLazySymbol(const mach_header*, uintptr_t* lazyPointer);
+protected:                     
        const uint8_t*                                                  fMachOData;
-       const uint8_t*                                                  fLinkEditBase; // add any internal "offset" to this to get actual address
-       const struct macho_nlist*                               fSymbolTable;
-       const char*                                                             fStrings;
-       const struct dysymtab_command*                  fDynamicInfo;
+       const uint8_t*                                                  fLinkEditBase; // add any internal "offset" to this to get mapped address
        uintptr_t                                                               fSlide;
-       const struct twolevel_hints_command*    fTwoLevelHints;
-       const struct dylib_command*                             fDylibID;
-       class SegmentMachO*                                             fSegmentsArray;
+       uint32_t                                                                fEHFrameSectionOffset;
+       uint32_t                                                                fUnwindInfoSectionOffset;
+       uint32_t                                                                fDylibIDOffset;
+       uint32_t                                                                fSegmentsCount : 8,
+                                                                                       fIsSplitSeg : 1,
+                                                                                       fInSharedCache : 1,
 #if TEXT_RELOC_SUPPORT
-       class SegmentMachO*                                             fTextSegmentWithFixups; // NULL unless __TEXT segment has fixups
+                                                                                       fTextSegmentRebases : 1, 
+                                                                                       fTextSegmentBinds : 1, 
 #endif
 #if __i386__
-       class SegmentMachO*                                             fReadOnlyImportSegment; // NULL unless __IMPORT segment built with -read_only_stubs
-       static uint32_t                                                 fgReadOnlyImportSpinLock;
-#endif
-       uint32_t                                                                fSegmentsArrayCount : 8,
-                                                                                       fIsSplitSeg : 1,
-                                                                                       fInSharedCache : 1,
-#if __ppc64__
-                                                                                       f4GBWritable : 1,
+                                                                                       fReadOnlyImportSegment : 1,
 #endif
                                                                                        fHasSubLibraries : 1,
                                                                                        fHasSubUmbrella : 1,
@@ -186,51 +210,11 @@ private:
                                                                                        fHasDOFSections : 1,
                                                                                        fHasDashInit : 1,
                                                                                        fHasInitializers : 1,
-#if IMAGE_NOTIFY_SUPPORT
-                                                                                       fHasImageNotifySection : 1,
-#endif
                                                                                        fHasTerminators : 1;
-       static uint32_t                                 fgHintedBinaryTreeSearchs;
-       static uint32_t                                 fgUnhintedBinaryTreeSearchs;
-       static uint32_t                                 fgCountOfImagesWithWeakExports;
-};
-
-
-class SegmentMachO : public Segment
-{
-public:        
-                                                               SegmentMachO(const struct macho_segment_command* cmd);
-       virtual                                         ~SegmentMachO();
-                                                               
-       virtual const char*                     getName();
-       virtual uintptr_t                       getSize();
-       virtual uintptr_t                       getFileSize();
-       virtual uintptr_t                       getFileOffset();
-       virtual bool                            readable();
-       virtual bool                            writeable();
-       virtual bool                            executable();
-       virtual bool                            unaccessible();
-       virtual uintptr_t                       getActualLoadAddress(const ImageLoader*);
-       virtual uintptr_t                       getPreferredLoadAddress();
-       virtual void                            unmap(const ImageLoader*);
-       virtual Segment*                        next(Segment*);
-#if TEXT_RELOC_SUPPORT
-       virtual bool                            hasFixUps();
-#endif
-#if __i386__
-       virtual bool                            readOnlyImportStubs();
-#endif
-protected:
-       virtual bool                            hasPreferredLoadAddress();
-       
-private:
-                                               SegmentMachO(const SegmentMachO&);
-       void                            operator=(const SegmentMachO&);
-       void                            adjust(const struct macho_segment_command* cmd);
-
-       friend class ImageLoaderMachO;
-       
-       const struct macho_segment_command*             fSegmentLoadCommand;
+                                                                                       
+                                                                                       
+       static uint32_t                                 fgSymbolTableBinarySearchs;
+       static uint32_t                                 fgSymbolTrieSearchs;
 };
 
 
diff --git a/src/ImageLoaderMachOClassic.cpp b/src/ImageLoaderMachOClassic.cpp
new file mode 100644 (file)
index 0000000..182047e
--- /dev/null
@@ -0,0 +1,1979 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2004-2008 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@
+ */
+
+// work around until conformance work is complete rdar://problem/4508801
+#define __srr0 srr0 
+#define __eip  eip 
+#define __rip  rip 
+
+
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h> 
+#include <sys/mman.h>
+#include <mach/mach.h>
+#include <mach/thread_status.h>
+#include <mach-o/loader.h> 
+#include <mach-o/reloc.h> 
+#include <mach-o/nlist.h> 
+#include <sys/sysctl.h>
+#include <libkern/OSAtomic.h>
+#include <libkern/OSCacheControl.h>
+
+#if __ppc__ || __ppc64__
+       #include <mach-o/ppc/reloc.h>
+#endif
+#if __x86_64__
+       #include <mach-o/x86_64/reloc.h>
+#endif
+#if __arm__
+       #include <mach-o/arm/reloc.h>
+#endif
+
+#include "ImageLoaderMachOClassic.h"
+#include "mach-o/dyld_images.h"
+
+// optimize strcmp for ppc
+#if __ppc__
+       #include <ppc_intrinsics.h>
+#else
+       #define astrcmp(a,b) strcmp(a,b)
+#endif
+
+
+// in dyldStartup.s
+extern "C" void fast_stub_binding_helper_interface();
+
+
+#if __x86_64__
+       #define POINTER_RELOC X86_64_RELOC_UNSIGNED
+#else
+       #define POINTER_RELOC GENERIC_RELOC_VANILLA
+#endif
+
+
+// relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables
+#if __LP64__
+       #define RELOC_SIZE 3
+       #define LC_SEGMENT_COMMAND              LC_SEGMENT_64
+       #define LC_ROUTINES_COMMAND             LC_ROUTINES_64
+       struct macho_segment_command    : public segment_command_64  {};
+       struct macho_section                    : public section_64  {};        
+       struct macho_routines_command   : public routines_command_64  {};       
+#else
+       #define RELOC_SIZE 2
+       #define LC_SEGMENT_COMMAND              LC_SEGMENT
+       #define LC_ROUTINES_COMMAND             LC_ROUTINES
+       struct macho_segment_command    : public segment_command {};
+       struct macho_section                    : public section  {};   
+       struct macho_routines_command   : public routines_command  {};  
+#endif
+
+
+
+
+// create image for main executable
+ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateMainExecutable(const macho_header* mh, uintptr_t slide, const char* path, 
+                                                                                                                                               unsigned int segCount, unsigned int libCount, const LinkContext& context)
+{
+       ImageLoaderMachOClassic* image = ImageLoaderMachOClassic::instantiateStart(mh, path, segCount, libCount);
+
+       // set slide for PIE programs
+       image->setSlide(slide);
+
+       // for PIE record end of program, to know where to start loading dylibs
+       if ( (mh->flags & MH_PIE) && !context.noPIE )
+               fgNextPIEDylibAddress = (uintptr_t)image->getEnd();
+       
+       image->instantiateFinish(context);
+       
+#if __i386__
+       // kernel may have mapped in __IMPORT segment read-only, we need it read/write to do binding
+       if ( image->fReadOnlyImportSegment ) {
+               for(unsigned int i=0; i < image->fSegmentsCount; ++i) {
+                       if ( image->segIsReadOnlyImport(i) )
+                               image->segMakeWritable(i, context);
+               }
+       }
+#endif
+
+       if ( context.verboseMapping ) {
+               dyld::log("dyld: Main executable mapped %s\n", path);
+               for(unsigned int i=0, e=image->segmentCount(); i < e; ++i) {
+                       const char* name = image->segName(i);
+                       if ( (strcmp(name, "__PAGEZERO") == 0) || (strcmp(name, "__UNIXSTACK") == 0)  )
+                               dyld::log("%18s at 0x%08lX->0x%08lX\n", name, image->segPreferredLoadAddress(i), image->segPreferredLoadAddress(i)+image->segSize(i));
+                       else
+                               dyld::log("%18s at 0x%08lX->0x%08lX\n", name, image->segActualLoadAddress(i), image->segActualEndAddress(i));
+               }
+       }
+
+       return image;
+}
+
+// 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)
+{
+       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);
+       #endif
+               
+               // 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] == '/') )
+                       image->setPathUnowned(installName);
+               else if ( path[0] != '/' ) {
+                       // rdar://problem/5135363 turn relative paths into absolute paths so gdb, Symbolication can later find them
+                       char realPath[MAXPATHLEN];
+                       if ( realpath(path, realPath) != NULL )
+                               image->setPath(realPath);
+                       else
+                               image->setPath(path);
+               }
+               else 
+                       image->setPath(path);
+
+               // 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
+               // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight
+               delete image;
+               throw;
+       }
+       
+       return image;
+}
+
+// create image by using cached mach-o file
+ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateFromCache(const macho_header* mh, const char* path, const struct stat& info,
+                                                                                                                               unsigned int segCount, unsigned int libCount, const LinkContext& context)
+{
+       ImageLoaderMachOClassic* image = ImageLoaderMachOClassic::instantiateStart(mh, path, segCount, libCount);
+       try {
+               // record info about file  
+               image->setFileInfo(info.st_dev, info.st_ino, info.st_mtime);
+
+               // remember this is from shared cache and cannot be unloaded
+               image->fInSharedCache = true;
+               image->setNeverUnload();
+
+               // segments already mapped in cache
+               if ( context.verboseMapping ) {
+                       dyld::log("dyld: Using shared cached for %s\n", path);
+                       for(unsigned int i=0, e=image->segmentCount(); i < e; ++i) {
+                               dyld::log("%18s at 0x%08lX->0x%08lX\n", image->segName(i), image->segActualLoadAddress(i), image->segActualEndAddress(i));
+                       }
+               }
+
+               image->instantiateFinish(context);
+       }
+       catch (...) {
+               // ImageLoader::setMapped() can throw an exception to block loading of image
+               // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight
+               delete image;
+               throw;
+       }
+       
+       return image;
+}
+
+// create image by copying an in-memory mach-o file
+ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateFromMemory(const char* moduleName, const macho_header* mh, uint64_t len, 
+                                                                                                                       unsigned int segCount, unsigned int libCount, const LinkContext& context)
+{
+       ImageLoaderMachOClassic* image = ImageLoaderMachOClassic::instantiateStart(mh, moduleName, segCount, libCount);
+       try {
+               // map segments 
+               if ( mh->filetype == MH_EXECUTE ) 
+                       throw "can't load another MH_EXECUTE";
+               
+               // vmcopy segments
+               image->ImageLoaderMachO::mapSegments((const void*)mh, len, context);
+
+               // for compatibility, never unload dylibs loaded from memory
+               image->setNeverUnload();
+
+               // bundle loads need path copied
+               if ( moduleName != NULL ) 
+                       image->setPath(moduleName);
+
+               image->instantiateFinish(context);
+       }
+       catch (...) {
+               // ImageLoader::setMapped() can throw an exception to block loading of image
+               // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight
+               delete image;
+               throw;
+       }
+       
+       return image;
+}
+
+
+ImageLoaderMachOClassic::ImageLoaderMachOClassic(const macho_header* mh, const char* path, 
+                                                                                                       unsigned int segCount, uint32_t segOffsets[], unsigned int libCount)
+ : ImageLoaderMachO(mh, path, segCount, segOffsets, libCount), fStrings(NULL), fSymbolTable(NULL), fDynamicInfo(NULL)
+{
+}
+
+// construct ImageLoaderMachOClassic using "placement new" with SegmentMachO objects array at end
+ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateStart(const macho_header* mh, const char* path,
+                                                                                                                                               unsigned int segCount, unsigned int libCount)
+{
+       size_t size = sizeof(ImageLoaderMachOClassic) + segCount * sizeof(uint32_t) + libCount * sizeof(ImageLoader*);
+       ImageLoaderMachOClassic* allocatedSpace = static_cast<ImageLoaderMachOClassic*>(malloc(size));
+       if ( allocatedSpace == NULL )
+               throw "malloc failed";
+       uint32_t* segOffsets = ((uint32_t*)(((uint8_t*)allocatedSpace) + sizeof(ImageLoaderMachOClassic)));
+       bzero(&segOffsets[segCount], libCount*sizeof(void*));   // zero out lib array
+       return new (allocatedSpace) ImageLoaderMachOClassic(mh, path, segCount, segOffsets, libCount);
+}
+
+
+
+// common code to finish initializing object
+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()
+{
+       // don't do clean up in ~ImageLoaderMachO() because virtual call to segmentCommandOffsets() won't work
+       destroy();
+}
+
+uint32_t* ImageLoaderMachOClassic::segmentCommandOffsets() const
+{
+       return ((uint32_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic)));
+}
+
+
+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));
+}
+
+bool ImageLoaderMachOClassic::libReExported(unsigned int libIndex) const
+{
+       const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic) + fSegmentsCount*sizeof(uint32_t)));
+       // re-export flag is low bit
+       return ((images[libIndex] & 1) != 0);
+}      
+
+
+void ImageLoaderMachOClassic::setLibImage(unsigned int libIndex, ImageLoader* image, bool reExported)
+{
+       uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic) + fSegmentsCount*sizeof(uint32_t)));
+       uintptr_t value = (uintptr_t)image;
+       if ( reExported ) 
+               value |= 1;
+       images[libIndex] = value;
+}
+
+
+void ImageLoaderMachOClassic::setSymbolTableInfo(const macho_nlist* symbols, const char* strings, const dysymtab_command* dynSym)
+{
+       fSymbolTable = symbols;
+       fStrings = strings;
+       fDynamicInfo = dynSym;
+}
+
+void ImageLoaderMachOClassic::prefetchLINKEDIT(const LinkContext& context)
+{
+       // always prefetch a subrange of __LINKEDIT pages
+       uintptr_t symbolTableStart = (uintptr_t)fSymbolTable;
+       uintptr_t stringTableStart = (uintptr_t)fStrings;
+       uintptr_t start;
+       // if image did not load at preferred address
+       if ( segPreferredLoadAddress(0) != (uintptr_t)fMachOData ) {
+               // local relocations will be processed, so start pre-fetch at local symbols
+               start = (uintptr_t)fMachOData + fDynamicInfo->locreloff;
+       }
+       else {
+               // otherwise start pre-fetch at global symbols section of symbol table
+               start = symbolTableStart + fDynamicInfo->iextdefsym * sizeof(macho_nlist);
+       }
+       // prefetch ends at end of last undefined string in string pool
+       uintptr_t end = stringTableStart;
+       if ( fDynamicInfo->nundefsym != 0 )
+               end += fSymbolTable[fDynamicInfo->iundefsym+fDynamicInfo->nundefsym-1].n_un.n_strx;
+       else if ( fDynamicInfo->nextdefsym != 0 )
+               end += fSymbolTable[fDynamicInfo->iextdefsym+fDynamicInfo->nextdefsym-1].n_un.n_strx;
+               
+       // round to whole pages
+       start = start & (-4096);
+       end = (end + 4095) & (-4096);
+       
+       // skip if there is only one page
+       if ( (end-start) > 4096 ) {
+               madvise((void*)start, end-start, MADV_WILLNEED);
+               fgTotalBytesPreFetched += (end-start);
+               if ( context.verboseMapping ) {
+                       dyld::log("%18s prefetching 0x%0lX -> 0x%0lX\n", "__LINKEDIT", start, end-1);
+               }
+       }
+}
+
+
+#if SPLIT_SEG_DYLIB_SUPPORT    
+unsigned int
+ImageLoaderMachOClassic::getExtraZeroFillEntriesCount()
+{
+       // calculate mapping entries
+       unsigned int extraZeroFillEntries = 0;
+       for(unsigned int i=0; i < fSegmentsCount; ++i) {
+               if ( segHasTrailingZeroFill(i) )
+                       ++extraZeroFillEntries;
+       }
+       
+       return extraZeroFillEntries;
+}
+
+void
+ImageLoaderMachOClassic::initMappingTable(uint64_t offsetInFat,
+                                                                  shared_file_mapping_np *mappingTable)
+{
+       for(unsigned int i=0,entryIndex=0; i < fSegmentsCount; ++i, ++entryIndex) {
+               shared_file_mapping_np* entry = &mappingTable[entryIndex];
+               entry->sfm_address                      = segActualLoadAddress(i);
+               entry->sfm_size                         = segFileSize(i);
+               entry->sfm_file_offset          = segFileOffset(i) + offsetInFat;
+               entry->sfm_init_prot            = VM_PROT_NONE;
+               if ( !segUnaccessible(i) ) {
+                       if ( segExecutable(i) )
+                               entry->sfm_init_prot   |= VM_PROT_EXECUTE;
+                       if ( segReadable(i) )
+                               entry->sfm_init_prot   |= VM_PROT_READ;
+                       if ( segWriteable(i) )
+                               entry->sfm_init_prot   |= VM_PROT_WRITE | VM_PROT_COW;
+               }
+               entry->sfm_max_prot                     = entry->sfm_init_prot;
+               if ( segHasTrailingZeroFill(i) ) {
+                       shared_file_mapping_np* zfentry = &mappingTable[++entryIndex];
+                       zfentry->sfm_address            = entry->sfm_address + segFileSize(i);
+                       zfentry->sfm_size                       = segSize(i) - segFileSize(i);
+                       zfentry->sfm_file_offset        = 0;
+                       zfentry->sfm_init_prot          = entry->sfm_init_prot | VM_PROT_COW | VM_PROT_ZF;
+                       zfentry->sfm_max_prot           = zfentry->sfm_init_prot;
+               }
+       }
+}
+
+int
+ImageLoaderMachOClassic::mapSplitSegDylibOutsideSharedRegion(int fd,
+                                                                                                       uint64_t offsetInFat,
+                                                                                                       uint64_t lenInFat,
+                                                                                                       uint64_t fileLen,
+                                                                                                       const LinkContext& context)
+{
+       uintptr_t nextAltLoadAddress = 0;
+       const unsigned int segmentCount = fSegmentsCount;
+       const unsigned int extraZeroFillEntries = getExtraZeroFillEntriesCount();
+       const unsigned int regionCount = segmentCount+extraZeroFillEntries;
+       shared_file_mapping_np regions[regionCount];
+       initMappingTable(offsetInFat, regions);
+       int r = -1;
+       // find space somewhere to allocate split seg
+       bool foundRoom = false;
+       while ( ! foundRoom ) {
+               foundRoom = true;
+               for(unsigned int i=0; i < regionCount; ++i) {
+                       vm_address_t addr = nextAltLoadAddress + regions[i].sfm_address - regions[0].sfm_address;
+                       vm_size_t size = regions[i].sfm_size ;
+                       r = vm_allocate(mach_task_self(), &addr, size, false /*only this range*/);
+                       if ( 0 != r ) {
+                               // no room here, deallocate what has succeeded so far
+                               for(unsigned int j=0; j < i; ++j) {
+                                       vm_address_t addr = nextAltLoadAddress + regions[j].sfm_address - regions[0].sfm_address;
+                                       vm_size_t size = regions[j].sfm_size ;
+                                       (void)vm_deallocate(mach_task_self(), addr, size);
+                               }
+                               nextAltLoadAddress += 0x00100000;  // skip ahead 1MB and try again
+                               // skip over shared region
+                               if ( (SHARED_REGION_BASE <= nextAltLoadAddress) && (nextAltLoadAddress < (SHARED_REGION_BASE + SHARED_REGION_SIZE)) )
+                                       nextAltLoadAddress = (SHARED_REGION_BASE + SHARED_REGION_SIZE);
+                               if ( nextAltLoadAddress > 0xFF000000 )
+                                       throw "can't map split seg anywhere";
+                               foundRoom = false;
+                               break;
+                       }
+               }
+       }
+       
+       // map in each region
+       uintptr_t slide = nextAltLoadAddress - regions[0].sfm_address;
+       this->setSlide(slide);
+       for(unsigned int i=0; i < regionCount; ++i) {
+               if ( ((regions[i].sfm_init_prot & VM_PROT_ZF) != 0) || (regions[i].sfm_size == 0) ) {
+                       // nothing to mmap for zero-fills areas, they are just vm_allocated 
+               }
+               else {
+                       void* mmapAddress = (void*)(uintptr_t)(regions[i].sfm_address + slide);
+                       size_t size = regions[i].sfm_size;
+                       int protection = 0;
+                       if ( regions[i].sfm_init_prot & VM_PROT_EXECUTE )
+                               protection   |= PROT_EXEC;
+                       if ( regions[i].sfm_init_prot & VM_PROT_READ )
+                               protection   |= PROT_READ;
+                       if ( regions[i].sfm_init_prot & VM_PROT_WRITE )
+                               protection   |= PROT_WRITE;
+                       off_t offset = regions[i].sfm_file_offset;
+                       //dyld::log("mmap(%p, 0x%08lX, %s\n", mmapAddress, size, fPath);
+                       mmapAddress = mmap(mmapAddress, size, protection, MAP_FIXED | MAP_PRIVATE, fd, offset);
+                       if ( mmapAddress == ((void*)(-1)) )
+                               throw "mmap error";
+               }
+       }
+       
+       // logging
+       if ( context.verboseMapping ) {
+               dyld::log("dyld: Mapping split-seg outside shared region, slid by 0x%08lX %s\n", this->fSlide, this->getPath());
+               for(unsigned int segIndex=0,entryIndex=0; segIndex < segmentCount; ++segIndex, ++entryIndex){
+                       const shared_file_mapping_np* entry = &regions[entryIndex];
+                       if ( (entry->sfm_init_prot & VM_PROT_ZF) == 0 ) 
+                               dyld::log("%18s at 0x%08lX->0x%08lX\n",
+                                               segName(segIndex), segActualLoadAddress(segIndex), segActualEndAddress(segIndex)-1);
+                       if ( entryIndex < (regionCount-1) ) {
+                               const shared_file_mapping_np* nextEntry = &regions[entryIndex+1];
+                               if ( (nextEntry->sfm_init_prot & VM_PROT_ZF) != 0 ) {
+                                       uint64_t segOffset = nextEntry->sfm_address - entry->sfm_address;
+                                       dyld::log("%18s at 0x%08lX->0x%08lX (zerofill)\n",
+                                                       segName(segIndex), (uintptr_t)(segActualLoadAddress(segIndex) + segOffset), (uintptr_t)(segActualLoadAddress(segIndex) + segOffset + nextEntry->sfm_size - 1));
+                                       ++entryIndex;
+                               }
+                       }
+               }
+       }
+       
+       return r;
+}
+#endif // SPLIT_SEG_DYLIB_SUPPORT
+
+
+void ImageLoaderMachOClassic::mapSegmentsClassic(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context)
+{
+       // non-split segment libraries handled by super class
+       if ( !fIsSplitSeg )
+               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;
+       // if there is a problem, fall into case where we map file somewhere outside the shared region
+#endif
+
+#if SPLIT_SEG_DYLIB_SUPPORT
+       // support old split-seg dylibs by mapping them where ever we find space
+       if ( mapSplitSegDylibOutsideSharedRegion(fd, offsetInFat, lenInFat, fileLen, context) != 0 ) 
+#endif
+               throw "mapping error";
+}
+
+
+#if SPLIT_SEG_SHARED_REGION_SUPPORT    
+static int _shared_region_map_np(int fd, uint32_t count, const shared_file_mapping_np mappings[])
+{
+       return syscall(295, fd, count, mappings);
+}
+
+int
+ImageLoaderMachOClassic::mapSplitSegDylibInfoSharedRegion(int fd,
+                                         uint64_t offsetInFat,
+                                         uint64_t lenInFat,
+                                         uint64_t fileLen,
+                                         const LinkContext& context)
+{
+       // build table of segments to map
+       const unsigned int segmentCount = fSegmentsCount;
+       const unsigned int extraZeroFillEntries = getExtraZeroFillEntriesCount();
+       const unsigned int mappingTableCount = segmentCount+extraZeroFillEntries;
+       shared_file_mapping_np mappingTable[mappingTableCount];
+       initMappingTable(offsetInFat, mappingTable);
+
+       // try to map it in shared
+       int r = _shared_region_map_np(fd, mappingTableCount, mappingTable);
+       if ( 0 == r ) {
+               this->setNeverUnload();
+               if ( context.verboseMapping ) {
+                       dyld::log("dyld: Mapping split-seg shared %s\n", this->getPath());
+                       for(unsigned int segIndex=0,entryIndex=0; segIndex < segmentCount; ++segIndex, ++entryIndex){
+                               const shared_file_mapping_np* entry = &mappingTable[entryIndex];
+                               if ( (entry->sfm_init_prot & VM_PROT_ZF) == 0 ) 
+                                       dyld::log("%18s at 0x%08lX->0x%08lX\n",
+                                                         segName(segIndex), segActualLoadAddress(segIndex), segActualEndAddress(segIndex)-1);
+                               if ( entryIndex < (mappingTableCount-1) ) {
+                                       const shared_file_mapping_np* nextEntry = &mappingTable[entryIndex+1];
+                                       if ( (nextEntry->sfm_init_prot & VM_PROT_ZF) != 0 ) {
+                                               uint64_t segOffset = nextEntry->sfm_address - entry->sfm_address;
+                                               dyld::log("%18s at 0x%08lX->0x%08lX\n",
+                                                                 segName(segIndex), (uintptr_t)(segActualLoadAddress(segIndex) + segOffset), 
+                                                                 (uintptr_t)(segActualLoadAddress(segIndex) + segOffset + nextEntry->sfm_size - 1));
+                                               ++entryIndex;
+                                       }
+                               }
+                       }
+               }
+       }
+       return r;
+}
+
+#endif // SPLIT_SEG_SHARED_REGION_SUPPORT      
+
+// test if this image is re-exported through parent (the image that loaded this one)
+bool ImageLoaderMachOClassic::isSubframeworkOf(const LinkContext& context, const ImageLoader* parent) const
+{
+       if ( fInUmbrella ) {
+               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) {
+                       if (cmd->cmd == LC_SUB_FRAMEWORK) {
+                               const struct sub_framework_command* subf = (struct sub_framework_command*)cmd;
+                               const char* exportThruName = (char*)cmd + subf->umbrella.offset;
+                               // need to match LC_SUB_FRAMEWORK string against the leaf name of the install location of parent...
+                               const char* parentInstallPath = parent->getInstallPath();
+                               if ( parentInstallPath != NULL ) {
+                                       const char* lastSlash = strrchr(parentInstallPath, '/');
+                                       if ( lastSlash != NULL ) {
+                                               if ( strcmp(&lastSlash[1], exportThruName) == 0 )
+                                                       return true;
+                                               if ( context.imageSuffix != NULL ) {
+                                                       // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end
+                                                       char reexportAndSuffix[strlen(context.imageSuffix)+strlen(exportThruName)+1];
+                                                       strcpy(reexportAndSuffix, exportThruName);
+                                                       strcat(reexportAndSuffix, context.imageSuffix);
+                                                       if ( strcmp(&lastSlash[1], reexportAndSuffix) == 0 )
+                                                               return true;
+                                               }
+                                       }
+                               }
+                       }
+                       cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+               }
+       }
+       return false;
+}
+
+// test if child is re-exported 
+bool ImageLoaderMachOClassic::hasSubLibrary(const LinkContext& context, const ImageLoader* child) const
+{
+       if ( fHasSubLibraries ) {
+               // need to match LC_SUB_LIBRARY string against the leaf name (without extension) of the install location of child...
+               const char* childInstallPath = child->getInstallPath();
+               if ( childInstallPath != NULL ) {
+                       const char* lastSlash = strrchr(childInstallPath, '/');
+                       if ( lastSlash != NULL ) {
+                               const char* firstDot = strchr(lastSlash, '.');
+                               int len;
+                               if ( firstDot == NULL )
+                                       len = strlen(lastSlash);
+                               else
+                                       len = firstDot-lastSlash-1;
+                               char childLeafName[len+1];
+                               strncpy(childLeafName, &lastSlash[1], len);
+                               childLeafName[len] = '\0';
+                               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_SUB_LIBRARY:
+                                                       {
+                                                               const struct sub_library_command* lib = (struct sub_library_command*)cmd;
+                                                               const char* aSubLibName = (char*)cmd + lib->sub_library.offset;
+                                                               if ( strcmp(aSubLibName, childLeafName) == 0 )
+                                                                       return true;
+                                                               if ( context.imageSuffix != NULL ) {
+                                                                       // when DYLD_IMAGE_SUFFIX is used, childLeafName string needs imageSuffix removed from end
+                                                                       char aSubLibNameAndSuffix[strlen(context.imageSuffix)+strlen(aSubLibName)+1];
+                                                                       strcpy(aSubLibNameAndSuffix, aSubLibName);
+                                                                       strcat(aSubLibNameAndSuffix, context.imageSuffix);
+                                                                       if ( strcmp(aSubLibNameAndSuffix, childLeafName) == 0 )
+                                                                               return true;
+                                                               }
+                                                       }
+                                                       break;
+                                       }
+                                       cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+                               }
+                       }
+               }
+       }
+       if ( fHasSubUmbrella ) {
+               // need to match LC_SUB_UMBRELLA string against the leaf name of install location of child...
+               const char* childInstallPath = child->getInstallPath();
+               if ( childInstallPath != NULL ) {
+                       const char* lastSlash = strrchr(childInstallPath, '/');
+                       if ( lastSlash != NULL ) {
+                               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_SUB_UMBRELLA:
+                                                       {
+                                                               const struct sub_umbrella_command* um = (struct sub_umbrella_command*)cmd;
+                                                               const char* aSubUmbrellaName = (char*)cmd + um->sub_umbrella.offset;
+                                                               if ( strcmp(aSubUmbrellaName, &lastSlash[1]) == 0 )
+                                                                       return true;
+                                                               if ( context.imageSuffix != NULL ) {
+                                                                       // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end
+                                                                       char umbrellaAndSuffix[strlen(context.imageSuffix)+strlen(aSubUmbrellaName)+1];
+                                                                       strcpy(umbrellaAndSuffix, aSubUmbrellaName);
+                                                                       strcat(umbrellaAndSuffix, context.imageSuffix);
+                                                                       if ( strcmp(umbrellaAndSuffix, &lastSlash[1]) == 0 )
+                                                                               return true;
+                                                               }
+                                                       }
+                                                       break;
+                                       }
+                                       cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+                               }
+                       }
+               }
+       }
+       return false;
+}
+
+
+uintptr_t ImageLoaderMachOClassic::getFirstWritableSegmentAddress()
+{
+       // in split segment libraries r_address is offset from first writable segment
+       for(unsigned int i=0; i < fSegmentsCount; ++i) {
+               if ( segWriteable(i) ) 
+                       return segActualLoadAddress(i);
+       }
+       throw "no writable segment";
+}
+
+uintptr_t ImageLoaderMachOClassic::getRelocBase()
+{
+       // r_address is either an offset from the first segment address
+       // or from the first writable segment address
+#if __x86_64__
+       return getFirstWritableSegmentAddress();
+#else
+       if ( fIsSplitSeg )
+               return getFirstWritableSegmentAddress();
+       else
+               return segActualLoadAddress(0);
+#endif
+}
+
+
+#if __ppc__
+static inline void otherRelocsPPC(uintptr_t* locationToFix, uint8_t relocationType, uint16_t otherHalf, uintptr_t slide)
+{
+       // low 16 bits of 32-bit ppc instructions need fixing
+       struct ppcInstruction { uint16_t opcode; int16_t immediateValue; };
+       ppcInstruction* instruction = (ppcInstruction*)locationToFix;
+       //uint32_t before = *((uint32_t*)locationToFix);
+       switch ( relocationType )
+       {
+               case PPC_RELOC_LO16: 
+                       instruction->immediateValue = ((otherHalf << 16) | instruction->immediateValue) + slide;
+                       break;
+               case PPC_RELOC_HI16: 
+                       instruction->immediateValue = ((((instruction->immediateValue << 16) | otherHalf) + slide) >> 16);
+                       break;
+               case PPC_RELOC_HA16: 
+                       int16_t signedOtherHalf = (int16_t)(otherHalf & 0xffff);
+                       uint32_t temp = (instruction->immediateValue << 16) + signedOtherHalf + slide;
+                       if ( (temp & 0x00008000) != 0 )
+                               temp += 0x00008000;
+                       instruction->immediateValue = temp >> 16;
+       }
+       //uint32_t after = *((uint32_t*)locationToFix);
+       //dyld::log("dyld: ppc fixup %0p type %d from 0x%08X to 0x%08X\n", locationToFix, relocationType, before, after);
+}
+#endif
+
+#if PREBOUND_IMAGE_SUPPORT
+void ImageLoaderMachOClassic::resetPreboundLazyPointers(const LinkContext& context)
+{
+       // loop through all local (internal) relocation records looking for pre-bound-lazy-pointer values
+       const uintptr_t relocBase = this->getRelocBase();
+       register const uintptr_t slide = this->fSlide;
+       const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->locreloff]);
+       const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nlocrel];
+       for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
+               if ( (reloc->r_address & R_SCATTERED) != 0 ) {
+                       const struct scattered_relocation_info* sreloc = (struct scattered_relocation_info*)reloc;
+                       if (sreloc->r_length == RELOC_SIZE) {
+                               uintptr_t* locationToFix = (uintptr_t*)(sreloc->r_address + relocBase);
+                               switch(sreloc->r_type) {
+               #if __ppc__ 
+                                       case PPC_RELOC_PB_LA_PTR:
+                                               *locationToFix = sreloc->r_value + slide;
+                                               break;
+               #endif
+               #if __i386__
+                                       case GENERIC_RELOC_PB_LA_PTR:
+                                               *locationToFix = sreloc->r_value + slide;
+                                               break;
+               #endif
+               #if __arm__
+                                       case ARM_RELOC_PB_LA_PTR:
+                                               *locationToFix = sreloc->r_value + slide;
+                                               break;
+               #endif
+                               }
+                       }
+               }
+       }
+}
+#endif
+
+
+
+
+void ImageLoaderMachOClassic::rebase(const LinkContext& context)
+{
+       register const uintptr_t slide = this->fSlide;
+       const uintptr_t relocBase = this->getRelocBase();
+       
+       // prefetch any LINKEDIT pages needed
+       if ( !context.preFetchDisabled && !this->isPrebindable())
+               this->prefetchLINKEDIT(context);
+       
+       // loop through all local (internal) relocation records
+       const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->locreloff]);
+       const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nlocrel];
+       for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
+               try {
+       #if LINKEDIT_USAGE_DEBUG
+                       noteAccessedLinkEditAddress(reloc);
+       #endif
+               #if __x86_64__
+                       // only one kind of local relocation supported for x86_64
+                       if ( reloc->r_length != 3 ) 
+                               throw "bad local relocation length";
+                       if ( reloc->r_type != X86_64_RELOC_UNSIGNED ) 
+                               throw "unknown local relocation type";
+                       if ( reloc->r_pcrel != 0 ) 
+                               throw "bad local relocation pc_rel";
+                       if ( reloc->r_extern != 0 ) 
+                               throw "extern relocation found with local relocations";
+                       *((uintptr_t*)(reloc->r_address + relocBase)) += slide;
+               #else   
+                       if ( (reloc->r_address & R_SCATTERED) == 0 ) {
+                               if ( reloc->r_symbolnum == R_ABS ) {
+                                       // ignore absolute relocations
+                               }
+                               else if (reloc->r_length == RELOC_SIZE) {
+                                       switch(reloc->r_type) {
+                                               case GENERIC_RELOC_VANILLA:
+                                                       *((uintptr_t*)(reloc->r_address + relocBase)) += slide;
+                                                       break;
+                       #if __ppc__
+                                               case PPC_RELOC_HI16: 
+                                               case PPC_RELOC_LO16: 
+                                               case PPC_RELOC_HA16: 
+                                                       // some tools leave object file relocations in linked images
+                                                       otherRelocsPPC((uintptr_t*)(reloc->r_address + relocBase), reloc->r_type, reloc[1].r_address, slide);
+                                                       ++reloc; // these relocations come in pairs, skip next
+                                                       break;
+                       #endif
+                                               default:
+                                                       throw "unknown local relocation type";
+                                       }
+                               }
+                               else {
+                                       throw "bad local relocation length";
+                               }
+                       }
+                       else {
+                               const struct scattered_relocation_info* sreloc = (struct scattered_relocation_info*)reloc;
+                               if (sreloc->r_length == RELOC_SIZE) {
+                                       uintptr_t* locationToFix = (uintptr_t*)(sreloc->r_address + relocBase);
+                                       switch(sreloc->r_type) {
+                                               case GENERIC_RELOC_VANILLA:
+                                                       *locationToFix += slide;
+                                                       break;
+                       #if __ppc__
+                                               case PPC_RELOC_HI16: 
+                                               case PPC_RELOC_LO16: 
+                                               case PPC_RELOC_HA16: 
+                                                       // Metrowerks compiler sometimes leaves object file relocations in linked images???
+                                                       ++reloc; // these relocations come in pairs, get next one
+                                                       otherRelocsPPC(locationToFix, sreloc->r_type, reloc->r_address, slide);
+                                                       break;
+                                               case PPC_RELOC_PB_LA_PTR:
+                                                       // do nothing
+                                                       break;
+                       #elif __ppc64__
+                                               case PPC_RELOC_PB_LA_PTR:
+                                                       // needed for compatibility with ppc64 binaries built with the first ld64
+                                                       // which used PPC_RELOC_PB_LA_PTR relocs instead of GENERIC_RELOC_VANILLA for lazy pointers
+                                                       *locationToFix += slide;
+                                                       break;
+                       #elif __i386__
+                                               case GENERIC_RELOC_PB_LA_PTR:
+                                                       // do nothing
+                                                       break;
+                       #elif __arm__
+                                               case ARM_RELOC_PB_LA_PTR:
+                                                       // do nothing
+                                                       break;
+                       #endif
+                                               default:
+                                                       throw "unknown local scattered relocation type";
+                                       }
+                               }
+                               else {
+                                       throw "bad local scattered relocation length";
+                               }
+                       }
+               #endif // x86_64
+               }
+               catch (const char* msg) {
+                       const uint8_t* r = (uint8_t*)reloc;
+                       dyld::throwf("%s in %s. reloc record at %p: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",
+                               msg, this->getPath(), reloc, r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]);
+               }
+       }
+       
+       // update stats
+       fgTotalRebaseFixups += fDynamicInfo->nlocrel;
+}
+
+
+
+const struct macho_nlist* ImageLoaderMachOClassic::binarySearchWithToc(const char* key, const char stringPool[], const struct macho_nlist symbols[], 
+                                                                                               const struct dylib_table_of_contents toc[], uint32_t symbolCount, uint32_t hintIndex) const
+{
+       int32_t high = symbolCount-1;
+       int32_t mid = hintIndex;
+       
+       // handle out of range hint
+       if ( mid >= (int32_t)symbolCount )
+               mid = symbolCount/2;
+       ++ImageLoaderMachO::fgSymbolTableBinarySearchs;
+       ++fgTotalBindImageSearches;     
+
+       //dyld::log("dyld: binarySearchWithToc for %s in %s\n", key, this->getShortName());
+
+       for (int32_t low = 0; low <= high; mid = (low+high)/2) {
+               const uint32_t index = toc[mid].symbol_index;
+               const struct macho_nlist* pivot = &symbols[index];
+               const char* pivotStr = &stringPool[pivot->n_un.n_strx];
+#if LINKEDIT_USAGE_DEBUG
+               noteAccessedLinkEditAddress(&toc[mid]);
+               noteAccessedLinkEditAddress(pivot);
+               noteAccessedLinkEditAddress(pivotStr);
+#endif
+               int cmp = astrcmp(key, pivotStr);
+               if ( cmp == 0 )
+                       return pivot;
+               if ( cmp > 0 ) {
+                       // key > pivot 
+                       low = mid + 1;
+               }
+               else {
+                       // key < pivot 
+                       high = mid - 1;
+               }
+       }
+       return NULL;
+}
+
+const struct macho_nlist* ImageLoaderMachOClassic::binarySearch(const char* key, const char stringPool[], const struct macho_nlist symbols[], uint32_t symbolCount) const
+{
+       // update stats
+       ++fgTotalBindImageSearches;     
+       ++ImageLoaderMachO::fgSymbolTableBinarySearchs;
+       
+       //dyld::log("dyld: binarySearch for %s in %s, stringpool=%p, symbols=%p, symbolCount=%u\n", 
+       //                              key, this->getShortName(), stringPool, symbols, symbolCount);
+
+       const struct macho_nlist* base = symbols;
+       for (uint32_t n = symbolCount; n > 0; n /= 2) {
+               const struct macho_nlist* pivot = &base[n/2];
+               const char* pivotStr = &stringPool[pivot->n_un.n_strx];
+#if LINKEDIT_USAGE_DEBUG
+               noteAccessedLinkEditAddress(pivot);
+               noteAccessedLinkEditAddress(pivotStr);
+#endif
+               int cmp = astrcmp(key, pivotStr);
+               if ( cmp == 0 )
+                       return pivot;
+               if ( cmp > 0 ) {
+                       // key > pivot 
+                       // move base to symbol after pivot
+                       base = &pivot[1];
+                       --n; 
+               }
+               else {
+                       // key < pivot 
+                       // keep same base
+               }
+       }
+       return NULL;
+}
+
+
+const ImageLoader::Symbol* ImageLoaderMachOClassic::findExportedSymbol(const char* name, const ImageLoader** foundIn) const
+{
+       const struct macho_nlist* sym = NULL;
+       if ( fDynamicInfo->tocoff == 0 )
+               sym = binarySearch(name, fStrings, &fSymbolTable[fDynamicInfo->iextdefsym], fDynamicInfo->nextdefsym);
+       else 
+               sym = binarySearchWithToc(name, fStrings, fSymbolTable, (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff], 
+                                                                               fDynamicInfo->ntoc, fDynamicInfo->nextdefsym);
+       if ( sym != NULL ) {
+               if ( foundIn != NULL )
+                       *foundIn = (ImageLoader*)this;          
+               return (const Symbol*)sym;
+       }
+       return NULL;
+}
+
+
+
+bool ImageLoaderMachOClassic::containsSymbol(const void* addr) const
+{
+       return ( (fSymbolTable <= addr) && (addr < fStrings) );
+}
+
+
+uintptr_t ImageLoaderMachOClassic::exportedSymbolAddress(const Symbol* symbol) const
+{
+       const struct macho_nlist* sym = (macho_nlist*)symbol;
+       uintptr_t result = sym->n_value + fSlide;
+       #if __arm__
+               // processor assumes code address with low bit set is thumb
+               if (sym->n_desc & N_ARM_THUMB_DEF)
+                       result |= 1;
+       #endif
+       return result;
+}
+
+bool ImageLoaderMachOClassic::exportedSymbolIsWeakDefintion(const Symbol* symbol) const
+{
+       const struct macho_nlist* nlistSym = (const struct macho_nlist*)symbol;
+       return ( (nlistSym->n_desc & N_WEAK_DEF) != 0 );
+}
+
+const char* ImageLoaderMachOClassic::exportedSymbolName(const Symbol* symbol) const
+{
+       const struct macho_nlist* nlistSym = (const struct macho_nlist*)symbol;
+       return &fStrings[nlistSym->n_un.n_strx];
+}
+
+unsigned int ImageLoaderMachOClassic::exportedSymbolCount() const
+{
+       return fDynamicInfo->nextdefsym;
+}
+
+const ImageLoader::Symbol* ImageLoaderMachOClassic::exportedSymbolIndexed(unsigned int index) const
+{
+       if ( index < fDynamicInfo->nextdefsym ) {
+               const struct macho_nlist* sym = &fSymbolTable[fDynamicInfo->iextdefsym + index];
+               return (const ImageLoader::Symbol*)sym;
+       }
+       return NULL;
+}
+
+unsigned int ImageLoaderMachOClassic::importedSymbolCount() const
+{
+       return fDynamicInfo->nundefsym;
+}
+
+const ImageLoader::Symbol* ImageLoaderMachOClassic::importedSymbolIndexed(unsigned int index) const
+{
+       if ( index < fDynamicInfo->nundefsym ) {
+               const struct macho_nlist* sym = &fSymbolTable[fDynamicInfo->iundefsym + index];
+               return (const ImageLoader::Symbol*)sym;
+       }
+       return NULL;
+}      
+
+const char* ImageLoaderMachOClassic::importedSymbolName(const Symbol* symbol) const
+{
+       const struct macho_nlist* nlistSym = (const struct macho_nlist*)symbol;
+       return &fStrings[nlistSym->n_un.n_strx];
+}
+
+
+
+bool ImageLoaderMachOClassic::symbolIsWeakDefinition(const struct macho_nlist* symbol)
+{
+       // if a define and weak ==> coalesced 
+       if ( ((symbol->n_type & N_TYPE) == N_SECT) && ((symbol->n_desc & N_WEAK_DEF) != 0) ) 
+               return true;
+       
+       // regular symbol
+       return false;
+}
+
+bool ImageLoaderMachOClassic::symbolIsWeakReference(const struct macho_nlist* symbol)
+{
+       // if an undefine and not referencing a weak symbol ==> coalesced
+       if ( ((symbol->n_type & N_TYPE) != N_SECT) && ((symbol->n_desc & N_REF_TO_WEAK) != 0) )
+               return true;
+       
+       // regular symbol
+       return false;
+}
+
+uintptr_t ImageLoaderMachOClassic::getSymbolAddress(const macho_nlist* sym, const LinkContext& context) const
+{
+       return ImageLoaderMachO::getSymbolAddress((Symbol*)sym, this, context);
+}
+
+uintptr_t ImageLoaderMachOClassic::resolveUndefined(const LinkContext& context, const struct macho_nlist* undefinedSymbol, 
+                                                                               bool twoLevel, bool dontCoalesce, const ImageLoader** foundIn)
+{
+       ++fgTotalBindSymbolsResolved;
+       const char* symbolName = &fStrings[undefinedSymbol->n_un.n_strx];
+
+#if LINKEDIT_USAGE_DEBUG
+       noteAccessedLinkEditAddress(undefinedSymbol);
+       noteAccessedLinkEditAddress(symbolName);
+#endif
+       if ( context.bindFlat || !twoLevel ) {
+               // 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);
+                       *foundIn = this;
+                       return addr;
+               }
+               const Symbol* sym;
+               if ( context.flatExportFinder(symbolName, &sym, foundIn) ) {
+                       if ( (*foundIn != this) && !(*foundIn)->neverUnload() )
+                                       this->addDynamicReference(*foundIn);
+                       return (*foundIn)->getExportedSymbolAddress(sym, context, this);
+               }
+               // 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->findExportedSymbol(symbolName, foundIn);
+                       if ( sym != NULL )
+                               return (*foundIn)->getExportedSymbolAddress(sym, context, this);
+               }
+               if ( (undefinedSymbol->n_desc & N_WEAK_REF) != 0 ) {
+                       // definition can't be found anywhere
+                       // if reference is weak_import, then it is ok, just return 0
+                       return 0;
+               }
+               throwSymbolNotFound(symbolName, this->getPath(), "flat namespace");
+       }
+       else {
+               // symbol requires searching images with coalesced symbols (not done during prebinding)
+               if ( !context.prebinding && !dontCoalesce && (symbolIsWeakReference(undefinedSymbol) || symbolIsWeakDefinition(undefinedSymbol)) ) {
+                       const Symbol* sym;
+                       if ( context.coalescedExportFinder(symbolName, &sym, foundIn) ) {
+                               if ( (*foundIn != this) && !(*foundIn)->neverUnload() )
+                                       this->addDynamicReference(*foundIn);
+                               return (*foundIn)->getExportedSymbolAddress(sym, context, this);
+                       }
+                       //throwSymbolNotFound(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);
+                       *foundIn = this;
+                       return addr;
+               }
+
+               // two level lookup
+               ImageLoader* target = NULL;
+               uint8_t ord = GET_LIBRARY_ORDINAL(undefinedSymbol->n_desc);
+               if ( ord == EXECUTABLE_ORDINAL ) {
+                       target = context.mainExecutable;
+               }
+               else if ( ord == SELF_LIBRARY_ORDINAL ) {
+                       target = this;
+               }
+               else if ( ord == DYNAMIC_LOOKUP_ORDINAL ) {
+                       // rnielsen: HACKHACK
+                       // flat lookup
+                       const Symbol* sym;
+                       if ( context.flatExportFinder(symbolName, &sym, foundIn) )
+                               return (*foundIn)->getExportedSymbolAddress(sym, context, this);
+                       // no image has exports this symbol
+                       // report error
+                       context.undefinedHandler(symbolName);
+                       // try looking again
+                       if ( context.flatExportFinder(symbolName, &sym, foundIn) )
+                               return (*foundIn)->getExportedSymbolAddress(sym, context, this);
+                       
+                       throwSymbolNotFound(symbolName, this->getPath(), "dynamic lookup");
+               }
+               else if ( ord <= libraryCount() ) {
+                       target = libImage(ord-1);
+                       if ( target == NULL ) {
+                               // if target library not loaded and reference is weak or library is weak return 0
+                               return 0;
+                       }
+               }
+               else {
+                       dyld::throwf("bad mach-o binary, library ordinal (%u) too big (max %u) for symbol %s in %s",
+                               ord, libraryCount(), symbolName, this->getPath());
+               }
+               
+               if ( target == NULL ) {
+                       //dyld::log("resolveUndefined(%s) in %s\n", symbolName, this->getPath());
+                       throw "symbol not found";
+               }
+                               
+               const Symbol* sym = target->findExportedSymbol(symbolName, true, foundIn);
+               if ( sym!= NULL ) {
+                       return (*foundIn)->getExportedSymbolAddress(sym, context, this);
+               }
+               else if ( (undefinedSymbol->n_type & N_PEXT) != 0 ) {
+                       // don't know why the static linker did not eliminate the internal reference to a private extern definition
+                       *foundIn = this;
+                       return this->getSymbolAddress(undefinedSymbol, context);
+               }
+               else if ( (undefinedSymbol->n_desc & N_WEAK_REF) != 0 ) {
+                       // if definition not found and reference is weak return 0
+                       return 0;
+               }
+               
+               // nowhere to be found
+               throwSymbolNotFound(symbolName, this->getPath(), target->getPath());
+       }
+}
+
+
+
+// returns if 'addr' is within the address range of section 'sectionIndex'
+// fSlide is not used.  'addr' is assumed to be a prebound address in this image 
+bool ImageLoaderMachOClassic::isAddrInSection(uintptr_t addr, uint8_t sectionIndex)
+{
+       uint8_t currentSectionIndex = 1;
+       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) {
+               if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
+                       const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
+                       if ( (currentSectionIndex <= sectionIndex) && (sectionIndex < currentSectionIndex+seg->nsects) ) {
+                               // 'sectionIndex' is in this segment, get section info
+                               const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
+                               const struct macho_section* const section = &sectionsStart[sectionIndex-currentSectionIndex];
+                               return ( (section->addr <= addr) && (addr < section->addr+section->size) );
+                       }
+                       else {
+                               // 'sectionIndex' not in this segment, skip to next segment
+                               currentSectionIndex += seg->nsects;
+                       }
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+       }
+       
+       return false;
+}
+
+void ImageLoaderMachOClassic::doBindExternalRelocations(const LinkContext& context)
+{
+       const uintptr_t relocBase = this->getRelocBase();
+       const bool twoLevel = this->usesTwoLevelNameSpace();
+       const bool prebound = this->isPrebindable();
+       
+#if TEXT_RELOC_SUPPORT
+       // if there are __TEXT fixups, temporarily make __TEXT writable
+       if ( fTextSegmentBinds ) 
+               this->makeTextSegmentWritable(context, true);
+#endif
+       // cache last lookup
+       const struct macho_nlist*       lastUndefinedSymbol = NULL;
+       uintptr_t                                       symbolAddr = 0;
+       const ImageLoader*                      image = NULL;
+       
+       // loop through all external relocation records and bind each
+       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:
+                                       {
+                                               const struct macho_nlist* undefinedSymbol = &fSymbolTable[reloc->r_symbolnum];
+                                               uintptr_t* location = ((uintptr_t*)(reloc->r_address + relocBase));
+                                               uintptr_t value = *location;
+                                               bool symbolAddrCached = true;
+                                       #if __i386__
+                                               if ( reloc->r_pcrel ) {
+                                                       value += (uintptr_t)location + 4 - fSlide;
+                                               }
+                                       #endif
+                                               if ( prebound ) {
+                                                       // we are doing relocations, so prebinding was not usable
+                                                       // in a prebound executable, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound
+                                                       // so, subtracting that gives the initial displacement which we need to add to the newly found symbol address
+                                                       // if mach-o relocation structs had an "addend" field this complication would not be necessary.
+                                                       if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_WEAK_DEF) != 0) ) {
+                                                               // weak symbols need special casing, since *location may have been prebound to a definition in another image.
+                                                               // If *location is currently prebound to somewhere in the same section as the weak definition, we assume 
+                                                               // that we can subtract off the weak symbol address to get the addend.
+                                                               // If prebound elsewhere, we've lost the addend and have to assume it is zero.
+                                                               // The prebinding to elsewhere only happens with 10.4+ update_prebinding which only operates on a small set of Apple dylibs
+                                                               if ( (value == undefinedSymbol->n_value) || this->isAddrInSection(value, undefinedSymbol->n_sect) ) {
+                                                                       value -= undefinedSymbol->n_value;
+                        #if __arm__
+                                    // if weak and thumb subtract off extra thumb bit
+                                    if ( (undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0 )
+                                        value -= 1;
+                        #endif
+                                                               }
+                                                               else
+                                                                       value = 0;
+                                                       } 
+                                       #if __arm__
+                                                       else if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0) ) {
+                                                               // it was prebound to a defined symbol for thumb code in the same linkage unit
+                                                               // we need to subtract off one to get real addend
+                                                               value -= (undefinedSymbol->n_value+1);
+                                                       }
+                                       #endif
+                                                       else {
+                                                               // is undefined or non-weak symbol, so do subtraction to get addend
+                                                               value -= undefinedSymbol->n_value;
+                                                       }
+                                               }
+                                               // if undefinedSymbol is same as last time, then symbolAddr and image will resolve to the same too
+                                               if ( undefinedSymbol != lastUndefinedSymbol ) {
+                                                       bool dontCoalesce = true;
+                                                       if ( symbolIsWeakReference(undefinedSymbol) ) { 
+                                                               // when weakbind() is run on a classic mach-o encoding, it won't try
+                                                               // to coalesce N_REF_TO_WEAK symbols because they are not in the sorted
+                                                               // range of global symbols.  To handle that case we do the coalesing now.
+                                                               dontCoalesce = false;
+                                                       }
+                                                       symbolAddr = this->resolveUndefined(context, undefinedSymbol, twoLevel, dontCoalesce, &image);
+                                                       lastUndefinedSymbol = undefinedSymbol;
+                                                       symbolAddrCached = false;
+                                               }
+                                               if ( context.verboseBind ) {
+                                                       const char *path = NULL;
+                                                       if ( image != NULL ) {
+                                                               path = image->getShortName();
+                                                       }
+                                                       const char* cachedString = "(cached)";
+                                                       if ( !symbolAddrCached ) 
+                                                               cachedString = "";
+                                                       if ( value == 0 ) {
+                                                               dyld::log("dyld: bind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX%s\n",
+                                                                               this->getShortName(), (uintptr_t)location,
+                                                                               path, &fStrings[undefinedSymbol->n_un.n_strx], (uintptr_t)location, symbolAddr, cachedString);
+                                                       }
+                                                       else {
+                                                               dyld::log("dyld: bind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX%s + %ld\n",
+                                                                               this->getShortName(), (uintptr_t)location,
+                                                                               path, &fStrings[undefinedSymbol->n_un.n_strx], (uintptr_t)location, symbolAddr, cachedString, value);
+                                                       }
+                                               }
+                                               value += symbolAddr;
+                                       #if __i386__
+                                               if ( reloc->r_pcrel ) {
+                                                       *location = value - ((uintptr_t)location + 4);
+                                               }
+                                               else {
+                                                       // don't dirty page if prebound value was correct
+                                                       if ( !prebound || (*location != value) )
+                                                               *location = value; 
+                                               }
+                                       #else
+                                               // don't dirty page if prebound value was correct
+                                               if ( !prebound || (*location != value) )
+                                                       *location = value; 
+                                       #endif
+                                               // update stats
+                                               ++fgTotalBindFixups;
+                                       }
+                                       break;
+                               default:
+                                       throw "unknown external relocation type";
+                       }
+               }
+               else {
+                       throw "bad external relocation length";
+               }
+       }
+       
+#if TEXT_RELOC_SUPPORT
+       // if there were __TEXT fixups, restore write protection
+       if ( fTextSegmentBinds ) {
+               this->makeTextSegmentWritable(context, true);
+       }
+#endif
+}
+
+
+
+uintptr_t ImageLoaderMachOClassic::bindIndirectSymbol(uintptr_t* ptrToBind, const struct macho_section* sect, const char* symbolName, uintptr_t targetAddr, const ImageLoader* targetImage, const LinkContext& context)
+{
+       if ( context.verboseBind ) {
+               const char* path = NULL;
+               if ( targetImage != NULL )
+                       path = targetImage->getShortName();
+               dyld::log("dyld: bind indirect sym: %s:%s$%s = %s:%s, *0x%08lx = 0x%08lx\n",
+                               this->getShortName(), symbolName, (((sect->flags & SECTION_TYPE)==S_NON_LAZY_SYMBOL_POINTERS) ? "non_lazy_ptr" : "lazy_ptr"),
+                               ((path != NULL) ? path : "<weak_import-not-found>"), symbolName, (uintptr_t)ptrToBind, targetAddr);
+       }
+       if ( context.bindingHandler != NULL ) {
+               const char* path = NULL;
+               if ( targetImage != NULL )
+                       path = targetImage->getShortName();
+               targetAddr = (uintptr_t)context.bindingHandler(path, symbolName, (void *)targetAddr);
+       }
+#if __i386__
+       // i386 has special self-modifying stubs that change from "CALL rel32" to "JMP rel32"
+       if ( ((sect->flags & SECTION_TYPE) == S_SYMBOL_STUBS) && ((sect->flags & S_ATTR_SELF_MODIFYING_CODE) != 0) && (sect->reserved2 == 5) ) {
+               uint32_t rel32 = targetAddr - (((uint32_t)ptrToBind)+5);
+               // re-write instruction in a thread-safe manner
+               // use 8-byte compare-and-swap to alter 5-byte jump table entries
+               // loop is required in case the extra three bytes that cover the next entry are altered by another thread
+               bool done = false;
+               while ( !done ) {
+                       volatile int64_t* jumpPtr = (int64_t*)ptrToBind;
+                       int pad = 0;
+                       // By default the three extra bytes swapped follow the 5-byte JMP.
+                       // But, if the 5-byte jump is up against the end of the __IMPORT segment
+                       // We don't want to access bytes off the end of the segment, so we shift
+                       // the extra bytes to precede the 5-byte JMP.
+                       if ( (((uint32_t)ptrToBind + 8) & 0x00000FFC) == 0x00000000 ) {
+                               jumpPtr = (int64_t*)((uint32_t)ptrToBind - 3);
+                               pad = 3;
+                       }
+                       int64_t oldEntry = *jumpPtr;
+                       union {
+                               int64_t int64;
+                               uint8_t bytes[8];
+                       } newEntry;
+                       newEntry.int64 = oldEntry;
+                       newEntry.bytes[pad+0] = 0xE9; // JMP rel32
+                       newEntry.bytes[pad+1] = rel32 & 0xFF;
+                       newEntry.bytes[pad+2] = (rel32 >> 8) & 0xFF;
+                       newEntry.bytes[pad+3] = (rel32 >> 16) & 0xFF;
+                       newEntry.bytes[pad+4] = (rel32 >> 24) & 0xFF;
+                       done = OSAtomicCompareAndSwap64Barrier(oldEntry, newEntry.int64, (int64_t*)jumpPtr);
+               }
+       }
+       else
+#endif
+       *ptrToBind = targetAddr;
+       return targetAddr;
+}
+
+uintptr_t ImageLoaderMachOClassic::doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context)
+{
+       throw "compressed LINKEDIT lazy binder called with classic LINKEDIT";
+}
+
+uintptr_t ImageLoaderMachOClassic::doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context)
+{
+       // scan for all lazy-pointer sections
+       const bool twoLevel = this->usesTwoLevelNameSpace();
+       const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
+       const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
+       const struct load_command* cmd = cmds;
+       const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff];
+       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;
+                                               uint32_t symbolIndex = INDIRECT_SYMBOL_LOCAL;
+                                               if ( type == S_LAZY_SYMBOL_POINTERS ) {
+                                                       const uint32_t pointerCount = sect->size / sizeof(uintptr_t);
+                                                       uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + fSlide);
+                                                       if ( (lazyPointer >= symbolPointers) && (lazyPointer < &symbolPointers[pointerCount]) ) {
+                                                               const uint32_t indirectTableOffset = sect->reserved1;
+                                                               const uint32_t lazyIndex = lazyPointer - symbolPointers;
+                                                               symbolIndex = indirectTable[indirectTableOffset + lazyIndex];
+                                                       }
+                                               }
+                                       #if __i386__
+                                               else if ( (type == S_SYMBOL_STUBS) && (sect->flags & S_ATTR_SELF_MODIFYING_CODE) && (sect->reserved2 == 5) ) {
+                                                       // 5 bytes stubs on i386 are new "fast stubs"
+                                                       uint8_t* const jmpTableBase = (uint8_t*)(sect->addr + fSlide);
+                                                       uint8_t* const jmpTableEnd = jmpTableBase + sect->size;
+                                                       // initial CALL instruction in jump table leaves pointer to next entry, so back up
+                                                       uint8_t* const jmpTableEntryToPatch = ((uint8_t*)lazyPointer) - 5;  
+                                                       lazyPointer = (uintptr_t*)jmpTableEntryToPatch; 
+                                                       if ( (jmpTableEntryToPatch >= jmpTableBase) && (jmpTableEntryToPatch < jmpTableEnd) ) {
+                                                               const uint32_t indirectTableOffset = sect->reserved1;
+                                                               const uint32_t entryIndex = (jmpTableEntryToPatch - jmpTableBase)/5;
+                                                               symbolIndex = indirectTable[indirectTableOffset + entryIndex];
+                                                       }
+                                               }
+                                       #endif
+                                               if ( symbolIndex != INDIRECT_SYMBOL_ABS && symbolIndex != INDIRECT_SYMBOL_LOCAL ) {
+                                                       const char* symbolName = &fStrings[fSymbolTable[symbolIndex].n_un.n_strx];
+                                                       const ImageLoader* image = NULL;
+                                                       uintptr_t symbolAddr = this->resolveUndefined(context, &fSymbolTable[symbolIndex], twoLevel, false, &image);
+                                                       symbolAddr = this->bindIndirectSymbol(lazyPointer, sect, symbolName, symbolAddr, image,  context);
+                                                       ++fgTotalLazyBindFixups;
+                                                       return symbolAddr;
+                                               }
+                                       }
+                               }
+                               break;
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+       }
+       dyld::throwf("lazy pointer not found at address %p in image %s", lazyPointer, this->getPath());
+}
+
+
+
+void ImageLoaderMachOClassic::initializeCoalIterator(CoalIterator& it, unsigned int loadOrder)
+{
+       it.image = this;
+       it.symbolName = " ";
+       it.loadOrder = loadOrder;
+       it.weakSymbol = false;
+       it.symbolMatches = false;
+       it.done = false;
+       it.type = 0; 
+       if ( fDynamicInfo->tocoff != 0 ) {
+               it.curIndex = 0;
+               it.endIndex = fDynamicInfo->ntoc;
+       }
+       else {
+               it.curIndex = 0;
+               it.endIndex = fDynamicInfo->nextdefsym;
+       }
+}
+
+
+bool ImageLoaderMachOClassic::incrementCoalIterator(CoalIterator& it)
+{
+       if ( it.done )
+               return false;
+               
+       if ( fDynamicInfo->tocoff != 0 ) {
+               if ( it.curIndex >= fDynamicInfo->ntoc ) {
+                       it.done = true;
+                       it.symbolName = "~~~";
+                       return true;
+               }
+               else {
+                       const dylib_table_of_contents* toc = (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff];
+                       const uint32_t index = toc[it.curIndex].symbol_index;
+                       const struct macho_nlist* sym = &fSymbolTable[index];
+                       const char* symStr = &fStrings[sym->n_un.n_strx];
+                       it.symbolName = symStr;
+                       it.weakSymbol = (sym->n_desc & N_WEAK_DEF);
+                       it.symbolMatches = false;
+                       it.type = 0; // clear flag that says we applied updates for this symbol
+                       //dyld::log("incrementCoalIterator() curIndex=%ld, symbolName=%s in %s\n", it.curIndex, symStr, this->getPath());
+                       it.curIndex++;
+                       return false;
+               }
+       }
+       else {
+               if ( it.curIndex >= fDynamicInfo->nextdefsym ) {
+                       it.done = true;
+                       it.symbolName = "~~~";
+                       return true;
+               }
+               else {
+                       const struct macho_nlist* sym = &fSymbolTable[fDynamicInfo->iextdefsym+it.curIndex];
+                       const char* symStr = &fStrings[sym->n_un.n_strx];
+                       it.symbolName = symStr;
+                       it.weakSymbol = (sym->n_desc & N_WEAK_DEF);
+                       it.symbolMatches = false;
+                       it.type = 0; // clear flag that says we applied updates for this symbol
+                       //dyld::log("incrementCoalIterator() curIndex=%ld, symbolName=%s in %s\n", it.curIndex, symStr, this->getPath());
+                       it.curIndex++;
+                       return false;
+               }
+       }       
+       
+       return false;
+}
+
+uintptr_t ImageLoaderMachOClassic::getAddressCoalIterator(CoalIterator& it, const LinkContext& context)
+{
+       uint32_t symbol_index = 0;
+       if ( fDynamicInfo->tocoff != 0 ) {
+               const dylib_table_of_contents* toc = (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff];
+               symbol_index = toc[it.curIndex-1].symbol_index;
+       }
+       else {
+               symbol_index = fDynamicInfo->iextdefsym+it.curIndex-1;
+       }       
+       const struct macho_nlist* sym = &fSymbolTable[symbol_index];
+       //dyld::log("getAddressCoalIterator() => 0x%llX, %s symbol_index=%d, in %s\n", (uint64_t)(sym->n_value + fSlide), &fStrings[sym->n_un.n_strx], symbol_index, this->getPath());
+       return sym->n_value + fSlide;
+}
+
+
+void ImageLoaderMachOClassic::updateUsesCoalIterator(CoalIterator& it, uintptr_t value, ImageLoader* targetImage, const LinkContext& context)
+{
+       // flat_namespace images with classic LINKEDIT do not need late coalescing.
+       // They still need to be iterated becuase they may implement
+       // something needed by other coalescing images.
+       // But they need no updating because during the bind phase every symbol lookup is a full scan.
+       if ( !this->usesTwoLevelNameSpace() )
+               return;
+               
+       // <rdar://problem/6570879> weak binding done too early with inserted libraries
+       if ( this->getState() < dyld_image_state_bound  )
+               return;
+
+       uint32_t symbol_index = 0;
+       if ( fDynamicInfo->tocoff != 0 ) {
+               const dylib_table_of_contents* toc = (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff];
+               symbol_index = toc[it.curIndex-1].symbol_index;
+       }
+       else {
+               symbol_index = fDynamicInfo->iextdefsym+it.curIndex-1;
+       }       
+
+       // if this image's copy of the symbol is not a weak definition nor a weak reference then nothing to coalesce here
+       if ( !symbolIsWeakReference(&fSymbolTable[symbol_index]) && !symbolIsWeakDefinition(&fSymbolTable[symbol_index]) ) {
+               return;
+       }
+
+       // <rdar://problem/6555720> malformed dylib with duplicate weak symbols causes re-binding
+       if ( it.type ) 
+               return;
+
+       bool boundSomething = false;
+       // scan external relocations for uses of symbol_index
+       const uintptr_t relocBase = this->getRelocBase();
+       const bool prebound = this->isPrebindable();
+       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_symbolnum == symbol_index ) {
+                       //dyld::log("found external reloc using symbol_index=%d in %s\n",symbol_index, this->getPath());
+                       const struct macho_nlist* undefinedSymbol = &fSymbolTable[reloc->r_symbolnum];
+                       const char* symbolName = &fStrings[undefinedSymbol->n_un.n_strx];
+                       uintptr_t* location = ((uintptr_t*)(reloc->r_address + relocBase));
+                       const uintptr_t initialValue = *location;
+                       uintptr_t addend = 0;
+                       if ( prebound ) {
+                               // we are doing relocations, so prebinding was not usable
+                               // in a prebound executable, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound
+                               // so, subtracting that gives the initial displacement which we need to add to the newly found symbol address
+                               // if mach-o relocation structs had an "addend" field this complication would not be necessary.
+                               if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_WEAK_DEF) != 0) ) {
+                                       // weak symbols need special casing, since *location may have been prebound to a definition in another image.
+                                       // If *location is currently prebound to somewhere in the same section as the weak definition, we assume 
+                                       // that we can subtract off the weak symbol address to get the addend.
+                                       // If prebound elsewhere, we've lost the addend and have to assume it is zero.
+                                       // The prebinding to elsewhere only happens with 10.4+ update_prebinding which only operates on a small set of Apple dylibs
+                                       if ( (initialValue == undefinedSymbol->n_value) || this->isAddrInSection(initialValue, undefinedSymbol->n_sect) ) {
+                                               addend = initialValue - undefinedSymbol->n_value;
+                       #if __arm__
+                                               // if weak and thumb subtract off extra thumb bit
+                                               if ( (undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0 )
+                                                       addend += 1;
+                       #endif
+                                       }
+                               } 
+               #if __arm__
+                               else if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0) ) {
+                                       // it was prebound to a defined symbol for thumb code in the same linkage unit
+                                       // we need to subtract off one to get real addend
+                                       addend = initialValue - (undefinedSymbol->n_value+1);
+                               }
+               #endif
+                               else {
+                                       // is undefined or non-weak symbol, so do subtraction to get addend
+                                       addend = initialValue - undefinedSymbol->n_value;
+                               }
+                       }
+                       else {
+                               // non-prebound case
+                               if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_WEAK_DEF) != 0) ) {
+                                       // if target is weak-def in same linkage unit, then bind phase has already set initialValue 
+                                       // 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);
+                               }
+                               else {
+                                       // nothing fixed up yet, addend is just initial value
+                                       //dyld::log("addend=0x%lX\n", initialValue);
+                                       addend = initialValue;
+                               }
+                       }
+                       
+                       uint8_t type = BIND_TYPE_POINTER;
+               #if __i386__
+                       if ( reloc->r_pcrel ) 
+                               type = BIND_TYPE_TEXT_PCREL32;
+               #endif
+                       this->bindLocation(context, (uintptr_t)location, value, targetImage, type, symbolName, addend, "weak ");
+                       boundSomething = true;
+               }
+       }
+
+       // scan lazy and non-lazy pointers for uses of symbol_index
+       const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
+       const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
+       const struct load_command* cmd = cmds;
+       const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff];
+       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) {
+                               uint32_t elementSize = sizeof(uintptr_t);
+                               switch ( sect->flags & SECTION_TYPE ) {
+                               #if __i386__
+                                       case S_SYMBOL_STUBS:
+                                               if ( ((sect->flags & S_ATTR_SELF_MODIFYING_CODE) ==0) || (sect->reserved2 != 5) )
+                                                       continue;
+                                               elementSize = 5;
+                               #endif
+                                       case S_NON_LAZY_SYMBOL_POINTERS:
+                                       case S_LAZY_SYMBOL_POINTERS:
+                                       {
+                                               uint32_t elementCount = sect->size / elementSize;
+                                               const uint32_t indirectTableOffset = sect->reserved1;
+                                               uint8_t* ptrToBind = (uint8_t*)(sect->addr + fSlide);
+                                               //dyld::log(" scanning section %s of %s starting at %p\n", sect->sectname, this->getShortName(), ptrToBind);
+                                               for (uint32_t j=0; j < elementCount; ++j, ptrToBind += elementSize) {
+                                                       if ( indirectTable[indirectTableOffset + j] == symbol_index ) {
+                                                               //dyld::log("  found symbol index match at %d/%d, ptrToBind=%p\n", j, elementCount, ptrToBind);
+                                                               // update pointer
+                                                               this->bindIndirectSymbol((uintptr_t*)ptrToBind, sect, it.symbolName, value, targetImage, context);
+                                                               boundSomething = true;
+                                                       }
+                                               }
+                                       }
+                                       break;
+                               }
+                       }
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+       }
+       if ( boundSomething && (targetImage != this) && !targetImage->neverUnload() )
+               this->addDynamicReference(targetImage);
+       
+       // mark that this symbol has already been bound, so we don't try to bind again
+       it.type = 1;
+}
+
+
+void ImageLoaderMachOClassic::bindIndirectSymbolPointers(const LinkContext& context, bool bindNonLazys, bool bindLazys)
+{
+       // scan for all non-lazy-pointer sections 
+       const bool twoLevel = this->usesTwoLevelNameSpace();
+       const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds;
+       const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)];
+       const struct load_command* cmd = cmds;
+       const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff];
+       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) {
+                                               bool isLazySymbol = false;
+                                               const uint8_t type = sect->flags & SECTION_TYPE;
+                                               uint32_t elementSize = sizeof(uintptr_t);
+                                               uint32_t elementCount = sect->size / elementSize;
+                                               if ( type == S_NON_LAZY_SYMBOL_POINTERS ) {
+                                                       if ( ! bindNonLazys )
+                                                               continue;
+                                               }
+                                               else if ( type == S_LAZY_SYMBOL_POINTERS ) {
+                                                       // process each symbol pointer in this section
+                                                       fgTotalPossibleLazyBindFixups += elementCount;
+                                                       isLazySymbol = true;
+                                                       if ( ! bindLazys )
+                                                               continue;
+                                               }
+                               #if __i386__
+                                               else if ( (type == S_SYMBOL_STUBS) && (sect->flags & S_ATTR_SELF_MODIFYING_CODE) && (sect->reserved2 == 5) ) {
+                                                       // process each jmp entry in this section
+                                                       elementCount = sect->size / 5;
+                                                       elementSize = 5;
+                                                       fgTotalPossibleLazyBindFixups += elementCount;
+                                                       isLazySymbol = true;
+                                                       if ( ! bindLazys )
+                                                               continue;
+                                               }
+                               #endif
+                                               else {
+                                                       continue;
+                                               }
+                                               const uint32_t indirectTableOffset = sect->reserved1;
+                                               uint8_t* ptrToBind = (uint8_t*)(sect->addr + fSlide);
+                                               for (uint32_t j=0; j < elementCount; ++j, ptrToBind += elementSize) {
+                               #if LINKEDIT_USAGE_DEBUG
+                                                       noteAccessedLinkEditAddress(&indirectTable[indirectTableOffset + j]);
+                               #endif
+                                                       uint32_t symbolIndex = indirectTable[indirectTableOffset + j];
+                                                       if ( symbolIndex == INDIRECT_SYMBOL_LOCAL) {
+                                                               *((uintptr_t*)ptrToBind) += this->fSlide;
+                                                       }
+                                                       else if ( symbolIndex == INDIRECT_SYMBOL_ABS) {
+                                                               // do nothing since already has absolute address
+                                                       }
+                                                       else {
+                                                               const struct macho_nlist* sym = &fSymbolTable[symbolIndex];
+                                                               if ( symbolIndex == 0 ) {
+                                                                       // This could be rdar://problem/3534709 
+                                                                       if ( ((const macho_header*)fMachOData)->filetype == MH_EXECUTE ) {
+                                                                               static bool alreadyWarned = false;
+                                                                               if ( (sym->n_type & N_TYPE) != N_UNDF ) {
+                                                                                       // The indirect table parallels the (non)lazy pointer sections.  For
+                                                                                       // instance, to find info about the fifth lazy pointer you look at the
+                                                                                       // fifth entry in the indirect table.  (try otool -Iv on a file).
+                                                                                       // The entry in the indirect table contains an index into the symbol table.
+
+                                                                                       // The bug in ld caused the entry in the indirect table to be zero
+                                                                                       // (instead of a magic value that means a local symbol).  So, if the
+                                                                                       // symbolIndex == 0, we may be encountering the bug, or 0 may be a valid
+                                                                                       // symbol table index. The check I put in place is to see if the zero'th
+                                                                                       // symbol table entry is an import entry (usually it is a local symbol
+                                                                                       // definition).
+                                                                                       if ( context.verboseWarnings && !alreadyWarned ) {
+                                                                                               dyld::log("dyld: malformed executable '%s', skipping indirect symbol to %s\n",
+                                                                                                               this->getPath(), &fStrings[sym->n_un.n_strx]);
+                                                                                               alreadyWarned = true;
+                                                                                       }
+                                                                                       continue;
+                                                                               }
+                                                                       }
+                                                               }
+                                                               const ImageLoader* image = NULL;
+                                                               // let weak definitions resolve to themselves, later coalescing may overwrite them
+                                                               bool dontCoalesce = true;
+                                                               if ( bindLazys && isLazySymbol ) {
+                                                                       // if this is something normally lazy bound, but we are forcing
+                                                                       // it to be bound now, do coalescing
+                                                                       dontCoalesce = false;
+                                                               }
+                                                               if ( symbolIsWeakReference(sym) ) { 
+                                                                       // when weakbind() is run on a classic mach-o encoding, it won't try
+                                                                       // to coalesce N_REF_TO_WEAK symbols because they are not in the sorted
+                                                                       // range of global symbols.  To handle that case we do the coalesing now.
+                                                                       dontCoalesce = false;
+                                                               }
+                                                               uintptr_t symbolAddr = resolveUndefined(context, sym, twoLevel, dontCoalesce, &image);
+                                                               // update pointer
+                                                               symbolAddr = this->bindIndirectSymbol((uintptr_t*)ptrToBind, sect, &fStrings[sym->n_un.n_strx], symbolAddr, image,  context);
+                                                               // update stats
+                                                               ++fgTotalBindFixups;
+                                                       }
+                                               }
+                                       }
+                               }
+                               break;
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+       }
+}
+
+
+
+#if __i386__
+void ImageLoaderMachOClassic::initializeLazyStubs(const LinkContext& context)
+{
+       if ( ! this->usablePrebinding(context) ) {
+               // reset all "fast" stubs
+               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) {
+                       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_SYMBOL_STUBS) && (sect->flags & S_ATTR_SELF_MODIFYING_CODE) && (sect->reserved2 == 5) ) {
+                                                       // reset each jmp entry in this section
+                                                       const uint32_t indirectTableOffset = sect->reserved1;
+                                                       const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff];
+                                                       uint8_t* start = (uint8_t*)(sect->addr + this->fSlide);
+                                                       uint8_t* end = start + sect->size;
+                                                       uintptr_t dyldHandler = (uintptr_t)&fast_stub_binding_helper_interface;
+                                                       uint32_t entryIndex = 0;
+                                                       for (uint8_t* entry = start; entry < end; entry += 5, ++entryIndex) {
+                                                               bool installLazyHandler = true;
+                                                               // jump table entries that cross a (64-byte) cache line boundary have the potential to cause crashes
+                                                               // if the instruction is updated by one thread while being executed by another
+                                                               if ( ((uint32_t)entry & 0xFFFFFFC0) != ((uint32_t)entry+4 & 0xFFFFFFC0) ) {
+                                                                       // need to bind this now to avoid a potential problem if bound lazily
+                                                                       uint32_t symbolIndex = indirectTable[indirectTableOffset + entryIndex];
+                                                                       // the latest linker marks 64-byte crossing stubs with INDIRECT_SYMBOL_ABS so they are not used
+                                                                       if ( symbolIndex != INDIRECT_SYMBOL_ABS ) {
+                                                                               const char* symbolName = &fStrings[fSymbolTable[symbolIndex].n_un.n_strx];
+                                                                               const ImageLoader* image = NULL;
+                                                                               try {
+                                                                                       uintptr_t symbolAddr = this->resolveUndefined(context, &fSymbolTable[symbolIndex], this->usesTwoLevelNameSpace(), false, &image);
+                                                                                       symbolAddr = this->bindIndirectSymbol((uintptr_t*)entry, sect, symbolName, symbolAddr, image, context);
+                                                                                       ++fgTotalBindFixups;
+                                                                                       uint32_t rel32 = symbolAddr - (((uint32_t)entry)+5);
+                                                                                       entry[0] = 0xE9; // JMP rel32
+                                                                                       entry[1] = rel32 & 0xFF;
+                                                                                       entry[2] = (rel32 >> 8) & 0xFF;
+                                                                                       entry[3] = (rel32 >> 16) & 0xFF;
+                                                                                       entry[4] = (rel32 >> 24) & 0xFF;
+                                                                                       installLazyHandler = false;
+                                                                               } 
+                                                                               catch (const char* msg) {
+                                                                                       // ignore errors when binding symbols early
+                                                                                       // maybe the function is never called, and therefore erroring out now would be a regression
+                                                                               }
+                                                                       }
+                                                               }
+                                                               if ( installLazyHandler ) {
+                                                                       uint32_t rel32 = dyldHandler - (((uint32_t)entry)+5);
+                                                                       entry[0] = 0xE8; // CALL rel32
+                                                                       entry[1] = rel32 & 0xFF;
+                                                                       entry[2] = (rel32 >> 8) & 0xFF;
+                                                                       entry[3] = (rel32 >> 16) & 0xFF;
+                                                                       entry[4] = (rel32 >> 24) & 0xFF;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+               }
+       }
+}
+#endif // __i386__
+
+
+void ImageLoaderMachOClassic::doBind(const LinkContext& context, bool forceLazysBound)
+{
+#if __i386__
+       this->initializeLazyStubs(context);
+#endif
+
+       // 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) ) {
+               // binding already up to date
+       }
+       else {
+               // no valid prebinding, so bind symbols.
+               // values bound by name are stored two different ways in classic mach-o:
+               
+               // 1) external relocations are used for data initialized to external symbols
+               this->doBindExternalRelocations(context);
+               
+               // 2) "indirect symbols" are used for code references to external symbols
+               // 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);
+
+       }
+       
+       // set up dyld entry points in image
+       this->setupLazyPointerHandler(context);
+}
+
+void ImageLoaderMachOClassic::doBindJustLazies(const LinkContext& context)
+{
+       // some API called requested that all lazy pointers in this image be force bound
+       this->bindIndirectSymbolPointers(context, false, true);
+}
+
+const char* ImageLoaderMachOClassic::findClosestSymbol(const void* addr, const void** closestAddr) const
+{
+       uintptr_t targetAddress = (uintptr_t)addr - fSlide;
+       const struct macho_nlist* bestSymbol = NULL;
+       // first walk all global symbols
+       const struct macho_nlist* const globalsStart = &fSymbolTable[fDynamicInfo->iextdefsym];
+       const struct macho_nlist* const globalsEnd= &globalsStart[fDynamicInfo->nextdefsym];
+       for (const struct macho_nlist* s = globalsStart; s < globalsEnd; ++s) {
+               if ( (s->n_type & N_TYPE) == N_SECT ) {
+                       if ( bestSymbol == NULL ) {
+                               if ( s->n_value <= targetAddress )
+                                       bestSymbol = s;
+                       }
+                       else if ( (s->n_value <= targetAddress) && (bestSymbol->n_value < s->n_value) ) {
+                               bestSymbol = s;
+                       }
+               }
+       }
+       // next walk all local symbols
+       const struct macho_nlist* const localsStart = &fSymbolTable[fDynamicInfo->ilocalsym];
+       const struct macho_nlist* const localsEnd= &localsStart[fDynamicInfo->nlocalsym];
+       for (const struct macho_nlist* s = localsStart; s < localsEnd; ++s) {
+               if ( ((s->n_type & N_TYPE) == N_SECT) && ((s->n_type & N_STAB) == 0) ) {
+                       if ( bestSymbol == NULL ) {
+                               if ( s->n_value <= targetAddress )
+                                       bestSymbol = s;
+                       }
+                       else if ( (s->n_value <= targetAddress) && (bestSymbol->n_value < s->n_value) ) {
+                               bestSymbol = s;
+                       }
+               }
+       }
+       if ( bestSymbol != NULL ) {
+               *closestAddr = (void*)(bestSymbol->n_value + fSlide);
+               return &fStrings[bestSymbol->n_un.n_strx];
+       }
+       return NULL;
+}
+
+
diff --git a/src/ImageLoaderMachOClassic.h b/src/ImageLoaderMachOClassic.h
new file mode 100644 (file)
index 0000000..6a339ec
--- /dev/null
@@ -0,0 +1,134 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 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 __IMAGELOADER_MACHO_CLASSIC__
+#define __IMAGELOADER_MACHO_CLASSIC__
+
+#include <stdint.h> 
+
+#include "ImageLoaderMachO.h"
+
+
+//
+// ImageLoaderMachOClassic is the concrete subclass of ImageLoader which loads mach-o files 
+// that use the traditional LINKEDIT format.  
+//
+class ImageLoaderMachOClassic : public ImageLoaderMachO {
+public:
+       static ImageLoaderMachOClassic*         instantiateMainExecutable(const macho_header* mh, uintptr_t slide, const char* path, 
+                                                                                                                                       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 LinkContext& context);
+       static ImageLoaderMachOClassic*         instantiateFromMemory(const char* moduleName, const macho_header* mh, uint64_t len, 
+                                                                                                                       unsigned int segCount, unsigned int libCount, const LinkContext& context);
+
+       virtual                                                         ~ImageLoaderMachOClassic();
+
+       virtual ImageLoader*                            libImage(unsigned int) const;
+       virtual bool                                            libReExported(unsigned int) const;
+       virtual void                                            setLibImage(unsigned int, ImageLoader*, 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 const char*                                     findClosestSymbol(const void* addr, const void** closestAddr) const;
+       virtual void                                            initializeCoalIterator(CoalIterator&, unsigned int loadOrder);
+       virtual bool                                            incrementCoalIterator(CoalIterator&);
+       virtual uintptr_t                                       getAddressCoalIterator(CoalIterator&, const LinkContext& contex);
+       virtual void                                            updateUsesCoalIterator(CoalIterator&, uintptr_t newAddr, ImageLoader* target, const LinkContext& context);
+
+protected:
+       virtual void                                            setDyldInfo(const dyld_info_command*) {}
+       virtual void                                            setSymbolTableInfo(const macho_nlist*, const char*, const dysymtab_command*);
+       virtual bool                                            isSubframeworkOf(const LinkContext& context, const ImageLoader* image) const;
+       virtual bool                                            hasSubLibrary(const LinkContext& context, const ImageLoader* child) const;
+       virtual uint32_t*                                       segmentCommandOffsets() const;
+       virtual void                                            rebase(const LinkContext& context);
+       virtual const ImageLoader::Symbol*      findExportedSymbol(const char* name, const ImageLoader** foundIn) const;
+       virtual bool                                            containsSymbol(const void* addr) const;
+       virtual uintptr_t                                       exportedSymbolAddress(const Symbol* symbol) const;
+       virtual bool                                            exportedSymbolIsWeakDefintion(const Symbol* symbol) const;
+       virtual const char*                                     exportedSymbolName(const Symbol* symbol) const;
+       virtual unsigned int                            exportedSymbolCount() const;
+       virtual const ImageLoader::Symbol*      exportedSymbolIndexed(unsigned int) const;
+       virtual unsigned int                            importedSymbolCount() const;
+       virtual const ImageLoader::Symbol*      importedSymbolIndexed(unsigned int) const;
+       virtual const char*                                     importedSymbolName(const Symbol* symbol) const;
+#if PREBOUND_IMAGE_SUPPORT
+       virtual void                                            resetPreboundLazyPointers(const LinkContext& context);
+#endif
+
+
+private:
+                                                                               ImageLoaderMachOClassic(const macho_header* mh, const char* path, unsigned int segCount, 
+                                                                                                                                               uint32_t segOffsets[], unsigned int libCount);
+       static ImageLoaderMachOClassic*         instantiateStart(const macho_header* mh, const char* path, unsigned int segCount, unsigned int libCount);
+       void                                                            instantiateFinish(const LinkContext& context);
+       uintptr_t                                                       getRelocBase();
+       void                                                            mapSegmentsClassic(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context);
+       uintptr_t                                                       getFirstWritableSegmentAddress();
+       const struct macho_nlist*                       binarySearch(const char* key, const char stringPool[], const struct macho_nlist symbols[], uint32_t symbolCount) const;
+       const struct macho_nlist*                       binarySearchWithToc(const char* key, const char stringPool[], const struct macho_nlist symbols[], 
+                                                                                                                       const struct dylib_table_of_contents toc[], uint32_t symbolCount, uint32_t hintIndex) const;
+       static  bool                                            symbolIsWeakReference(const struct macho_nlist* symbol); 
+       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;
+       bool                                                            isAddrInSection(uintptr_t addr, uint8_t sectionIndex);
+       void                                                            doBindExternalRelocations(const LinkContext& context);
+       uintptr_t                                                       bindIndirectSymbol(uintptr_t* ptrToBind, const struct macho_section* sect, 
+                                                                                                                       const char* symbolName, uintptr_t targetAddr, 
+                                                                                                                       const ImageLoader* targetImage, const LinkContext& context);
+       void                                                            bindIndirectSymbolPointers(const LinkContext& context, bool bindNonLazys, bool bindLazys);
+       void                                                            initializeLazyStubs(const LinkContext& context);
+       void                                                            prefetchLINKEDIT(const LinkContext& context);
+#if SPLIT_SEG_DYLIB_SUPPORT    
+       unsigned int                                            getExtraZeroFillEntriesCount();
+       void                                                            initMappingTable(uint64_t offsetInFat, shared_file_mapping_np *mappingTable);
+#endif
+       int                                                                     mapSplitSegDylibOutsideSharedRegion(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context);
+#if SPLIT_SEG_SHARED_REGION_SUPPORT
+       int                                                                     mapSplitSegDylibInfoSharedRegion(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context);
+#endif
+
+                       
+       const char*                                                             fStrings;
+       const struct macho_nlist*                               fSymbolTable;
+       const struct dysymtab_command*                  fDynamicInfo;
+
+};
+
+
+
+
+#endif // __IMAGELOADER_MACHO_CLASSIC__
+
+
+
+
diff --git a/src/ImageLoaderMachOCompressed.cpp b/src/ImageLoaderMachOCompressed.cpp
new file mode 100644 (file)
index 0000000..7d3812b
--- /dev/null
@@ -0,0 +1,1370 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 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 <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h> 
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <mach/mach.h>
+#include <mach/thread_status.h>
+#include <mach-o/loader.h> 
+
+#include "ImageLoaderMachOCompressed.h"
+#include "mach-o/dyld_images.h"
+
+
+// relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables
+#if __LP64__
+       #define RELOC_SIZE 3
+       #define LC_SEGMENT_COMMAND              LC_SEGMENT_64
+       #define LC_ROUTINES_COMMAND             LC_ROUTINES_64
+       struct macho_segment_command    : public segment_command_64  {};
+       struct macho_section                    : public section_64  {};        
+       struct macho_routines_command   : public routines_command_64  {};       
+#else
+       #define RELOC_SIZE 2
+       #define LC_SEGMENT_COMMAND              LC_SEGMENT
+       #define LC_ROUTINES_COMMAND             LC_ROUTINES
+       struct macho_segment_command    : public segment_command {};
+       struct macho_section                    : public section  {};   
+       struct macho_routines_command   : public routines_command  {};  
+#endif
+
+       
+static uintptr_t read_uleb128(const uint8_t*& p, const uint8_t* end)
+{
+       uint64_t result = 0;
+       int              bit = 0;
+       do {
+               if (p == end)
+                       dyld::throwf("malformed uleb128");
+
+               uint64_t slice = *p & 0x7f;
+
+               if (bit >= 64 || slice << bit >> bit != slice)
+                       dyld::throwf("uleb128 too big");
+               else {
+                       result |= (slice << bit);
+                       bit += 7;
+               }
+       } 
+       while (*p++ & 0x80);
+       return result;
+}
+
+
+static intptr_t read_sleb128(const uint8_t*& p, const uint8_t* end)
+{
+       int64_t result = 0;
+       int bit = 0;
+       uint8_t byte;
+       do {
+               if (p == end)
+                       throw "malformed sleb128";
+               byte = *p++;
+               result |= ((byte & 0x7f) << bit);
+               bit += 7;
+       } while (byte & 0x80);
+       // sign extend negative numbers
+       if ( (byte & 0x40) != 0 )
+               result |= (-1LL) << bit;
+       return result;
+}
+
+
+// create image for main executable
+ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateMainExecutable(const macho_header* mh, uintptr_t slide, const char* path, 
+                                                                                                                                               unsigned int segCount, unsigned int libCount, const LinkContext& context)
+{
+       ImageLoaderMachOCompressed* image = ImageLoaderMachOCompressed::instantiateStart(mh, path, segCount, libCount);
+
+       // set slide for PIE programs
+       image->setSlide(slide);
+
+       // for PIE record end of program, to know where to start loading dylibs
+       if ( (mh->flags & MH_PIE) && !context.noPIE )
+               fgNextPIEDylibAddress = (uintptr_t)image->getEnd();
+       
+       image->setNeverUnload();
+       image->instantiateFinish(context);
+       
+       if ( context.verboseMapping ) {
+               dyld::log("dyld: Main executable mapped %s\n", path);
+               for(unsigned int i=0, e=image->segmentCount(); i < e; ++i) {
+                       const char* name = image->segName(i);
+                       if ( (strcmp(name, "__PAGEZERO") == 0) || (strcmp(name, "__UNIXSTACK") == 0)  )
+                               dyld::log("%18s at 0x%08lX->0x%08lX\n", name, image->segPreferredLoadAddress(i), image->segPreferredLoadAddress(i)+image->segSize(i));
+                       else
+                               dyld::log("%18s at 0x%08lX->0x%08lX\n", name, image->segActualLoadAddress(i), image->segActualEndAddress(i));
+               }
+       }
+
+       return image;
+}
+
+// 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)
+{
+       ImageLoaderMachOCompressed* image = ImageLoaderMachOCompressed::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->mapSegments(fd, offsetInFat, lenInFat, info.st_size, context);
+
+               // finish construction
+               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] == '/') )
+                       image->setPathUnowned(installName);
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+               // <rdar://problem/6563887> app crashes when libSystem cannot be found
+               else if ( (installName != NULL) && (strcmp(path, "/usr/lib/libgcc_s.1.dylib") == 0) && (strcmp(installName, "/usr/lib/libSystem.B.dylib") == 0) )
+                       image->setPathUnowned("/usr/lib/libSystem.B.dylib");
+#endif
+               else if ( path[0] != '/' ) {
+                       // rdar://problem/5135363 turn relative paths into absolute paths so gdb, Symbolication can later find them
+                       char realPath[MAXPATHLEN];
+                       if ( realpath(path, realPath) != NULL )
+                               image->setPath(realPath);
+                       else
+                               image->setPath(path);
+               }
+               else 
+                       image->setPath(path);
+
+               // 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()) {
+                       image->preFetchDATA(fd, offsetInFat, context);
+                       image->markSequentialLINKEDIT(context);
+               }
+       }
+       catch (...) {
+               // ImageLoader::setMapped() can throw an exception to block loading of image
+               // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight
+               delete image;
+               throw;
+       }
+       
+       return image;
+}
+
+// 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* image = ImageLoaderMachOCompressed::instantiateStart(mh, path, segCount, libCount);
+       try {
+               // record info about file  
+               image->setFileInfo(info.st_dev, info.st_ino, info.st_mtime);
+
+               // remember this is from shared cache and cannot be unloaded
+               image->fInSharedCache = true;
+               image->setNeverUnload();
+
+               // segments already mapped in cache
+               if ( context.verboseMapping ) {
+                       dyld::log("dyld: Using shared cached for %s\n", path);
+                       for(unsigned int i=0; i < image->fSegmentsCount; ++i) {
+                               dyld::log("%18s at 0x%08lX->0x%08lX\n", image->segName(i), image->segActualLoadAddress(i), image->segActualEndAddress(i));
+                       }
+               }
+
+               image->instantiateFinish(context);
+       }
+       catch (...) {
+               // ImageLoader::setMapped() can throw an exception to block loading of image
+               // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight
+               delete image;
+               throw;
+       }
+       
+       return image;
+}
+
+// create image by copying an in-memory mach-o file
+ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateFromMemory(const char* moduleName, const macho_header* mh, uint64_t len, 
+                                                                                                                       unsigned int segCount, unsigned int libCount, const LinkContext& context)
+{
+       ImageLoaderMachOCompressed* image = ImageLoaderMachOCompressed::instantiateStart(mh, moduleName, segCount, libCount);
+       try {
+               // map segments 
+               if ( mh->filetype == MH_EXECUTE ) 
+                       throw "can't load another MH_EXECUTE";
+               
+               // vmcopy segments
+               image->mapSegments((const void*)mh, len, context);
+               
+               // for compatibility, never unload dylibs loaded from memory
+               image->setNeverUnload();
+
+               // bundle loads need path copied
+               if ( moduleName != NULL ) 
+                       image->setPath(moduleName);
+
+               image->instantiateFinish(context);
+       }
+       catch (...) {
+               // ImageLoader::setMapped() can throw an exception to block loading of image
+               // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight
+               delete image;
+               throw;
+       }
+       
+       return image;
+}
+
+
+ImageLoaderMachOCompressed::ImageLoaderMachOCompressed(const macho_header* mh, const char* path, unsigned int segCount, 
+                                                                                                                                               uint32_t segOffsets[], unsigned int libCount)
+ : ImageLoaderMachO(mh, path, segCount, segOffsets, libCount), fDyldInfo(NULL)
+{
+}
+
+ImageLoaderMachOCompressed::~ImageLoaderMachOCompressed()
+{
+       // don't do clean up in ~ImageLoaderMachO() because virtual call to segmentCommandOffsets() won't work
+       destroy();
+}
+
+
+
+// construct ImageLoaderMachOCompressed using "placement new" with SegmentMachO objects array at end
+ImageLoaderMachOCompressed* ImageLoaderMachOCompressed::instantiateStart(const macho_header* mh, const char* path, 
+                                                                                                                                                       unsigned int segCount, unsigned int libCount)
+{
+       size_t size = sizeof(ImageLoaderMachOCompressed) + segCount * sizeof(uint32_t) + libCount * sizeof(ImageLoader*);
+       ImageLoaderMachOCompressed* allocatedSpace = static_cast<ImageLoaderMachOCompressed*>(malloc(size));
+       if ( allocatedSpace == NULL )
+               throw "malloc failed";
+       uint32_t* segOffsets = ((uint32_t*)(((uint8_t*)allocatedSpace) + sizeof(ImageLoaderMachOCompressed)));
+       bzero(&segOffsets[segCount], libCount*sizeof(void*));   // zero out lib array
+       return new (allocatedSpace) ImageLoaderMachOCompressed(mh, path, segCount, segOffsets, libCount);
+}
+
+
+// common code to finish initializing object
+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
+{
+       return ((uint32_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed)));
+}
+
+
+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));
+}
+
+bool ImageLoaderMachOCompressed::libReExported(unsigned int libIndex) const
+{
+       const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed) + fSegmentsCount*sizeof(uint32_t)));
+       // re-export flag is low bit
+       return ((images[libIndex] & 1) != 0);
+}      
+
+
+void ImageLoaderMachOCompressed::setLibImage(unsigned int libIndex, ImageLoader* image, bool reExported)
+{
+       uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOCompressed) + fSegmentsCount*sizeof(uint32_t)));
+       uintptr_t value = (uintptr_t)image;
+       if ( reExported ) 
+               value |= 1;
+       images[libIndex] = value;
+}
+
+
+void ImageLoaderMachOCompressed::markFreeLINKEDIT(const LinkContext& context)
+{
+       // mark that we are done with rebase and bind info 
+       markLINKEDIT(context, MADV_FREE);
+}
+
+void ImageLoaderMachOCompressed::markSequentialLINKEDIT(const LinkContext& context)
+{
+       // mark the rebase and bind info and using sequential access
+       markLINKEDIT(context, MADV_SEQUENTIAL);
+}
+
+void ImageLoaderMachOCompressed::markLINKEDIT(const LinkContext& context, int advise)
+{
+       // if not loaded at preferred address, mark rebase info 
+       uintptr_t start = 0;
+       if ( (fSlide != 0) && (fDyldInfo->rebase_size != 0) ) 
+               start = (uintptr_t)fLinkEditBase + fDyldInfo->rebase_off;
+       else if ( fDyldInfo->bind_off != 0 )
+               start = (uintptr_t)fLinkEditBase + fDyldInfo->bind_off;
+       else
+               return; // no binding info to prefetch
+               
+       // end is at end of bind info
+       uintptr_t end = 0;
+       if ( fDyldInfo->bind_off != 0 )
+               end = (uintptr_t)fLinkEditBase + fDyldInfo->bind_off + fDyldInfo->bind_size;
+       else if ( fDyldInfo->rebase_off != 0 )
+               end = (uintptr_t)fLinkEditBase + fDyldInfo->rebase_off + fDyldInfo->rebase_size;
+       else
+               return;
+               
+                       
+       // round to whole pages
+       start = start & (-4096);
+       end = (end + 4095) & (-4096);
+
+       // do nothing if only one page of rebase/bind info
+       if ( (end-start) <= 4096 )
+               return;
+       
+       // tell kernel about our access to these pages
+       madvise((void*)start, end-start, advise);
+       if ( context.verboseMapping ) {
+               const char* adstr = "sequential";
+               if ( advise == MADV_FREE )
+                       adstr = "free";
+               dyld::log("%18s %s 0x%0lX -> 0x%0lX\n", "__LINKEDIT", adstr, start, end-1);
+       }
+}
+
+
+
+void ImageLoaderMachOCompressed::rebaseAt(const LinkContext& context, uintptr_t addr, uintptr_t slide, uint8_t type)
+{
+       //dyld::log("0x%08lX type=%d\n", addr, type);
+       uintptr_t* locationToFix = (uintptr_t*)addr;
+       switch (type) {
+               case REBASE_TYPE_POINTER:
+                       *locationToFix += slide;
+                       break;
+               case REBASE_TYPE_TEXT_ABSOLUTE32:
+                       *locationToFix += slide;
+                       break;
+               default:
+                       dyld::throwf("bad rebase type %d", type);
+       }
+}
+
+void ImageLoaderMachOCompressed::throwBadRebaseAddress(uintptr_t address, uintptr_t segmentEndAddress, int segmentIndex, 
+                                                                               const uint8_t* startOpcodes, const uint8_t* endOpcodes, const uint8_t* pos)
+{
+       dyld::throwf("malformed rebase opcodes (%ld/%ld): address 0x%08lX is beyond end of segment %s (0x%08lX -> 0x%08lX)",
+               (intptr_t)(pos-startOpcodes), (intptr_t)(endOpcodes-startOpcodes), address, segName(segmentIndex), 
+               segActualLoadAddress(segmentIndex), segmentEndAddress); 
+}
+
+void ImageLoaderMachOCompressed::rebase(const LinkContext& context)
+{
+       const uintptr_t slide = this->fSlide;
+       const uint8_t* const start = fLinkEditBase + fDyldInfo->rebase_off;
+       const uint8_t* const end = &start[fDyldInfo->rebase_size];
+       const uint8_t* p = start;
+
+       try {
+               uint8_t type = 0;
+               int segmentIndex = 0;
+               uintptr_t address = segActualLoadAddress(0);
+               uintptr_t segmentEndAddress = segActualEndAddress(0);
+               uint32_t count;
+               uint32_t skip;
+               bool done = false;
+               while ( !done && (p < end) ) {
+                       uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
+                       uint8_t opcode = *p & REBASE_OPCODE_MASK;
+                       ++p;
+                       switch (opcode) {
+                               case REBASE_OPCODE_DONE:
+                                       done = true;
+                                       break;
+                               case REBASE_OPCODE_SET_TYPE_IMM:
+                                       type = immediate;
+                                       break;
+                               case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+                                       segmentIndex = immediate;
+                                       if ( segmentIndex > fSegmentsCount )
+                                               dyld::throwf("REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (%d)\n", 
+                                                               segmentIndex, fSegmentsCount);
+                                       address = segActualLoadAddress(segmentIndex) + read_uleb128(p, end);
+                                       segmentEndAddress = segActualEndAddress(segmentIndex);
+                                       break;
+                               case REBASE_OPCODE_ADD_ADDR_ULEB:
+                                       address += read_uleb128(p, end);
+                                       break;
+                               case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
+                                       address += immediate*sizeof(uintptr_t);
+                                       break;
+                               case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
+                                       for (int i=0; i < immediate; ++i) {
+                                               if ( address >= segmentEndAddress ) 
+                                                       throwBadRebaseAddress(address, segmentEndAddress, segmentIndex, start, end, p);
+                                               rebaseAt(context, address, slide, type);
+                                               address += sizeof(uintptr_t);
+                                       }
+                                       fgTotalRebaseFixups += immediate;
+                                       break;
+                               case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
+                                       count = read_uleb128(p, end);
+                                       for (uint32_t i=0; i < count; ++i) {
+                                               if ( address >= segmentEndAddress ) 
+                                                       throwBadRebaseAddress(address, segmentEndAddress, segmentIndex, start, end, p);
+                                               rebaseAt(context, address, slide, type);
+                                               address += sizeof(uintptr_t);
+                                       }
+                                       fgTotalRebaseFixups += count;
+                                       break;
+                               case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
+                                       if ( address >= segmentEndAddress ) 
+                                               throwBadRebaseAddress(address, segmentEndAddress, segmentIndex, start, end, p);
+                                       rebaseAt(context, address, slide, type);
+                                       address += read_uleb128(p, end) + sizeof(uintptr_t);
+                                       ++fgTotalRebaseFixups;
+                                       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) {
+                                               if ( address >= segmentEndAddress ) 
+                                                       throwBadRebaseAddress(address, segmentEndAddress, segmentIndex, start, end, p);
+                                               rebaseAt(context, address, slide, type);
+                                               address += skip + sizeof(uintptr_t);
+                                       }
+                                       fgTotalRebaseFixups += count;
+                                       break;
+                               default:
+                                       dyld::throwf("bad rebase opcode %d", *p);
+                       }
+               }
+       }
+       catch (const char* msg) {
+               const char* newMsg = dyld::mkstringf("%s in %s", msg, this->getPath());
+               free((void*)msg);
+               throw newMsg;
+       }
+}
+
+
+
+
+const ImageLoader::Symbol* ImageLoaderMachOCompressed::findExportedSymbol(const char* symbol, const ImageLoader** foundIn) const
+{
+       //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;
+               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;
+               }
+               const uint8_t childrenCount = *children++;
+               const uint8_t* e = children;
+               const uint8_t* newNode = NULL;
+               for (uint8_t i=0; i < childrenCount; ++i) {
+                       const char* ss = s;
+                       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' ) {
+                               if ( !wrongEdge ) {
+                                       if ( *e != *ss++ )
+                                               wrongEdge = true;
+                               }
+                               ++e;
+                       }
+                       if ( wrongEdge ) {
+                               // advance to next child
+                               ++e;
+                               read_uleb128(e, end);
+                       }
+                       else {
+                               // 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];
+                               s = ss;
+                               //dyld::log("findExportedSymbol() found matching edge advancing to node 0x%x\n", nodeOffset);
+                               break;
+                       }
+               }
+               if ( newNode != NULL )
+                       p = newNode;
+               else {
+                       //dyld::log("findExportedSymbol(%s) in %s failed\n", symbol, this->getShortName());
+                       return NULL;
+               }
+       } while ( true );
+}
+
+
+bool ImageLoaderMachOCompressed::containsSymbol(const void* addr) const
+{
+       const uint8_t* start = &fLinkEditBase[fDyldInfo->export_off];
+       const uint8_t* end = &start[fDyldInfo->export_size];
+       return ( (start <= addr) && (addr < end) );
+}
+
+
+uintptr_t ImageLoaderMachOCompressed::exportedSymbolAddress(const Symbol* symbol) 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";
+       uint32_t flags = read_uleb128(exportNode, exportTrieEnd);
+       if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_REGULAR )
+               return read_uleb128(exportNode, exportTrieEnd) + (uintptr_t)fMachOData;
+       else
+               throw "unsupported exported symbol kind";
+}
+
+bool ImageLoaderMachOCompressed::exportedSymbolIsWeakDefintion(const Symbol* symbol) 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";
+       uint32_t flags = read_uleb128(exportNode, exportTrieEnd);
+       return ( flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION );
+}
+
+
+const char* ImageLoaderMachOCompressed::exportedSymbolName(const Symbol* symbol) const
+{
+       throw "NSNameOfSymbol() not supported with compressed LINKEDIT";
+}
+
+unsigned int ImageLoaderMachOCompressed::exportedSymbolCount() const
+{
+       throw "NSSymbolDefinitionCountInObjectFileImage() not supported with compressed LINKEDIT";
+}
+
+const ImageLoader::Symbol* ImageLoaderMachOCompressed::exportedSymbolIndexed(unsigned int index) const
+{
+       throw "NSSymbolDefinitionNameInObjectFileImage() not supported with compressed LINKEDIT";
+}
+
+unsigned int ImageLoaderMachOCompressed::importedSymbolCount() const
+{
+       throw "NSSymbolReferenceCountInObjectFileImage() not supported with compressed LINKEDIT";
+}
+
+const ImageLoader::Symbol* ImageLoaderMachOCompressed::importedSymbolIndexed(unsigned int index) const
+{
+       throw "NSSymbolReferenceCountInObjectFileImage() not supported with compressed LINKEDIT";
+}
+
+const char* ImageLoaderMachOCompressed::importedSymbolName(const Symbol* symbol) const
+{
+       throw "NSSymbolReferenceNameInObjectFileImage() not supported with compressed LINKEDIT";
+}
+
+
+
+uintptr_t ImageLoaderMachOCompressed::resolveFlat(const LinkContext& context, const char* symbolName, bool weak_import, 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);
+       }
+       // 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);
+       }
+       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");
+}
+
+
+uintptr_t ImageLoaderMachOCompressed::resolveTwolevel(const LinkContext& context, const ImageLoader* targetImage, bool weak_import, 
+                                                                                               const char* symbolName, const ImageLoader** foundIn)
+{
+       // two level lookup
+       const Symbol* sym = targetImage->findExportedSymbol(symbolName, true, foundIn);
+       if ( sym != NULL ) {
+               return (*foundIn)->getExportedSymbolAddress(sym, context, this);
+       }
+       
+       if ( weak_import ) {
+               // definition can't be found anywhere, ok because it is weak, just return 0
+               return 0;
+       }
+
+       // nowhere to be found
+       throwSymbolNotFound(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)
+{
+       *targetImage = NULL;
+       
+       // only clients that benefit from caching last lookup pass in a LastLookup struct
+       if ( last != NULL ) {
+               if ( (last->ordinal == libraryOrdinal)
+                       && (last->flags == symboFlags)
+                       && (last->name == symbolName) ) {
+                               *targetImage = last->foundIn;
+                               return last->result;
+                       }
+       }
+       
+       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);
+       }
+       else {
+               if ( libraryOrdinal == BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE ) {
+                       *targetImage = context.mainExecutable;
+               }
+               else if ( libraryOrdinal == BIND_SPECIAL_DYLIB_SELF ) {
+                       *targetImage = this;
+               }
+               else if ( libraryOrdinal <= 0 ) {
+                       dyld::throwf("bad mach-o binary, unknown special library ordinal (%u) too big for symbol %s in %s",
+                               libraryOrdinal, symbolName, this->getPath());
+               }
+               else if ( (unsigned)libraryOrdinal <= libraryCount() ) {
+                       *targetImage = libImage(libraryOrdinal-1);
+               }
+               else {
+                       dyld::throwf("bad mach-o binary, library ordinal (%u) too big (max %u) for symbol %s in %s",
+                               libraryOrdinal, libraryCount(), symbolName, this->getPath());
+               }
+               if ( *targetImage == NULL ) {
+                       if ( weak_import ) {
+                               // if target library not loaded and reference is weak or library is weak return 0
+                               symbolAddress = 0;
+                       }
+                       else {
+                               dyld::throwf("can't resolve symbol %s in %s because dependent dylib #%d could not be loaded",
+                                       symbolName, this->getPath(), libraryOrdinal);
+                       }
+               }
+               else {
+                       symbolAddress = resolveTwolevel(context, *targetImage, weak_import, symbolName, targetImage);
+               }
+       }
+       
+       // save off lookup results if client wants 
+       if ( last != NULL ) {
+               last->ordinal   = libraryOrdinal;
+               last->flags             = symboFlags;
+               last->name              = symbolName;
+               last->foundIn   = *targetImage;
+               last->result    = symbolAddress;
+       }
+       
+       return symbolAddress;
+}
+
+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)
+{
+       const ImageLoader*      targetImage;
+       uintptr_t                       symbolAddress;
+       
+       // resolve symbol
+       symbolAddress = this->resolve(context, symbolName, symboFlags, libraryOrdinal, &targetImage, last);
+
+       // do actual update
+       return this->bindLocation(context, addr, symbolAddress, targetImage, type, symbolName, addend, msg);
+}
+
+void ImageLoaderMachOCompressed::throwBadBindingAddress(uintptr_t address, uintptr_t segmentEndAddress, int segmentIndex, 
+                                                                               const uint8_t* startOpcodes, const uint8_t* endOpcodes, const uint8_t* pos)
+{
+       dyld::throwf("malformed binding opcodes (%ld/%ld): address 0x%08lX is beyond end of segment %s (0x%08lX -> 0x%08lX)",
+               (intptr_t)(pos-startOpcodes), (intptr_t)(endOpcodes-startOpcodes), address, segName(segmentIndex), 
+               segActualLoadAddress(segmentIndex), segmentEndAddress); 
+}
+
+
+void ImageLoaderMachOCompressed::doBind(const LinkContext& context, bool forceLazysBound)
+{
+       // 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 {
+               // 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,
+               // there is no way to reset the lazy pointers, so force bind them now
+               if ( forceLazysBound || fInSharedCache )
+                       this->doBindJustLazies(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);
+}
+
+
+void ImageLoaderMachOCompressed::doBindJustLazies(const LinkContext& context)
+{
+       eachLazyBind(context, &ImageLoaderMachOCompressed::bindAt);
+}
+
+void ImageLoaderMachOCompressed::eachBind(const LinkContext& context, bind_handler handler)
+{
+       try {
+               uint8_t type = 0;
+               int segmentIndex = 0;
+               uintptr_t address = segActualLoadAddress(0);
+               uintptr_t segmentEndAddress = segActualEndAddress(0);
+               const char* symbolName = NULL;
+               uint8_t symboFlags = 0;
+               int libraryOrdinal = 0;
+               intptr_t addend = 0;
+               uint32_t count;
+               uint32_t skip;
+               LastLookup last = { 0, 0, NULL, 0, NULL };
+               const uint8_t* const start = fLinkEditBase + fDyldInfo->bind_off;
+               const uint8_t* const end = &start[fDyldInfo->bind_size];
+               const uint8_t* p = start;
+               bool done = false;
+               while ( !done && (p < end) ) {
+                       uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
+                       uint8_t opcode = *p & BIND_OPCODE_MASK;
+                       ++p;
+                       switch (opcode) {
+                               case BIND_OPCODE_DONE:
+                                       done = true;
+                                       break;
+                               case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+                                       libraryOrdinal = immediate;
+                                       break;
+                               case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+                                       libraryOrdinal = read_uleb128(p, end);
+                                       break;
+                               case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+                                       // the special ordinals are negative numbers
+                                       if ( immediate == 0 )
+                                               libraryOrdinal = 0;
+                                       else {
+                                               int8_t signExtended = BIND_OPCODE_MASK | immediate;
+                                               libraryOrdinal = signExtended;
+                                       }
+                                       break;
+                               case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+                                       symbolName = (char*)p;
+                                       symboFlags = immediate;
+                                       while (*p != '\0')
+                                               ++p;
+                                       ++p;
+                                       break;
+                               case BIND_OPCODE_SET_TYPE_IMM:
+                                       type = immediate;
+                                       break;
+                               case BIND_OPCODE_SET_ADDEND_SLEB:
+                                       addend = read_sleb128(p, end);
+                                       break;
+                               case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+                                       segmentIndex = immediate;
+                                       if ( segmentIndex > fSegmentsCount )
+                                               dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (%d)\n", 
+                                                               segmentIndex, fSegmentsCount);
+                                       address = segActualLoadAddress(segmentIndex) + read_uleb128(p, end);
+                                       segmentEndAddress = segActualEndAddress(segmentIndex);
+                                       break;
+                               case BIND_OPCODE_ADD_ADDR_ULEB:
+                                       address += read_uleb128(p, end);
+                                       break;
+                               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);
+                                       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);
+                                       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);
+                                       address += immediate*sizeof(intptr_t) + sizeof(intptr_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) {
+                                               if ( address >= segmentEndAddress ) 
+                                                       throwBadBindingAddress(address, segmentEndAddress, segmentIndex, start, end, p);
+                                               (this->*handler)(context, address, type, symbolName, symboFlags, addend, libraryOrdinal, "", &last);
+                                               address += skip + sizeof(intptr_t);
+                                       }
+                                       break;
+                               default:
+                                       dyld::throwf("bad bind opcode %d in bind info", *p);
+                       }
+               }
+       }
+       catch (const char* msg) {
+               const char* newMsg = dyld::mkstringf("%s in %s", msg, this->getPath());
+               free((void*)msg);
+               throw newMsg;
+       }
+}
+
+void ImageLoaderMachOCompressed::eachLazyBind(const LinkContext& context, bind_handler handler)
+{
+       try {
+               uint8_t type = BIND_TYPE_POINTER;
+               int segmentIndex = 0;
+               uintptr_t address = segActualLoadAddress(0);
+               uintptr_t segmentEndAddress = segActualEndAddress(0);
+               const char* symbolName = NULL;
+               uint8_t symboFlags = 0;
+               int libraryOrdinal = 0;
+               intptr_t addend = 0;
+               const uint8_t* const start = fLinkEditBase + fDyldInfo->lazy_bind_off;
+               const uint8_t* const end = &start[fDyldInfo->lazy_bind_size];
+               const uint8_t* p = start;
+               bool done = false;
+               while ( !done && (p < end) ) {
+                       uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
+                       uint8_t opcode = *p & BIND_OPCODE_MASK;
+                       ++p;
+                       switch (opcode) {
+                               case BIND_OPCODE_DONE:
+                                       // there is BIND_OPCODE_DONE at end of each lazy bind, don't stop until end of whole sequence
+                                       break;
+                               case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+                                       libraryOrdinal = immediate;
+                                       break;
+                               case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+                                       libraryOrdinal = read_uleb128(p, end);
+                                       break;
+                               case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+                                       // the special ordinals are negative numbers
+                                       if ( immediate == 0 )
+                                               libraryOrdinal = 0;
+                                       else {
+                                               int8_t signExtended = BIND_OPCODE_MASK | immediate;
+                                               libraryOrdinal = signExtended;
+                                       }
+                                       break;
+                               case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+                                       symbolName = (char*)p;
+                                       symboFlags = immediate;
+                                       while (*p != '\0')
+                                               ++p;
+                                       ++p;
+                                       break;
+                               case BIND_OPCODE_SET_TYPE_IMM:
+                                       type = immediate;
+                                       break;
+                               case BIND_OPCODE_SET_ADDEND_SLEB:
+                                       addend = read_sleb128(p, end);
+                                       break;
+                               case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+                                       segmentIndex = immediate;
+                                       if ( segmentIndex > fSegmentsCount )
+                                               dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (%d)\n", 
+                                                               segmentIndex, fSegmentsCount);
+                                       address = segActualLoadAddress(segmentIndex) + read_uleb128(p, end);
+                                       segmentEndAddress = segActualEndAddress(segmentIndex);
+                                       break;
+                               case BIND_OPCODE_ADD_ADDR_ULEB:
+                                       address += read_uleb128(p, end);
+                                       break;
+                               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);
+                                       address += sizeof(intptr_t);
+                                       break;
+                               case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+                               case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+                               case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
+                               default:
+                                       dyld::throwf("bad lazy bind opcode %d", *p);
+                       }
+               }
+       }  
+
+       catch (const char* msg) {
+               const char* newMsg = dyld::mkstringf("%s in %s", msg, this->getPath());
+               free((void*)msg);
+               throw newMsg;
+       }
+}
+
+// A program built targeting 10.5 will have hybrid stubs.  When used with weak symbols
+// the classic lazy loader is used even when running on 10.6
+uintptr_t ImageLoaderMachOCompressed::doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context)
+{
+       // only works with compressed LINKEDIT if classic symbol table is also present
+       const macho_nlist* symbolTable = NULL;
+       const char* symbolTableStrings = NULL;
+       const dysymtab_command* dynSymbolTable = NULL;
+       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_SYMTAB:
+                               {
+                                       const struct symtab_command* symtab = (struct symtab_command*)cmd;
+                                       symbolTableStrings = (const char*)&fLinkEditBase[symtab->stroff];
+                                       symbolTable = (macho_nlist*)(&fLinkEditBase[symtab->symoff]);
+                               }
+                               break;
+                       case LC_DYSYMTAB:
+                               dynSymbolTable = (struct dysymtab_command*)cmd;
+                               break;
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+       }
+       // no symbol table => no lookup by address
+       if ( (symbolTable == NULL) || (dynSymbolTable == NULL) )
+               dyld::throwf("classic lazy binding used with compressed LINKEDIT at %p in image %s", lazyPointer, this->getPath());
+
+       // scan for all lazy-pointer sections
+       const bool twoLevel = this->usesTwoLevelNameSpace();
+       const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[dynSymbolTable->indirectsymoff];
+       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;
+                                               uint32_t symbolIndex = INDIRECT_SYMBOL_LOCAL;
+                                               if ( type == S_LAZY_SYMBOL_POINTERS ) {
+                                                       const uint32_t pointerCount = sect->size / sizeof(uintptr_t);
+                                                       uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + fSlide);
+                                                       if ( (lazyPointer >= symbolPointers) && (lazyPointer < &symbolPointers[pointerCount]) ) {
+                                                               const uint32_t indirectTableOffset = sect->reserved1;
+                                                               const uint32_t lazyIndex = lazyPointer - symbolPointers;
+                                                               symbolIndex = indirectTable[indirectTableOffset + lazyIndex];
+                                                       }
+                                               }
+                                               if ( (symbolIndex != INDIRECT_SYMBOL_ABS) && (symbolIndex != INDIRECT_SYMBOL_LOCAL) ) {
+                                                       const macho_nlist* symbol = &symbolTable[symbolIndex];
+                                                       const char* symbolName = &symbolTableStrings[symbol->n_un.n_strx];
+                                                       int libraryOrdinal = GET_LIBRARY_ORDINAL(symbol->n_desc);
+                                                       if ( !twoLevel || context.bindFlat ) 
+                                                               libraryOrdinal = BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
+                                                       uintptr_t ptrToBind = (uintptr_t)lazyPointer;
+                                                       uintptr_t symbolAddr = bindAt(context, ptrToBind, BIND_TYPE_POINTER, symbolName, 0, 0, libraryOrdinal, "lazy ", NULL);
+                                                       ++fgTotalLazyBindFixups;
+                                                       return symbolAddr;
+                                               }
+                                       }
+                               }
+                               break;
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+       }
+       dyld::throwf("lazy pointer not found at address %p in image %s", lazyPointer, this->getPath());
+}
+
+
+uintptr_t ImageLoaderMachOCompressed::doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context)
+{
+       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";
+
+       uint8_t type = BIND_TYPE_POINTER;
+       uintptr_t address = 0;
+       const char* symbolName = NULL;
+       uint8_t symboFlags = 0;
+       int libraryOrdinal = 0;
+       bool done = false;
+       uintptr_t result = 0;
+       const uint8_t* p = &start[lazyBindingInfoOffset];
+       while ( !done && (p < end) ) {
+               uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
+               uint8_t opcode = *p & BIND_OPCODE_MASK;
+               ++p;
+               switch (opcode) {
+                       case BIND_OPCODE_DONE:
+                               done = true;
+                               break;
+                       case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+                               libraryOrdinal = immediate;
+                               break;
+                       case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+                               libraryOrdinal = read_uleb128(p, end);
+                               break;
+                       case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+                               // the special ordinals are negative numbers
+                               if ( immediate == 0 )
+                                       libraryOrdinal = 0;
+                               else {
+                                       int8_t signExtended = BIND_OPCODE_MASK | immediate;
+                                       libraryOrdinal = signExtended;
+                               }
+                               break;
+                       case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+                               symbolName = (char*)p;
+                               symboFlags = immediate;
+                               while (*p != '\0')
+                                       ++p;
+                               ++p;
+                               break;
+                       case BIND_OPCODE_SET_TYPE_IMM:
+                               type = immediate;
+                               break;
+                       case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+                               if ( immediate > fSegmentsCount )
+                                       dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (%d)\n", 
+                                                       immediate, fSegmentsCount);
+                               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);
+                               break;
+                       case BIND_OPCODE_SET_ADDEND_SLEB:
+                       case BIND_OPCODE_ADD_ADDR_ULEB:
+                       case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+                       case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+                       case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
+                       default:
+                               dyld::throwf("bad lazy bind opcode %d", *p);
+               }
+       }       
+       return result;
+}
+
+void ImageLoaderMachOCompressed::initializeCoalIterator(CoalIterator& it, unsigned int loadOrder)
+{
+       it.image = this;
+       it.symbolName = " ";
+       it.loadOrder = loadOrder;
+       it.weakSymbol = false;
+       it.symbolMatches = false;
+       it.done = false;
+       it.curIndex = 0;
+       it.endIndex = this->fDyldInfo->weak_bind_size;
+       it.address = 0;
+       it.type = 0;
+       it.addend = 0;
+}
+
+
+bool ImageLoaderMachOCompressed::incrementCoalIterator(CoalIterator& it)
+{
+       if ( it.done )
+               return false;
+               
+       if ( this->fDyldInfo->weak_bind_size == 0 ) {
+               /// hmmm, ld set MH_WEAK_DEFINES or MH_BINDS_TO_WEAK, but there is no weak binding info
+               it.done = true;
+               it.symbolName = "~~~";
+               return true;
+       }
+       const uint8_t* start = fLinkEditBase + fDyldInfo->weak_bind_off;
+       const uint8_t* p = start + it.curIndex;
+       const uint8_t* end = fLinkEditBase + fDyldInfo->weak_bind_off + this->fDyldInfo->weak_bind_size;
+       uint32_t count;
+       uint32_t skip;
+       while ( p < end ) {
+               uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
+               uint8_t opcode = *p & BIND_OPCODE_MASK;
+               ++p;
+               switch (opcode) {
+                       case BIND_OPCODE_DONE:
+                               it.done = true;
+                               it.curIndex = p - start;
+                               it.symbolName = "~~~"; // sorts to end
+                               return true;
+                       case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+                               it.symbolName = (char*)p;
+                               it.weakSymbol = ((immediate & BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) == 0);
+                               it.symbolMatches = false;
+                               while (*p != '\0')
+                                       ++p;
+                               ++p;
+                               it.curIndex = p - start;
+                               return false;
+                       case BIND_OPCODE_SET_TYPE_IMM:
+                               it.type = immediate;
+                               break;
+                       case BIND_OPCODE_SET_ADDEND_SLEB:
+                               it.addend = read_sleb128(p, end);
+                               break;
+                       case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+                               if ( immediate > fSegmentsCount )
+                                       dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (%d)\n", 
+                                                       immediate, fSegmentsCount);
+                               it.address = segActualLoadAddress(immediate) + read_uleb128(p, end);
+                               break;
+                       case BIND_OPCODE_ADD_ADDR_ULEB:
+                               it.address += read_uleb128(p, end);
+                               break;
+                       case BIND_OPCODE_DO_BIND:
+                               it.address += sizeof(intptr_t);
+                               break;
+                       case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+                               it.address += read_uleb128(p, end) + sizeof(intptr_t);
+                               break;
+                       case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+                               it.address += immediate*sizeof(intptr_t) + sizeof(intptr_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) {
+                                       it.address += skip + sizeof(intptr_t);
+                               }
+                               break;
+                       default:
+                               dyld::throwf("bad weak bind opcode %d", *p);
+               }
+       }
+       /// hmmm, BIND_OPCODE_DONE is missing...
+       it.done = true;
+       it.symbolName = "~~~";
+       //dyld::log("missing BIND_OPCODE_DONE for image %s\n", this->getPath());
+       return true;
+}
+
+uintptr_t ImageLoaderMachOCompressed::getAddressCoalIterator(CoalIterator& it, const LinkContext& context)
+{
+       //dyld::log("looking for %s in %s\n", it.symbolName, this->getPath());
+       const ImageLoader* foundIn = NULL;
+       const ImageLoader::Symbol* sym = this->findExportedSymbol(it.symbolName, &foundIn);
+       if ( sym != NULL ) {
+               //dyld::log("sym=%p, foundIn=%p\n", sym, foundIn);
+               return foundIn->getExportedSymbolAddress(sym, context, this);
+       }
+       return 0;
+}
+
+
+void ImageLoaderMachOCompressed::updateUsesCoalIterator(CoalIterator& it, uintptr_t value, ImageLoader* targetImage, const LinkContext& context)
+{
+       // <rdar://problem/6570879> weak binding done too early with inserted libraries
+       if ( this->getState() < dyld_image_state_bound  )
+               return;
+
+       const uint8_t* start = fLinkEditBase + fDyldInfo->weak_bind_off;
+       const uint8_t* p = start + it.curIndex;
+       const uint8_t* end = fLinkEditBase + fDyldInfo->weak_bind_off + this->fDyldInfo->weak_bind_size;
+
+       uint8_t type = it.type;
+       uintptr_t address = it.address;
+       const char* symbolName = it.symbolName;
+       intptr_t addend = it.addend;
+       uint32_t count;
+       uint32_t skip;
+       bool done = false;
+       bool boundSomething = false;
+       while ( !done && (p < end) ) {
+               uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
+               uint8_t opcode = *p & BIND_OPCODE_MASK;
+               ++p;
+               switch (opcode) {
+                       case BIND_OPCODE_DONE:
+                               done = true;
+                               break;
+                       case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+                               done = true;
+                               break;
+                       case BIND_OPCODE_SET_TYPE_IMM:
+                               type = immediate;
+                               break;
+                       case BIND_OPCODE_SET_ADDEND_SLEB:
+                               addend = read_sleb128(p, end);
+                               break;
+                       case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+                               if ( immediate > fSegmentsCount )
+                                       dyld::throwf("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment %d which is too large (%d)\n", 
+                                                       immediate, fSegmentsCount);
+                               address = segActualLoadAddress(immediate) + read_uleb128(p, end);
+                               break;
+                       case BIND_OPCODE_ADD_ADDR_ULEB:
+                               address += read_uleb128(p, end);
+                               break;
+                       case BIND_OPCODE_DO_BIND:
+                               bindLocation(context, address, value, targetImage, type, symbolName, addend, "weak ");
+                               boundSomething = true;
+                               address += sizeof(intptr_t);
+                               break;
+                       case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+                               bindLocation(context, address, value, targetImage, type, symbolName, addend, "weak ");
+                               boundSomething = true;
+                               address += read_uleb128(p, end) + sizeof(intptr_t);
+                               break;
+                       case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+                               bindLocation(context, address, value, targetImage, type, symbolName, addend, "weak ");
+                               boundSomething = true;
+                               address += immediate*sizeof(intptr_t) + sizeof(intptr_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) {
+                                       bindLocation(context, address, value, targetImage, type, symbolName, addend, "weak ");
+                                       boundSomething = true;
+                                       address += skip + sizeof(intptr_t);
+                               }
+                               break;
+                       default:
+                               dyld::throwf("bad bind opcode %d in weak binding info", *p);
+               }
+       }       
+       if ( boundSomething && (targetImage != this) && !targetImage->neverUnload() )
+               this->addDynamicReference(targetImage);
+}
+
+
+
+
+
+const char* ImageLoaderMachOCompressed::findClosestSymbol(const void* addr, const void** closestAddr) const
+{
+       // called by dladdr()
+       // only works with compressed LINKEDIT if classic symbol table is also present
+       const macho_nlist* symbolTable = NULL;
+       const char* symbolTableStrings = NULL;
+       const dysymtab_command* dynSymbolTable = NULL;
+       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_SYMTAB:
+                               {
+                                       const struct symtab_command* symtab = (struct symtab_command*)cmd;
+                                       symbolTableStrings = (const char*)&fLinkEditBase[symtab->stroff];
+                                       symbolTable = (macho_nlist*)(&fLinkEditBase[symtab->symoff]);
+                               }
+                               break;
+                       case LC_DYSYMTAB:
+                               dynSymbolTable = (struct dysymtab_command*)cmd;
+                               break;
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+       }
+       // no symbol table => no lookup by address
+       if ( (symbolTable == NULL) || (dynSymbolTable == NULL) )
+               return NULL;
+
+       uintptr_t targetAddress = (uintptr_t)addr - fSlide;
+       const struct macho_nlist* bestSymbol = NULL;
+       // first walk all global symbols
+       const struct macho_nlist* const globalsStart = &symbolTable[dynSymbolTable->iextdefsym];
+       const struct macho_nlist* const globalsEnd= &globalsStart[dynSymbolTable->nextdefsym];
+       for (const struct macho_nlist* s = globalsStart; s < globalsEnd; ++s) {
+               if ( (s->n_type & N_TYPE) == N_SECT ) {
+                       if ( bestSymbol == NULL ) {
+                               if ( s->n_value <= targetAddress )
+                                       bestSymbol = s;
+                       }
+                       else if ( (s->n_value <= targetAddress) && (bestSymbol->n_value < s->n_value) ) {
+                               bestSymbol = s;
+                       }
+               }
+       }
+       // next walk all local symbols
+       const struct macho_nlist* const localsStart = &symbolTable[dynSymbolTable->ilocalsym];
+       const struct macho_nlist* const localsEnd= &localsStart[dynSymbolTable->nlocalsym];
+       for (const struct macho_nlist* s = localsStart; s < localsEnd; ++s) {
+               if ( ((s->n_type & N_TYPE) == N_SECT) && ((s->n_type & N_STAB) == 0) ) {
+                       if ( bestSymbol == NULL ) {
+                               if ( s->n_value <= targetAddress )
+                                       bestSymbol = s;
+                       }
+                       else if ( (s->n_value <= targetAddress) && (bestSymbol->n_value < s->n_value) ) {
+                               bestSymbol = s;
+                       }
+               }
+       }
+       if ( bestSymbol != NULL ) {
+               *closestAddr = (void*)(bestSymbol->n_value + fSlide);
+               return &symbolTableStrings[bestSymbol->n_un.n_strx];
+       }
+       return NULL;
+}
+
+
+#if PREBOUND_IMAGE_SUPPORT
+void ImageLoaderMachOCompressed::resetPreboundLazyPointers(const LinkContext& context)
+{
+       // no way to back off a prebound compress image
+}
+#endif
+
diff --git a/src/ImageLoaderMachOCompressed.h b/src/ImageLoaderMachOCompressed.h
new file mode 100644 (file)
index 0000000..ae137c0
--- /dev/null
@@ -0,0 +1,135 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2008 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 __IMAGELOADER_MACHO_COMPRESSED__
+#define __IMAGELOADER_MACHO_COMPRESSED__
+
+#include <stdint.h> 
+
+#include "ImageLoaderMachO.h"
+
+
+//
+// ImageLoaderMachOCompressed is the concrete subclass of ImageLoader which loads mach-o files 
+// that use the compressed LINKEDIT format.  
+//
+class ImageLoaderMachOCompressed : public ImageLoaderMachO {
+public:
+       static ImageLoaderMachOCompressed*      instantiateMainExecutable(const macho_header* mh, uintptr_t slide, const char* path, 
+                                                                                                                                       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 LinkContext& context);
+       static ImageLoaderMachOCompressed*      instantiateFromMemory(const char* moduleName, const macho_header* mh, uint64_t len, 
+                                                                                                                       unsigned int segCount, unsigned int libCount, const LinkContext& context);
+
+
+       virtual                                                         ~ImageLoaderMachOCompressed();
+
+       virtual ImageLoader*                            libImage(unsigned int) const;
+       virtual bool                                            libReExported(unsigned int) const;
+       virtual void                                            setLibImage(unsigned int, ImageLoader*, 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 const char*                                     findClosestSymbol(const void* addr, const void** closestAddr) const;
+       virtual void                                            initializeCoalIterator(CoalIterator&, unsigned int loadOrder);
+       virtual bool                                            incrementCoalIterator(CoalIterator&);
+       virtual uintptr_t                                       getAddressCoalIterator(CoalIterator&, const LinkContext& contex);
+       virtual void                                            updateUsesCoalIterator(CoalIterator&, uintptr_t newAddr, ImageLoader* target, const LinkContext& context);
+
+       
+protected:
+       virtual void                                            setDyldInfo(const dyld_info_command* dyldInfo) { fDyldInfo = dyldInfo; }
+       virtual void                                            setSymbolTableInfo(const macho_nlist*, const char*, const dysymtab_command*) {}
+       virtual bool                                            isSubframeworkOf(const LinkContext& context, const ImageLoader* image) const { return false; }
+       virtual bool                                            hasSubLibrary(const LinkContext& context, const ImageLoader* child) const { return false; }
+       virtual uint32_t*                                       segmentCommandOffsets() const;
+       virtual void                                            rebase(const LinkContext& context);
+       virtual const ImageLoader::Symbol*      findExportedSymbol(const char* name, const ImageLoader** foundIn) const;
+       virtual bool                                            containsSymbol(const void* addr) const;
+       virtual uintptr_t                                       exportedSymbolAddress(const Symbol* symbol) const;
+       virtual bool                                            exportedSymbolIsWeakDefintion(const Symbol* symbol) const;
+       virtual const char*                                     exportedSymbolName(const Symbol* symbol) const;
+       virtual unsigned int                            exportedSymbolCount() const;
+       virtual const ImageLoader::Symbol*      exportedSymbolIndexed(unsigned int) const;
+       virtual unsigned int                            importedSymbolCount() const;
+       virtual const ImageLoader::Symbol*      importedSymbolIndexed(unsigned int) const;
+       virtual const char*                                     importedSymbolName(const Symbol* symbol) const;
+#if PREBOUND_IMAGE_SUPPORT
+       virtual void                                            resetPreboundLazyPointers(const LinkContext& context);
+#endif
+
+               
+private:
+       struct LastLookup { int ordinal; uint8_t flags; const char* name; uintptr_t result; const ImageLoader* foundIn; };
+
+
+       typedef uintptr_t (ImageLoaderMachOCompressed::*bind_handler)(const LinkContext& context, uintptr_t addr, uint8_t type, 
+                                                                                       const char* symbolName, uint8_t symboFlags, intptr_t addend, int libraryOrdinal, 
+                                                                                       const char* msg, LastLookup* last);
+
+       void                                                            eachLazyBind(const LinkContext& context, bind_handler);
+       void                                                            eachBind(const LinkContext& context, bind_handler);
+
+
+                                                                               ImageLoaderMachOCompressed(const macho_header* mh, const char* path, unsigned int segCount,
+                                                                                                                                       uint32_t segOffsets[], unsigned int libCount);
+       static ImageLoaderMachOCompressed*      instantiateStart(const macho_header* mh, const char* path, unsigned int segCount, unsigned int libCount);
+       void                                                            instantiateFinish(const LinkContext& context);
+       void                                                            markSequentialLINKEDIT(const LinkContext& context);
+       void                                                            markFreeLINKEDIT(const LinkContext& context);
+       void                                                            markLINKEDIT(const LinkContext& context, int advise);
+
+       void                                                            rebaseAt(const LinkContext& context, uintptr_t addr, uintptr_t slide, uint8_t type);
+       void                                                            throwBadRebaseAddress(uintptr_t address, uintptr_t segmentEndAddress, int segmentIndex, 
+                                                                                               const uint8_t* startOpcodes, const uint8_t* endOpcodes, const uint8_t* pos);
+       uintptr_t                                                       bindAt(const LinkContext& context, uintptr_t addr, uint8_t type, const char* symbolName, 
+                                                                                               uint8_t symboFlags, intptr_t addend, int libraryOrdinal, const char* msg,
+                                                                                               LastLookup* last);
+       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, 
+                                                                                                       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 struct dyld_info_command*                 fDyldInfo;
+};
+
+
+
+#endif // __IMAGELOADER_MACHO_COMPRESSED__
+
+
+
+
diff --git a/src/ImageLoaderPE.cpp b/src/ImageLoaderPE.cpp
deleted file mode 100644 (file)
index 173dda8..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
-*
-* Copyright (c) 2007 AppleInc. 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@
-*/
-
diff --git a/src/ImageLoaderPE.h b/src/ImageLoaderPE.h
deleted file mode 100644 (file)
index 24812d5..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
- *
- * 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@
- */
-
-
index 93cfaaab79281d9d0df958b4dd7849075054c491..3d5bcd000bdb7cd7a7305d69a04149482f31ef51 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2008 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <sys/sysctl.h>
 #include <sys/mman.h>
 #include <sys/dtrace.h>
+#include <libkern/OSAtomic.h>
+
+#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
 
 #include <vector>
 #include <algorithm>
 #include "ImageLoader.h"
 #include "ImageLoaderMachO.h"
 #include "dyldLibSystemInterface.h"
+#if DYLD_SHARED_CACHE_SUPPORT
 #include "dyld_cache_format.h"
+#endif
+#if CORESYMBOLICATION_SUPPORT
+#include "coreSymbolicationDyldSupport.hpp"
+#endif
 
 // from _simple.h in libc
 typedef struct _SIMPLE*                _SIMPLE_STRING;
@@ -62,11 +78,9 @@ extern "C" char *                    _simple_string(_SIMPLE_STRING __b);
 
 
 
-// 32-bit ppc is only architecture that uses cpu-sub-types
-#define CPU_SUBTYPES_SUPPORTED __ppc__ 
-
+// 32-bit ppc and ARM are the only architecture that use cpu-sub-types
+#define CPU_SUBTYPES_SUPPORTED __ppc__ || __arm__
 
-#define OLD_GDB_DYLD_INTERFACE __ppc__ || __i386__
 
 
 #define CPU_TYPE_MASK 0x00FFFFFF       /* complement of CPU_ARCH_MASK */
@@ -75,10 +89,7 @@ extern "C" char *                    _simple_string(_SIMPLE_STRING __b);
 /* implemented in dyld_gdb.cpp */
 extern void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[]);
 extern void removeImageFromAllImages(const mach_header* mh);
-#if OLD_GDB_DYLD_INTERFACE
-extern void addImageForgdb(const mach_header* mh, uintptr_t slide, const char* physicalPath, const char* logicalPath);
-extern void removeImageForgdb(const struct mach_header* mh);
-#endif
+extern void setAlImageInfosHalt(const char* message, uintptr_t flags);
 
 // magic so CrashReporter logs message
 extern "C" {
@@ -110,7 +121,6 @@ struct EnvironmentVariables {
        const char* const *                     DYLD_FALLBACK_FRAMEWORK_PATH;
        const char* const *                     DYLD_LIBRARY_PATH;
        const char* const *                     DYLD_FALLBACK_LIBRARY_PATH;
-       const char*     const *                 DYLD_ROOT_PATH;
        const char* const *                     DYLD_INSERT_LIBRARIES;
        const char* const *                     LD_LIBRARY_PATH;                        // for unix conformance
        bool                                            DYLD_PRINT_LIBRARIES;
@@ -120,6 +130,9 @@ struct EnvironmentVariables {
        bool                                            DYLD_PRINT_OPTS;
        bool                                            DYLD_PRINT_ENV;
        bool                                            DYLD_DISABLE_DOFS;
+                            //  DYLD_SHARED_CACHE_DONT_VALIDATE ==> sSharedCacheIgnoreInodeAndTimeStamp
+                            //  DYLD_SHARED_CACHE_DIR           ==> sSharedCacheDir
+                                                       //      DYLD_ROOT_PATH                                  ==> gLinkContext.rootPaths
                                                        //      DYLD_IMAGE_SUFFIX                               ==> gLinkContext.imageSuffix
                                                        //      DYLD_PRINT_OPTS                                 ==> gLinkContext.verboseOpts
                                                        //      DYLD_PRINT_ENV                                  ==> gLinkContext.verboseEnv
@@ -127,6 +140,7 @@ struct EnvironmentVariables {
                                                        //      DYLD_PRINT_INITIALIZERS                 ==> gLinkContext.verboseInit
                                                        //      DYLD_PRINT_SEGMENTS                             ==> gLinkContext.verboseMapping
                                                        //      DYLD_PRINT_BINDINGS                             ==> gLinkContext.verboseBind
+                                                       //  DYLD_PRINT_WEAK_BINDINGS            ==> gLinkContext.verboseWeakBind
                                                        //      DYLD_PRINT_REBASINGS                    ==> gLinkContext.verboseRebase
                                                        //      DYLD_PRINT_DOFS                                 ==> gLinkContext.verboseDOF
                                                        //      DYLD_PRINT_APIS                                 ==> gLogAPIs
@@ -136,25 +150,22 @@ struct EnvironmentVariables {
                                                        //      DYLD_SHARED_REGION                              ==> gLinkContext.sharedRegionMode
                                                        //      DYLD_PRINT_WARNINGS                             ==> gLinkContext.verboseWarnings
 };
-
+        
 typedef std::vector<dyld_image_state_change_handler> StateHandlers;
 struct RegisteredDOF { const mach_header* mh; int registrationID; };
 
 // all global state
 static const char*                                     sExecPath = NULL;
-static const struct mach_header*       sMainExecutableMachHeader = NULL;
+static const macho_header*                     sMainExecutableMachHeader = NULL;
 static cpu_type_t                                      sHostCPU;
 static cpu_subtype_t                           sHostCPUsubtype;
 static ImageLoader*                                    sMainExecutable = NULL;
-static bool                                                    sMainExecutableIsSetuid = false;
+static bool                                                    sProcessIsRestricted = false;
 static unsigned int                                    sInsertedDylibCount = 0;
 static std::vector<ImageLoader*>       sAllImages;
 static std::vector<ImageLoader*>       sImageRoots;
 static std::vector<ImageLoader*>       sImageFilesNeedingTermination;
 static std::vector<RegisteredDOF>      sImageFilesNeedingDOFUnregistration;
-#if IMAGE_NOTIFY_SUPPORT
-static std::vector<ImageLoader*>       sImagesToNotifyAboutOtherImages;
-#endif
 static std::vector<ImageCallback>   sAddImageCallbacks;
 static std::vector<ImageCallback>   sRemoveImageCallbacks;
 static StateHandlers                           sSingleHandlers[7];
@@ -163,15 +174,12 @@ static ImageLoader*                                       sLastImageByAddressCache;
 static EnvironmentVariables                    sEnv;
 static const char*                                     sFrameworkFallbackPaths[] = { "$HOME/Library/Frameworks", "/Library/Frameworks", "/Network/Library/Frameworks", "/System/Library/Frameworks", NULL };
 static const char*                                     sLibraryFallbackPaths[] = { "$HOME/lib", "/usr/local/lib", "/usr/lib", NULL };
-static BundleNotificationCallBack   sBundleNotifier = NULL;
-static BundleLocatorCallBack           sBundleLocation = NULL;
 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;
-bool                                                           gSharedCacheNotFound = false;
-bool                                                           gSharedCacheNeedsUpdating = false;
-bool                                                           gSharedCacheDontNotify = false;
+static bool                                                    sSharedCacheIgnoreInodeAndTimeStamp = false;
+static const char*                                     sSharedCacheDir = DYLD_SHARED_CACHE_DIR;
 #endif
 ImageLoader::LinkContext                       gLinkContext;
 bool                                                           gLogAPIs = false;
@@ -179,52 +187,139 @@ const struct LibSystemHelpers*           gLibSystemHelpers = NULL;
 #if SUPPORT_OLD_CRT_INITIALIZATION
 bool                                                           gRunInitializersOldWay = false;
 #endif
-#if __i386__
-static uint32_t                                                sImportSegmentsStart = 0;
-static uint32_t                                                sImportSegmentsSize = 0;
-#endif
+
+
+//
+// The MappedRanges structure is used for fast address->image lookups.
+// The table is only updated when the dyld lock is held, so we don't
+// need to worry about multiple writers.  But readers may look at this
+// data without holding the lock. Therefore, all updates must be done
+// in an order that will never cause readers to see inconsistent data.
+// The general rule is that if the image field is non-NULL then
+// the other fields are valid.
+//
+struct MappedRanges
+{
+       enum { count=400 };
+       struct {
+               ImageLoader*    image;
+               uintptr_t               start;
+               uintptr_t               end;
+       } array[count];
+       MappedRanges*           next;
+};
+
+static MappedRanges                    sMappedRangesStart;
+
+void addMappedRange(ImageLoader* image, uintptr_t start, uintptr_t end)
+{
+       //dyld::log("addMappedRange(0x%lX->0x%lX) for %s\n", start, end, image->getShortName());
+       for (MappedRanges* p = &sMappedRangesStart; p != NULL; p = p->next) {
+               for (int i=0; i < MappedRanges::count; ++i) {
+                       if ( p->array[i].image == NULL ) {
+                               p->array[i].start = start;
+                               p->array[i].end = end;
+                               // add image field last with a barrier so that any reader will see consistent records
+                               OSMemoryBarrier();
+                               p->array[i].image = image;
+                               return;
+                       }
+               }
+       }
+       // table must be full, chain another
+       MappedRanges* newRanges = (MappedRanges*)malloc(sizeof(MappedRanges));
+       bzero(newRanges, sizeof(MappedRanges));
+       newRanges->array[0].start = start;
+       newRanges->array[0].end = end;
+       newRanges->array[0].image = image;
+       for (MappedRanges* p = &sMappedRangesStart; p != NULL; p = p->next) {
+               if ( p->next == NULL ) {
+                       OSMemoryBarrier();
+                       p->next = newRanges;
+                       break;
+               }
+       }
+}
+
+void removedMappedRanges(ImageLoader* image)
+{
+       for (MappedRanges* p = &sMappedRangesStart; p != NULL; p = p->next) {
+               for (int i=0; i < MappedRanges::count; ++i) {
+                       if ( p->array[i].image == image ) {
+                               // clear with a barrier so that any reader will see consistent records
+                               OSMemoryBarrier();
+                               p->array[i].image = NULL;
+                       }
+               }
+       }
+}
+
+ImageLoader* findMappedRange(uintptr_t target)
+{
+       for (MappedRanges* p = &sMappedRangesStart; p != NULL; p = p->next) {
+               for (int i=0; i < MappedRanges::count; ++i) {
+                       if ( p->array[i].image != NULL ) {
+                               if ( (p->array[i].start <= target) && (target < p->array[i].end) )
+                                       return p->array[i].image;
+                       }
+               }
+       }
+       return NULL;
+}
 
 
 
 const char* mkstringf(const char* format, ...)
 {
-       va_list list;
-       va_start(list, format);
        _SIMPLE_STRING buf = _simple_salloc();
-       _simple_vsprintf(buf, format, list);
-       va_end(list);
-       const char*     t = strdup(_simple_string(buf));
-       _simple_sfree(buf);
-       return t;
+       if ( buf != NULL ) {
+               va_list list;
+               va_start(list, format);
+               _simple_vsprintf(buf, format, list);
+               va_end(list);
+               const char*     t = strdup(_simple_string(buf));
+               _simple_sfree(buf);
+               if ( t != NULL )
+                       return t;
+       }
+       return "mkstringf, out of memory error";
 }
 
 
 void throwf(const char* format, ...) 
 {
-       va_list list;
-       va_start(list, format);
        _SIMPLE_STRING buf = _simple_salloc();
-       _simple_vsprintf(buf, format, list);
-       va_end(list);
-       const char*     t = strdup(_simple_string(buf));
-       _simple_sfree(buf);
-       throw t;
+       if ( buf != NULL ) {
+               va_list list;
+               va_start(list, format);
+               _simple_vsprintf(buf, format, list);
+               va_end(list);
+               const char*     t = strdup(_simple_string(buf));
+               _simple_sfree(buf);
+               if ( t != NULL )
+                       throw t;
+       }
+       throw "throwf, out of memory error";
 }
 
+
+//#define ALTERNATIVE_LOGFILE "/dev/console"
+static int sLogfile = STDERR_FILENO;
+
 void log(const char* format, ...) 
 {
        va_list list;
        va_start(list, format);
-       _simple_vdprintf(STDERR_FILENO, format, list);
+       _simple_vdprintf(sLogfile, format, list);
        va_end(list);
 }
 
 void warn(const char* format, ...) 
 {
-       _simple_dprintf(STDERR_FILENO, "dyld: warning, ");
+       _simple_dprintf(sLogfile, "dyld: warning, ");
        va_list list;
        va_start(list, format);
-       _simple_vdprintf(STDERR_FILENO, format, list);
+       _simple_vdprintf(sLogfile, format, list);
        va_end(list);
 }
 
@@ -344,29 +439,6 @@ static const char* notifyGDB(enum dyld_image_states state, uint32_t infoCount, c
        return NULL;
 }
 
-#if IMAGE_NOTIFY_SUPPORT
-// notify objc about these new images
-static void notifyAdding(const ImageLoader* const * images, unsigned int count)
-{
-       // build array
-       if ( count != 0 ) {
-               dyld_image_info infos[count];
-               for (unsigned int i=0; i < count; ++i) {
-                       dyld_image_info* p = &infos[i];
-                       const ImageLoader* image = images[i];
-                       p->imageLoadAddress = image->machHeader();
-                       p->imageFilePath = image->getPath();
-                       p->imageFileModDate = image->lastModified();
-                       //dyld::log("notifying objc about %s\n", image->getPath());
-               }
-               
-               // tell all interested images (after gdb, so you can debug anything the notification does)
-               for (std::vector<ImageLoader*>::iterator it=sImagesToNotifyAboutOtherImages.begin(); it != sImagesToNotifyAboutOtherImages.end(); it++) {
-                       (*it)->doNotification(dyld_image_adding, count, infos);
-               }
-       }
-}
-#endif
 
 static StateHandlers* stateToHandlers(dyld_image_states state, StateHandlers handlersArray[8]) 
 {
@@ -395,14 +467,16 @@ static StateHandlers* stateToHandlers(dyld_image_states state, StateHandlers han
        return NULL;
 }
 
-static void notifySingle(dyld_image_states state, const struct mach_header* mh, const char* path, time_t modDate)
+
+static void notifySingle(dyld_image_states state, const ImageLoader* image)
 {
+       //dyld::log("notifySingle(state=%d, image=%s)\n", state, image->getPath());
        std::vector<dyld_image_state_change_handler>* handlers = stateToHandlers(state, sSingleHandlers);
        if ( handlers != NULL ) {
                dyld_image_info info;
-               info.imageLoadAddress   = mh;
-               info.imageFilePath              = path;
-               info.imageFileModDate   = modDate;
+               info.imageLoadAddress   = image->machHeader();
+               info.imageFilePath              = image->getPath();
+               info.imageFileModDate   = image->lastModified();
                for (std::vector<dyld_image_state_change_handler>::iterator it = handlers->begin(); it != handlers->end(); ++it) {
                        const char* result = (*it)(state, 1, &info);
                        if ( (result != NULL) && (state == dyld_image_state_mapped) ) {
@@ -413,10 +487,20 @@ static void notifySingle(dyld_image_states state, const struct mach_header* mh,
                        }
                }
        }
+#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 ) {
+                               coresymbolication_unload_image(connection, image);
+                       }
+               }
+       }
+#endif 
 }
 
 
-
 static int imageSorter(const void* l, const void* r)
 {
        const ImageLoader* left = *((ImageLoader**)l);
@@ -482,6 +566,22 @@ 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 ) {
+                               // 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++) {
+                                       dyld_image_states imageState = (*it)->getState();
+                                       if ( (imageState == state) || (orLater && (imageState > state)) )
+                                               coresymbolication_load_image(connection, *it, load_timestamp);
+                               }
+                       }
+               }
+       }
+#endif
 }
 
 static void notifyBatch(dyld_image_states state)
@@ -500,14 +600,6 @@ static void addRootImage(ImageLoader* image)
        sImageRoots.push_back(image);
 }
 
-#if IMAGE_NOTIFY_SUPPORT
-// Objective-C will contain a __DATA/__image_notify section which contains pointers to a function to call
-// whenever any new image is loaded.
-static void addImageNeedingNotification(ImageLoader* image)
-{
-       sImagesToNotifyAboutOtherImages.push_back(image);
-}
-#endif
 
 static void clearAllDepths()
 {
@@ -520,29 +612,6 @@ static unsigned int imageCount()
        return sAllImages.size();
 }
 
-static void notifySharedCacheInvalid()
-{
-       gSharedCacheNeedsUpdating = true;
-}
-
-
-
-#if __i386__
-static void makeSharedCacheImportSegmentsWritable(bool writable)
-{
-       // if cache was built with read-only __IMPORT segments
-       if ( sImportSegmentsSize != 0 ) {
-               vm_prot_t prot = VM_PROT_EXECUTE | PROT_READ;
-               if ( writable )
-                       prot |= VM_PROT_WRITE;
-               vm_protect(mach_task_self(), sImportSegmentsStart, sImportSegmentsSize, false, prot);
-               if ( gLinkContext.verboseMapping ) {
-                       dyld::log("%18s at %p->%p altered permissions to %c%c%c\n", "", (char*)sImportSegmentsStart, (char*)sImportSegmentsStart+sImportSegmentsSize-1,
-                               (prot & PROT_READ) ? 'r' : '.',  (prot & PROT_WRITE) ? 'w' : '.',  (prot & PROT_EXEC) ? 'x' : '.' );
-               }
-       }
-}
-#endif
 
 static void setNewProgramVars(const ProgramVars& newVars)
 {
@@ -568,14 +637,34 @@ static void addImage(ImageLoader* image)
        // add to master list
        sAllImages.push_back(image);
        
+       // update mapped ranges
+       uintptr_t lastSegStart = 0;
+       uintptr_t lastSegEnd = 0;
+       for(unsigned int i=0, e=image->segmentCount(); i < e; ++i) {
+               if ( image->segUnaccessible(i) ) 
+                       continue;
+               uintptr_t start = image->segActualLoadAddress(i);
+               uintptr_t end = image->segActualEndAddress(i);
+               if ( start == lastSegEnd ) {
+                       // two segments are contiguous, just record combined segments
+                       lastSegEnd = end;
+               }
+               else {
+                       // non-contiguous segments, record last (if any)
+                       if ( lastSegEnd != 0 )
+                               addMappedRange(image, lastSegStart, lastSegEnd);
+                       lastSegStart = start;
+                       lastSegEnd = end;
+               }               
+       }
+       if ( lastSegEnd != 0 )
+               addMappedRange(image, lastSegStart, lastSegEnd);
+
+       
        if ( sEnv.DYLD_PRINT_LIBRARIES || (sEnv.DYLD_PRINT_LIBRARIES_POST_LAUNCH && (sMainExecutable!=NULL) && sMainExecutable->isLinked()) ) {
                dyld::log("dyld: loaded: %s\n", image->getPath());
        }
        
-#if OLD_GDB_DYLD_INTERFACE
-       // let gdb find out about this
-       addImageForgdb(image->machHeader(), image->getSlide(), image->getPath(), image->getLogicalPath());
-#endif
 }
 
 void removeImage(ImageLoader* image)
@@ -601,7 +690,7 @@ void removeImage(ImageLoader* image)
                }
        }
        
-       // tell all register add image handlers about this
+       // tell all registered remove image handlers about this
        // do this before removing image from internal data structures so that the callback can query dyld about the image
        if ( image->getState() >= dyld_image_state_bound ) {
                for (std::vector<ImageCallback>::iterator it=sRemoveImageCallbacks.begin(); it != sRemoveImageCallbacks.end(); it++) {
@@ -609,16 +698,11 @@ void removeImage(ImageLoader* image)
                }
        }
        
-#if IMAGE_NOTIFY_SUPPORT
-       // tell all interested images
-       for (std::vector<ImageLoader*>::iterator it=sImagesToNotifyAboutOtherImages.begin(); it != sImagesToNotifyAboutOtherImages.end(); it++) {
-               dyld_image_info info;
-               info.imageLoadAddress = image->machHeader();
-               info.imageFilePath = image->getPath();
-               info.imageFileModDate = image->lastModified();
-               (*it)->doNotification(dyld_image_removing, 1, &info);
-       }
-#endif
+       // notify 
+       notifySingle(dyld_image_state_terminated, image);
+       
+       // remove from mapped images table
+       removedMappedRanges(image);
 
        // remove from master list
        for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
@@ -632,16 +716,6 @@ void removeImage(ImageLoader* image)
        if ( sLastImageByAddressCache == image )
                sLastImageByAddressCache = NULL;
 
-#if IMAGE_NOTIFY_SUPPORT
-       // if in announcement list, pull it out 
-       for (std::vector<ImageLoader*>::iterator it=sImagesToNotifyAboutOtherImages.begin(); it != sImagesToNotifyAboutOtherImages.end(); it++) {
-               if ( *it == image ) {
-                       sImagesToNotifyAboutOtherImages.erase(it);
-                       break;
-               }
-       }
-#endif
-
        // if in root list, pull it out 
        for (std::vector<ImageLoader*>::iterator it=sImageRoots.begin(); it != sImageRoots.end(); it++) {
                if ( *it == image ) {
@@ -657,12 +731,6 @@ void removeImage(ImageLoader* image)
 
        // tell gdb, new way
        removeImageFromAllImages(image->machHeader());
-
-#if OLD_GDB_DYLD_INTERFACE
-       // tell gdb, old way
-       removeImageForgdb(image->machHeader());
-       gdb_dyld_state_changed();
-#endif
 }
 
 
@@ -683,12 +751,6 @@ void initializeMainExecutable()
        // record that we've reached this step
        gLinkContext.startedInitializingMainExecutable = true;
 
-#if __i386__
-       // make all __IMPORT segments in the shared cache read-only
-       // before executing any code
-       makeSharedCacheImportSegmentsWritable(false);
-#endif
-
        // run initialzers for any inserted dylibs
        const int rootCount = sImageRoots.size();
        if ( rootCount > 1 ) {
@@ -725,7 +787,6 @@ void runTerminators(void* extra)
        for(unsigned int i=imageCount; i > 0; --i){
                ImageLoader* image = sImageFilesNeedingTermination[i-1];
                image->doTermination(gLinkContext);
-               notifySingle(dyld_image_state_terminated, image->machHeader(), image->getPath(), image->lastModified());
        }
        sImageFilesNeedingTermination.clear();
        notifyBatch(dyld_image_state_terminated);
@@ -739,9 +800,11 @@ void runTerminators(void* extra)
 //
 static const char** parseColonList(const char* list)
 {
-       if ( list[0] == '\0' )
-               return NULL;
+       static const char* sEmptyList[] = { NULL };
 
+       if ( list[0] == '\0' ) 
+               return sEmptyList;
+       
        int colonCount = 0;
        for(const char* s=list; *s != '\0'; ++s) {
                if (*s == ':') 
@@ -839,40 +902,33 @@ void processDyldEnvironmentVarible(const char* key, const char* value)
 {
        if ( strcmp(key, "DYLD_FRAMEWORK_PATH") == 0 ) {
                sEnv.DYLD_FRAMEWORK_PATH = parseColonList(value);
-               gSharedCacheDontNotify = true;
        }
        else if ( strcmp(key, "DYLD_FALLBACK_FRAMEWORK_PATH") == 0 ) {
                sEnv.DYLD_FALLBACK_FRAMEWORK_PATH = parseColonList(value);
-               gSharedCacheDontNotify = true;
        }
        else if ( strcmp(key, "DYLD_LIBRARY_PATH") == 0 ) {
                sEnv.DYLD_LIBRARY_PATH = parseColonList(value);
-               gSharedCacheDontNotify = true;
        }
        else if ( strcmp(key, "DYLD_FALLBACK_LIBRARY_PATH") == 0 ) {
                sEnv.DYLD_FALLBACK_LIBRARY_PATH = parseColonList(value);
-               gSharedCacheDontNotify = true;
        }
        else if ( (strcmp(key, "DYLD_ROOT_PATH") == 0) || (strcmp(key, "DYLD_PATHS_ROOT") == 0) ) {
-               gSharedCacheDontNotify = true;
                if ( strcmp(value, "/") != 0 ) {
-                       sEnv.DYLD_ROOT_PATH = parseColonList(value);
-                       for (int i=0; sEnv.DYLD_ROOT_PATH[i] != NULL; ++i) {
-                               if ( sEnv.DYLD_ROOT_PATH[i][0] != '/' ) {
+                       gLinkContext.rootPaths = parseColonList(value);
+                       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");
-                                       sEnv.DYLD_ROOT_PATH = NULL;
+                                       gLinkContext.rootPaths = NULL;
                                        break;
                                }
                        }
                }
        } 
        else if ( strcmp(key, "DYLD_IMAGE_SUFFIX") == 0 ) {
-               gSharedCacheDontNotify = true;
                gLinkContext.imageSuffix = value;
        }
        else if ( strcmp(key, "DYLD_INSERT_LIBRARIES") == 0 ) {
                sEnv.DYLD_INSERT_LIBRARIES = parseColonList(value);
-               gSharedCacheDontNotify = true;
        }
        else if ( strcmp(key, "DYLD_PRINT_OPTS") == 0 ) {
                sEnv.DYLD_PRINT_OPTS = true;
@@ -902,7 +958,6 @@ void processDyldEnvironmentVarible(const char* key, const char* value)
                // ignore, no longer relevant but some scripts still set it
        }
        else if ( strcmp(key, "DYLD_NO_FIX_PREBINDING") == 0 ) {
-               gSharedCacheDontNotify = true;
        }
        else if ( strcmp(key, "DYLD_PREBIND_DEBUG") == 0 ) {
                gLinkContext.verbosePrebinding = true;
@@ -922,6 +977,9 @@ void processDyldEnvironmentVarible(const char* key, const char* value)
        else if ( strcmp(key, "DYLD_PRINT_BINDINGS") == 0 ) {
                gLinkContext.verboseBind = true;
        }
+       else if ( strcmp(key, "DYLD_PRINT_WEAK_BINDINGS") == 0 ) {
+               gLinkContext.verboseWeakBind = true;
+       }
        else if ( strcmp(key, "DYLD_PRINT_REBASINGS") == 0 ) {
                gLinkContext.verboseRebase = true;
        }
@@ -931,8 +989,10 @@ 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_SHARED_REGION") == 0 ) {
-               gSharedCacheDontNotify = true;
                if ( strcmp(value, "private") == 0 ) {
                        gLinkContext.sharedRegionMode = ImageLoader::kUsePrivateSharedRegion;
                }
@@ -949,8 +1009,15 @@ void processDyldEnvironmentVarible(const char* key, const char* value)
                        dyld::warn("unknown option to DYLD_SHARED_REGION.  Valid options are: use, private, avoid\n");
                }
        }
+#if DYLD_SHARED_CACHE_SUPPORT
+       else if ( strcmp(key, "DYLD_SHARED_CACHE_DIR") == 0 ) {
+        sSharedCacheDir = value;
+       }
+       else if ( strcmp(key, "DYLD_SHARED_CACHE_DONT_VALIDATE") == 0 ) {
+               sSharedCacheIgnoreInodeAndTimeStamp = true;
+       }
+#endif
        else if ( strcmp(key, "DYLD_IGNORE_PREBINDING") == 0 ) {
-               gSharedCacheDontNotify = true;
                if ( strcmp(value, "all") == 0 ) {
                        gLinkContext.prebindUsage = ImageLoader::kUseNoPrebinding;
                }
@@ -980,9 +1047,6 @@ void processDyldEnvironmentVarible(const char* key, const char* value)
 //
 static void pruneEnvironmentVariables(const char* envp[], const char*** applep)
 {
-       // setuit binaries don't trigger a cache rebuild
-       gSharedCacheDontNotify = true;
-
        // delete all DYLD_* and LD_LIBRARY_PATH environment variables
        int removedCount = 0;
        const char** d = envp;
@@ -1065,7 +1129,6 @@ static void getHostInfo()
        mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
        mach_port_t hostPort = mach_host_self();
        kern_return_t result = host_info(hostPort, HOST_BASIC_INFO, (host_info_t)&info, &count);
-       mach_port_deallocate(mach_task_self(), hostPort);
        if ( result != KERN_SUCCESS )
                throw "host_info() failed";
        
@@ -1083,10 +1146,10 @@ static void getHostInfo()
 
 static void checkSharedRegionDisable()
 {
-       #if __ppc__ || __i386__
+       #if !__LP64__
        // if main executable has segments that overlap the shared region, 
        // then disable using the shared region
-       if ( sMainExecutable->overlapsWithAddressRange((void*)0x90000000, (void*)0xAFFFFFFF) ) {
+       if ( sMainExecutable->overlapsWithAddressRange((void*)(uintptr_t)SHARED_REGION_BASE, (void*)(uintptr_t)(SHARED_REGION_BASE + SHARED_REGION_SIZE)) ) {
                gLinkContext.sharedRegionMode = ImageLoader::kDontUseSharedRegion;
                if ( gLinkContext.verboseMapping )
                        dyld::warn("disabling shared region because main executable overlaps\n");
@@ -1119,66 +1182,28 @@ ImageLoader* getIndexedImage(unsigned int index)
 
 ImageLoader* findImageByMachHeader(const struct mach_header* target)
 {
-       const unsigned int imageCount = sAllImages.size();
-       for(unsigned int i=0; i < imageCount; ++i) {
-               ImageLoader* anImage = sAllImages[i];
-               if ( anImage->machHeader() == target )
-                       return anImage;
-       }
-       return NULL;
+       return findMappedRange((uintptr_t)target);
 }
 
 
 ImageLoader* findImageContainingAddress(const void* addr)
 {
-#if FIND_STATS 
-       static int cacheHit = 0; 
-       static int cacheMiss = 0; 
-       static int cacheNotMacho = 0; 
-       if ( ((cacheHit+cacheMiss+cacheNotMacho) % 100) == 0 )
-               dyld::log("findImageContainingAddress(): cache hit = %d, miss = %d, unknown = %d\n", cacheHit, cacheMiss, cacheNotMacho);
-#endif
-       // first look in image where last address was found rdar://problem/3685517
-       if ( (sLastImageByAddressCache != NULL) && sLastImageByAddressCache->containsAddress(addr) ) {
-#if FIND_STATS 
-               ++cacheHit;
-#endif
-               return sLastImageByAddressCache;
-       }
-       // do exhastive search 
-       // todo: consider maintaining a list sorted by address ranges and do a binary search on that
-       const unsigned int imageCount = sAllImages.size();
-       for(unsigned int i=0; i < imageCount; ++i) {
-               ImageLoader* anImage = sAllImages[i];
-               if ( anImage->containsAddress(addr) ) {
-                       sLastImageByAddressCache = anImage;
-#if FIND_STATS 
-               ++cacheMiss;
-#endif
-                       return anImage;
-               }
-       }
-#if FIND_STATS 
-               ++cacheNotMacho;
-#endif
-       return NULL;
+       return findMappedRange((uintptr_t)addr);
 }
 
-ImageLoader* findImageContainingAddressThreadSafe(const void* addr)
+
+ImageLoader* findImageContainingSymbol(const void* symbol)
 {
-       // do exhastive search 
-       // todo: consider maintaining a list sorted by address ranges and do a binary search on that
-       const unsigned int imageCount = sAllImages.size();
-       for(unsigned int i=0; i < imageCount; ++i) {
-               ImageLoader* anImage = sAllImages[i];
-               if ( anImage->containsAddress(addr) ) {
+       for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
+               ImageLoader* anImage = *it;
+               if ( anImage->containsSymbol(symbol) )
                        return anImage;
-               }
        }
        return NULL;
 }
 
 
+
 void forEachImageDo( void (*callback)(ImageLoader*, void* userData), void* userData)
 {
        const unsigned int imageCount = sAllImages.size();
@@ -1285,6 +1310,7 @@ const cpu_subtype_t CPU_SUBTYPE_END_OF_LIST = -1;
 //
 
 
+#if __ppc__
 //      
 //     32-bit PowerPC sub-type lists
 //
@@ -1300,19 +1326,53 @@ static const cpu_subtype_t kPPC32[kPPC_RowCount][6] = {
        // G3 cannot run G4 or G5 code
        { CPU_SUBTYPE_POWERPC_750,  CPU_SUBTYPE_POWERPC_ALL, CPU_SUBTYPE_END_OF_LIST,  CPU_SUBTYPE_END_OF_LIST, CPU_SUBTYPE_END_OF_LIST, CPU_SUBTYPE_END_OF_LIST }
 };
+#endif
 
 
+#if __arm__
+//      
+//     ARM sub-type lists
+//
+const int kARM_RowCount = 5;
+static const cpu_subtype_t kARM[kARM_RowCount][6] = { 
+       // armv7 can run: v7, v6, v5, and v4
+       {  CPU_SUBTYPE_ARM_V7, CPU_SUBTYPE_ARM_V6, CPU_SUBTYPE_ARM_V5TEJ, CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, CPU_SUBTYPE_END_OF_LIST },
+       
+       // armv6 can run: v6, v5, and v4
+       {  CPU_SUBTYPE_ARM_V6, CPU_SUBTYPE_ARM_V5TEJ, CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, CPU_SUBTYPE_END_OF_LIST, CPU_SUBTYPE_END_OF_LIST },
+       
+       // xscale can run: xscale, v5, and v4
+       {  CPU_SUBTYPE_ARM_XSCALE, CPU_SUBTYPE_ARM_V5TEJ, CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, CPU_SUBTYPE_END_OF_LIST, CPU_SUBTYPE_END_OF_LIST },
+       
+       // armv5 can run: v5 and v4
+       {  CPU_SUBTYPE_ARM_V5TEJ, CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, CPU_SUBTYPE_END_OF_LIST, CPU_SUBTYPE_END_OF_LIST, CPU_SUBTYPE_END_OF_LIST },
+
+       // armv4 can run: v4
+       {  CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, CPU_SUBTYPE_END_OF_LIST, CPU_SUBTYPE_END_OF_LIST, CPU_SUBTYPE_END_OF_LIST, CPU_SUBTYPE_END_OF_LIST },
+};
+#endif
+
 
 // scan the tables above to find the cpu-sub-type-list for this machine
 static const cpu_subtype_t* findCPUSubtypeList(cpu_type_t cpu, cpu_subtype_t subtype)
 {
        switch (cpu) {
+#if __ppc__
                case CPU_TYPE_POWERPC:
                        for (int i=0; i < kPPC_RowCount ; ++i) {
                                if ( kPPC32[i][0] == subtype )
                                        return kPPC32[i];
                        }
                        break;
+#endif
+#if __arm__
+               case CPU_TYPE_ARM:
+                       for (int i=0; i < kARM_RowCount ; ++i) {
+                               if ( kARM[i][0] == subtype )
+                                       return kARM[i];
+                       }
+                       break;
+#endif
        }
        return NULL;
 }
@@ -1359,6 +1419,7 @@ static bool fatFindRunsOnAllCPUs(cpu_type_t cpu, const fat_header* fh, uint64_t*
        for(uint32_t i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
                if ( (cpu_type_t)OSSwapBigToHostInt32(archs[i].cputype) == cpu) {
                        switch (cpu) {
+#if __ppc__
                                case CPU_TYPE_POWERPC:
                                        if ( (cpu_subtype_t)OSSwapBigToHostInt32(archs[i].cpusubtype) == CPU_SUBTYPE_POWERPC_ALL ) {
                                                *offset = OSSwapBigToHostInt32(archs[i].offset);
@@ -1366,6 +1427,16 @@ static bool fatFindRunsOnAllCPUs(cpu_type_t cpu, const fat_header* fh, uint64_t*
                                                return true;
                                        }
                                        break;
+#endif
+#if __arm__
+                               case CPU_TYPE_ARM:
+                                       if ( (cpu_subtype_t)OSSwapBigToHostInt32(archs[i].cpusubtype) == CPU_SUBTYPE_ARM_ALL ) {
+                                               *offset = OSSwapBigToHostInt32(archs[i].offset);
+                                               *len = OSSwapBigToHostInt32(archs[i].size);
+                                               return true;
+                                       }
+                                       break;
+#endif
                        }
                }
        }
@@ -1420,7 +1491,7 @@ static bool fatFindBest(const fat_header* fh, uint64_t* offset, uint64_t* len)
 //
 // This is used to validate if a non-fat (aka thin or raw) mach-o file can be used
 // on the current processor. //
-bool isCompatibleMachO(const uint8_t* firstPage)
+bool isCompatibleMachO(const uint8_t* firstPage, const char* path)
 {
 #if CPU_SUBTYPES_SUPPORTED
        // It is deemed compatible if any of the following are true:
@@ -1440,7 +1511,7 @@ bool isCompatibleMachO(const uint8_t* firstPage)
                                                        return true;
                                        }
                                        // have list and not in list, so not compatible
-                                       throw "incompatible cpu-subtype";
+                                       throwf("incompatible cpu-subtype: 0x%08X in %s", mh->cpusubtype, path);
                                }
                                // unknown cpu sub-type, but if exact match for current subtype then ok to use
                                if ( mh->cpusubtype == sHostCPUsubtype ) 
@@ -1480,11 +1551,11 @@ bool isCompatibleMachO(const uint8_t* firstPage)
 
 // The kernel maps in main executable before dyld gets control.  We need to 
 // make an ImageLoader* for the already mapped in main executable.
-static ImageLoader* instantiateFromLoadedImage(const struct mach_header* mh, uintptr_t slide, const char* path)
+static ImageLoader* instantiateFromLoadedImage(const macho_header* mh, uintptr_t slide, const char* path)
 {
        // try mach-o loader
-       if ( isCompatibleMachO((const uint8_t*)mh) ) {
-               ImageLoader* image = new ImageLoaderMachO(mh, slide, path, gLinkContext);
+       if ( isCompatibleMachO((const uint8_t*)mh, path) ) {
+               ImageLoader* image = ImageLoaderMachO::instantiateMainExecutable(mh, slide, path, gLinkContext);
                addImage(image);
                return image;
        }
@@ -1493,6 +1564,40 @@ static ImageLoader* instantiateFromLoadedImage(const struct mach_header* mh, uin
 }
 
 #if DYLD_SHARED_CACHE_SUPPORT
+bool inSharedCache(const char* path)
+{
+       if ( sSharedCache != NULL ) {
+               struct stat stat_buf;
+               if ( stat(path, &stat_buf) == -1 )
+                       return false;
+               
+               // 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
+                                       return true;
+                               }
+                       }
+               }       
+       }
+       return false;
+}
+
 static ImageLoader* findSharedCacheImage(const struct stat& stat_buf, const char* path)
 {
        if ( sSharedCache != NULL ) {
@@ -1501,7 +1606,8 @@ static ImageLoader* findSharedCacheImage(const struct stat& stat_buf, const char
                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 ( ((time_t)p->modTime == stat_buf.st_mtime) && ((ino_t)p->inode == stat_buf.st_ino) ) {
+                       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);
@@ -1514,7 +1620,7 @@ static ImageLoader* findSharedCacheImage(const struct stat& stat_buf, const char
                                }
                                if ( cacheHit ) {
                                        // found image in cache, instantiate an ImageLoader with it
-                                       return new ImageLoaderMachO((struct mach_header*)(p->address), pathInCache, stat_buf, gLinkContext);
+                                       return ImageLoaderMachO::instantiateFromCache((macho_header*)(p->address), pathInCache, stat_buf, gLinkContext);
                                }
                        }
                }       
@@ -1534,7 +1640,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);
-                                       delete image;
+                                       ImageLoader::deleteImage(image);
                                        return anImage;
                                }
                        }
@@ -1547,6 +1653,12 @@ static ImageLoader* checkandAddImage(ImageLoader* image, const LoadContext& cont
        if ( context.mustBeDylib && !image->isDylib() )
                throw "not a dylib";
 
+       // regular main executables cannot be loaded 
+       if ( image->isExecutable() ) {
+               if ( !context.canBePIE || !image->isPositionIndependentExecutable() )
+                       throw "can't load a main executable";
+       }
+       
        // don't add bundles to global list, they can be loaded but not linked.  When linked it will be added to list
        if ( ! image->isBundle() ) 
                addImage(image);
@@ -1570,18 +1682,23 @@ static ImageLoader* loadPhase6(int fd, struct stat& stat_buf, const char* path,
        
        // min mach-o file is 4K
        if ( fileLength < 4096 ) {
-               pread(fd, firstPage, fileLength, 0);
+               if ( pread(fd, firstPage, fileLength, 0) != (ssize_t)fileLength )
+                       throwf("pread of short file failed: %d", errno);
                shortPage = true;
        } 
        else {
-               pread(fd, firstPage, 4096,0);
+               if ( pread(fd, firstPage, 4096,0) != 4096 )
+                       throwf("pread of first 4K failed: %d", errno);
        }
        
        // if fat wrapper, find usable sub-file
        const fat_header* fileStartAsFat = (fat_header*)firstPage;
        if ( fileStartAsFat->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
                if ( fatFindBest(fileStartAsFat, &fileOffset, &fileLength) ) {
-                       pread(fd, firstPage, 4096, fileOffset);
+                       if ( (fileOffset+fileLength) > (uint64_t)(stat_buf.st_size) )
+                               throwf("truncated fat file.  file length=%llu, but needed slice goes to %llu", stat_buf.st_size, fileOffset+fileLength);
+                       if (pread(fd, firstPage, 4096, fileOffset) != 4096)
+                               throwf("pread of fat file failed: %d", errno);
                }
                else {
                        throw "no matching architecture in universal wrapper";
@@ -1589,12 +1706,12 @@ static ImageLoader* loadPhase6(int fd, struct stat& stat_buf, const char* path,
        }
        
        // try mach-o loader
-       if ( isCompatibleMachO(firstPage) ) {
+       if ( isCompatibleMachO(firstPage, path) ) {
                if ( shortPage ) 
                        throw "file too short";
 
                // instantiate an image
-               ImageLoader* image = new ImageLoaderMachO(path, fd, firstPage, fileOffset, fileLength, stat_buf, gLinkContext);
+               ImageLoader* image = ImageLoaderMachO::instantiateFromFile(path, fd, firstPage, fileOffset, fileLength, stat_buf, gLinkContext);
                
                // validate
                return checkandAddImage(image, context);
@@ -1653,9 +1770,15 @@ static ImageLoader* loadPhase5open(const char* path, const LoadContext& context,
        // open file (automagically closed when this function exits)
        FileOpener file(path);
                
-       // just return NULL if file not found
-       if ( file.getFileDescriptor() == -1 ) 
-               return NULL;    
+       // 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);
@@ -1674,9 +1797,11 @@ static ImageLoader* loadPhase5check(const char* path, const LoadContext& context
        //dyld::log("%s(%s)\n", __func__ , path);
        // search path against load-path and install-path of all already loaded images
        uint32_t hash = ImageLoader::hash(path);
+       //dyld::log("check() hash=%d, path=%s\n", hash, path);
        for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
                ImageLoader* anImage = *it;
-               // check has first to cut down on strcmp calls
+               // 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 ( strcmp(path, anImage->getPath()) == 0 ) {
                                // if we are looking for a dylib don't return something else
@@ -1737,9 +1862,8 @@ static ImageLoader* loadPhase3(const char* path, const LoadContext& context, std
        ImageLoader* image = NULL;
        if ( strncmp(path, "@executable_path/", 17) == 0 ) {
                // executable_path cannot be in used in any binary in a setuid process rdar://problem/4589305
-               if ( sMainExecutableIsSetuid ) {
-                       throwf("unsafe use of @executable_path in %s with setuid binary", context.origin);
-               }
+               if ( sProcessIsRestricted ) 
+                       throwf("unsafe use of @executable_path in %s with restricted binary", context.origin);
                // handle @executable_path path prefix
                const char* executablePath = sExecPath;
                char newPath[strlen(executablePath) + strlen(path)];
@@ -1770,9 +1894,8 @@ static ImageLoader* loadPhase3(const char* path, const LoadContext& context, std
        }
        else if ( (strncmp(path, "@loader_path/", 13) == 0) && (context.origin != NULL) ) {
                // @loader_path cannot be used from the main executable of a setuid process rdar://problem/4589305
-               if ( sMainExecutableIsSetuid && (strcmp(context.origin, sExecPath) == 0) )
-                       throwf("unsafe use of @loader_path in %s with setuid binary", context.origin);
-       
+               if ( sProcessIsRestricted && (strcmp(context.origin, sExecPath) == 0) )
+                       throwf("unsafe use of @loader_path in %s with restricted binary", context.origin);
                // handle @loader_path path prefix
                char newPath[strlen(context.origin) + strlen(path)];
                strcpy(newPath, context.origin);
@@ -1829,8 +1952,8 @@ static ImageLoader* loadPhase3(const char* path, const LoadContext& context, std
                if ( (exceptions != NULL) && (trailingPath != path) )
                        return NULL;
        }
-       else if ( sMainExecutableIsSetuid && (path[0] != '/') ) {
-               throwf("unsafe use of relative rpath %s in %s with setuid binary", path, context.origin);
+       else if (sProcessIsRestricted && (path[0] != '/' )) {
+               throwf("unsafe use of relative rpath %s in %s with restricted binary", path, context.origin);
        }
        
        return loadPhase4(path, context, exceptions);
@@ -1903,8 +2026,11 @@ static ImageLoader* loadPhase1(const char* path, const LoadContext& context, std
                return image;
        
        // try fallback paths during second time (will open file)
-       if ( !context.dontLoad  && (exceptions != NULL) && ((sEnv.DYLD_FALLBACK_FRAMEWORK_PATH != NULL) || (sEnv.DYLD_FALLBACK_LIBRARY_PATH != NULL)) ) {
-               image = loadPhase2(path, context, sEnv.DYLD_FALLBACK_FRAMEWORK_PATH, sEnv.DYLD_FALLBACK_LIBRARY_PATH, exceptions);
+       const char* const* fallbackLibraryPaths = sEnv.DYLD_FALLBACK_LIBRARY_PATH;
+       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);
                if ( image != NULL )
                        return image;
        }
@@ -1918,8 +2044,8 @@ static ImageLoader* loadPhase0(const char* path, const LoadContext& context, std
        //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
 
        // handle DYLD_ROOT_PATH which forces absolute paths to use a new root
-       if ( (sEnv.DYLD_ROOT_PATH != NULL) && (path[0] == '/') ) {
-               for(const char* const* rootPath = sEnv.DYLD_ROOT_PATH ; *rootPath != NULL; ++rootPath) {
+       if ( (gLinkContext.rootPaths != NULL) && (path[0] == '/') ) {
+               for(const char* const* rootPath = gLinkContext.rootPaths ; *rootPath != NULL; ++rootPath) {
                        char newPath[strlen(*rootPath) + strlen(path)+2];
                        strcpy(newPath, *rootPath);
                        strcat(newPath, path);
@@ -1967,8 +2093,12 @@ ImageLoader* load(const char* path, const LoadContext& context)
        image = loadPhase0(path, context, &exceptions);
        if ( image != NULL )
                return image;
-       else if ( exceptions.size() == 0 )
-               throw "image not found";
+       else if ( exceptions.size() == 0 ) {
+               if ( context.dontLoad )
+                       return NULL;
+               else
+                       throw "image not found";
+       }
        else {
                const char* msgStart = "no suitable image found.  Did find:";
                const char* delim = "\n\t";
@@ -2021,13 +2151,7 @@ static int __attribute__((noinline)) _shared_region_map_np(int fd, uint32_t coun
        }
 
        // remove the shared region sub-map
-#if __ppc__ || __i386__
-       vm_address_t addr = (vm_address_t)0x90000000;
-       vm_deallocate(mach_task_self(), addr, 0x20000000);
-#elif __ppc64__ || __x86_64__
-       vm_address_t addr = (vm_address_t)0x7FFF60000000;
-       vm_deallocate(mach_task_self(), addr, 0x80000000);
-#endif
+       vm_deallocate(mach_task_self(), (vm_address_t)SHARED_REGION_BASE, SHARED_REGION_SIZE);
        
        // map cache just for this process with mmap()
        bool failed = false;
@@ -2090,17 +2214,21 @@ const void*     imMemorySharedCacheHeader()
 
 int openSharedCacheFile()
 {
+       char path[1024];
+       strcpy(path, sSharedCacheDir);
+       strcat(path, "/");
 #if __ppc__
-               // rosetta cannot handle optimized _ppc cache, so it use _rosetta cache instead, rdar://problem/5495438
-               if ( isRosetta() )
-                       return ::open(DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME_ROSETTA, O_RDONLY);
-               else
+       // rosetta cannot handle optimized _ppc cache, so it use _rosetta cache instead, rdar://problem/5495438
+    if ( isRosetta() )
+               strcat(path, DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME_ROSETTA);
+    else
 #endif
-               return ::open(DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME, O_RDONLY);
+               strcat(path, DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME);
+       return ::open(path, O_RDONLY);
 }
 
 static void mapSharedCache()
-{      
+{
        uint64_t cacheBaseAddress;
        // quick check if a cache is alreay mapped into shared region
        if ( _shared_region_check_np(&cacheBaseAddress) == 0 ) {
@@ -2113,14 +2241,16 @@ static void mapSharedCache()
                }
        }
        else {
+#if __i386__ || __x86_64__
                // <rdar://problem/5925940> Safe Boot should disable dyld shared cache
                // if we are in safe-boot mode and the cache was not made during this boot cycle,
-               // delete the cache file and let it be regenerated 
+               // delete the cache file
                uint32_t        safeBootValue = 0;
                size_t          safeBootValueSize = sizeof(safeBootValue);
                if ( (sysctlbyname("kern.safeboot", &safeBootValue, &safeBootValueSize, NULL, 0) == 0) && (safeBootValue != 0) ) {
                        // 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 ) {
                                struct timeval bootTimeValue;
                                size_t bootTimeValueSize = sizeof(bootTimeValue);
@@ -2129,20 +2259,20 @@ static void mapSharedCache()
                                        if ( dyldCacheStatInfo.st_mtime < bootTimeValue.tv_sec ) {
                                                ::unlink(DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME);
                                                gLinkContext.sharedRegionMode = ImageLoader::kDontUseSharedRegion;
-                                               gSharedCacheNotFound = true;
                                                return;
                                        }
                                }
                        }
                }
+#endif
                // map in shared cache to shared region
                int fd = openSharedCacheFile();
                if ( fd != -1 ) {
-                       uint8_t firstPage[4096];
-                       if ( ::read(fd, firstPage, 4096) == 4096 ) {
-                               dyld_cache_header* header = (dyld_cache_header*)firstPage;
+                       uint8_t firstPages[8192];
+                       if ( ::read(fd, firstPages, 8192) == 8192 ) {
+                               dyld_cache_header* header = (dyld_cache_header*)firstPages;
                                if ( strcmp(header->magic, ARCH_CACHE_MAGIC) == 0 ) {
-                                       const shared_file_mapping_np* mappings = (shared_file_mapping_np*)&firstPage[header->mappingOffset];
+                                       const shared_file_mapping_np* mappings = (shared_file_mapping_np*)&firstPages[header->mappingOffset];
                                        const shared_file_mapping_np* const end = &mappings[header->mappingCount];
                                        // validate that the cache file has not been truncated
                                        bool goodCache = false;
@@ -2152,37 +2282,51 @@ static void mapSharedCache()
                                                for (const shared_file_mapping_np* p = mappings; p < end; ++p) {
                                                        // 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->sfm_file_offset+p->sfm_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;
+                                                       }
+                                               }
+                                       }
+                                       // sanity check that /usr/lib/libSystem.B.dylib stat() info matches cache
+                                       if ( header->imagesCount * sizeof(dyld_cache_image_info) + header->imagesOffset < 8192 ) {
+                                               bool foundLibSystem = false;
+                                               if ( stat("/usr/lib/libSystem.B.dylib", &stat_buf) == 0 ) {
+                                                       const dyld_cache_image_info* images = (dyld_cache_image_info*)&firstPages[header->imagesOffset];
+                                                       const dyld_cache_image_info* const imagesEnd = &images[header->imagesCount];
+                                                       for (const dyld_cache_image_info* p = images; p < imagesEnd; ++p) {
+                                                               if ( ((time_t)p->modTime == stat_buf.st_mtime) && ((ino_t)p->inode == stat_buf.st_ino) ) {
+                                                                       foundLibSystem = true;
+                                                                       break;
+                                                               }
+                                                       }                                       
+                                               }
+                                               if ( !sSharedCacheIgnoreInodeAndTimeStamp && !foundLibSystem ) {
+                                                       dyld::log("dyld: shared cached file was build against a different libSystem.dylib, ignoring cache\n");
+                                                       goodCache = false;
                                                }
                                        }
+                                                                               
                                        if ( goodCache ) {
-                                               const shared_file_mapping_np* mappings = (shared_file_mapping_np*)&firstPage[header->mappingOffset];
+                                               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
                                                        sSharedCache = (dyld_cache_header*)mappings[0].sfm_address;
                                                }
                                        }
-                                       else {
-                                               gSharedCacheNeedsUpdating = true;
-                                               dyld::log("dyld: shared cached file is corrupt: " DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME "\n");
-                                       }
                                }
                                else {
-                                       gSharedCacheNeedsUpdating = true;
                                        if ( gLinkContext.verboseMapping ) 
                                                dyld::log("dyld: shared cached file is invalid\n");
                                }
                        }
                        else {
-                               gSharedCacheNeedsUpdating = true;
                                if ( gLinkContext.verboseMapping ) 
                                        dyld::log("dyld: shared cached file cannot be read\n");
                        }
                        close(fd);
                }
                else {
-                       gSharedCacheNotFound = true;
                        if ( gLinkContext.verboseMapping ) 
                                dyld::log("dyld: shared cached file cannot be opened\n");
                }
@@ -2202,9 +2346,9 @@ static void mapSharedCache()
                        dyld_shared_cache_ranges.sharedRegionsCount = 4;
                if ( gLinkContext.verboseMapping ) {
                        if ( gLinkContext.sharedRegionMode == ImageLoader::kUseSharedRegion )
-                               dyld::log("dyld: Mapping shared cache\n");
+                               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\n");
+                               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];
                int index = 0;
@@ -2218,12 +2362,18 @@ static void mapSharedCache()
                                        ((p->sfm_init_prot & VM_PROT_EXECUTE) ? "execute " : ""),  p->sfm_init_prot, p->sfm_max_prot);
                        }
                #if __i386__
-                       // record if a non-writable and executable region is found in the R/W shared region
-                       // this is the __IMPORT segments.  dyld will turn write protection on and off as needed
+                       // 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) ) {
-                               sImportSegmentsStart = p->sfm_address;
-                               sImportSegmentsSize = p->sfm_size;
-                               makeSharedCacheImportSegmentsWritable(true);
+                               if ( p->sfm_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);
+                                       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,
+                                                       (prot & PROT_READ) ? 'r' : '.',  (prot & PROT_WRITE) ? 'w' : '.',  (prot & PROT_EXEC) ? 'x' : '.' );
+                                       }
+                               }
                        }
                #endif
                }
@@ -2237,8 +2387,6 @@ static void mapSharedCache()
 // create when NSLinkModule is called for a second time on a bundle
 ImageLoader* cloneImage(ImageLoader* image)
 {
-       const uint64_t offsetInFat = image->getOffsetInFatFile();
-
        // open file (automagically closed when this function exits)
        FileOpener file(image->getPath());
        
@@ -2246,24 +2394,19 @@ ImageLoader* cloneImage(ImageLoader* image)
        if ( fstat(file.getFileDescriptor(), &stat_buf) == -1)
                throw "stat error";
        
-       // read first page of file
-       uint8_t firstPage[4096];
-       pread(file.getFileDescriptor(), firstPage, 4096, offsetInFat);
-       
-       // fat length is only used for sanity checking, since this image was already loaded once, just use upper bound
-       uint64_t lenInFat = stat_buf.st_size - offsetInFat;
-       
-       // try mach-o loader
-       if ( isCompatibleMachO(firstPage) ) {
-               ImageLoader* clone = new ImageLoaderMachO(image->getPath(), file.getFileDescriptor(), firstPage, offsetInFat, lenInFat, stat_buf, gLinkContext);
-               // don't add bundles to global list, they can be loaded but not linked.  When linked it will be added to list
-               if ( ! image->isBundle() ) 
-                       addImage(clone);
-               return clone;
-       }
-       
-       // try other file formats...
-       throw "can't clone image";
+       dyld::LoadContext context;
+       context.useSearchPaths          = false;
+       context.useFallbackPaths        = false;
+       context.useLdLibraryPath        = false;
+       context.implicitRPath           = false;
+       context.matchByInstallName      = false;
+       context.dontLoad                        = false;
+       context.mustBeBundle            = true;
+       context.mustBeDylib                     = false;
+       context.canBePIE                        = false;
+       context.origin                          = false;
+       context.rpath                           = false;
+       return loadPhase6(file.getFileDescriptor(), stat_buf, image->getPath(), context);
 }
 
 
@@ -2284,8 +2427,8 @@ ImageLoader* loadFromMemory(const uint8_t* mem, uint64_t len, const char* module
        }
 
        // try each loader
-       if ( isCompatibleMachO(mem) ) {
-               ImageLoader* image = new ImageLoaderMachO(moduleName, (mach_header*)mem, len, gLinkContext);
+       if ( isCompatibleMachO(mem, moduleName) ) {
+               ImageLoader* image = ImageLoaderMachO::instantiateFromMemory(moduleName, (macho_header*)mem, len, gLinkContext);
                // don't add bundles to global list, they can be loaded but not linked.  When linked it will be added to list
                if ( ! image->isBundle() ) 
                        addImage(image);
@@ -2334,8 +2477,7 @@ void clearErrorMessage()
 void setErrorMessage(const char* message)
 {
        // save off error message in global buffer for CrashReporter to find
-       strncpy(error_string, message, sizeof(error_string)-1);
-       error_string[sizeof(error_string)-1] = '\0';
+       strlcpy(error_string, message, sizeof(error_string));
 }
 
 const char* getErrorMessage()
@@ -2344,12 +2486,14 @@ const char* getErrorMessage()
 }
 
 
-void  halt(const char* message)
+void halt(const char* message)
 {
        dyld::log("dyld: %s\n", message);
        setErrorMessage(message);
-       strncpy(error_string, message, sizeof(error_string)-1);
-       error_string[sizeof(error_string)-1] = '\0';
+       uintptr_t terminationFlags = 0;
+       if ( !gLinkContext.startedInitializingMainExecutable )
+               terminationFlags = 1;
+       setAlImageInfosHalt(error_string, terminationFlags);
        dyld_fatal_error(error_string);
 }
 
@@ -2368,7 +2512,7 @@ uintptr_t bindLazySymbol(const mach_header* mh, uintptr_t* lazyPointer)
        #if __i386__
                // fast stubs pass NULL for mh and image is instead found via the location of stub (aka lazyPointer)
                if ( mh == NULL )
-                       target = dyld::findImageContainingAddressThreadSafe(lazyPointer);
+                       target = dyld::findImageContainingAddress(lazyPointer);
                else
                        target = dyld::findImageByMachHeader(mh);
        #else
@@ -2393,12 +2537,36 @@ uintptr_t bindLazySymbol(const mach_header* mh, uintptr_t* lazyPointer)
 }
 
 
-// SPI used by ZeroLink to lazy load bundles
-void registerZeroLinkHandlers(BundleNotificationCallBack notify, BundleLocatorCallBack locate)
+#if COMPRESSED_DYLD_INFO_SUPPORT
+uintptr_t fastBindLazySymbol(ImageLoader** imageLoaderCache, uintptr_t lazyBindingInfoOffset)
 {
-       sBundleNotifier = notify;
-       sBundleLocation = locate;
+       uintptr_t result = 0;
+       // get image 
+       if ( *imageLoaderCache == NULL ) {
+               // save in cache
+               *imageLoaderCache = dyld::findMappedRange((uintptr_t)imageLoaderCache);
+               if ( *imageLoaderCache == NULL ) {
+                       const char* message = "fast lazy binding from unknown image";
+                       dyld::log("dyld: %s\n", message);
+                       halt(message);
+               }
+       }
+       
+       // bind lazy pointer and return it
+       try {
+               result = (*imageLoaderCache)->doBindFastLazySymbol(lazyBindingInfoOffset, gLinkContext);
+       }
+       catch (const char* message) {
+               dyld::log("dyld: lazy symbol binding failed: %s\n", message);
+               halt(message);
+       }
+
+       // return target address to glue which jumps to it with real parameters restored
+       return result;
 }
+#endif // COMPRESSED_DYLD_INFO_SUPPORT
+
+
 
 void registerUndefinedHandler(UndefinedHandler handler)
 {
@@ -2414,48 +2582,6 @@ static void undefinedHandler(const char* symboName)
 
 static bool findExportedSymbol(const char* name, bool onlyInCoalesced, const ImageLoader::Symbol** sym, const ImageLoader** image)
 {
-       // try ZeroLink short cut to finding bundle which exports this symbol
-       if ( sBundleLocation != NULL ) {
-               ImageLoader* zlImage = (*sBundleLocation)(name);
-               if ( zlImage == ((ImageLoader*)(-1)) ) {
-                       // -1 is magic value that request symbol is in a bundle not yet linked into process
-                       // try calling handler to link in that symbol
-                       undefinedHandler(name);
-                       // call locator again
-                       zlImage = (*sBundleLocation)(name);
-               }
-               // if still not found, then ZeroLink has no idea where to find it
-               if ( zlImage == ((ImageLoader*)(-1)) ) 
-                       return false;
-               if ( zlImage != NULL ) {
-                       // ZeroLink cache knows where the symbol is
-                       if ( onlyInCoalesced ) {
-                               // but ZeroLink does not know about coalescing weak symbols, so ignore ZeroLink's hint when onlyInCoalesced==true
-                       }
-                       else {
-                               *sym = zlImage->findExportedSymbol(name, NULL, false, image);
-                               if ( *sym != NULL ) {
-                                       *image = zlImage;
-                                       return true;
-                               }
-                       }
-               }
-               else {
-                       // ZeroLink says it is in some bundle already loaded, but not linked, walk them all
-                       const unsigned int imageCount = sAllImages.size();
-                       for(unsigned int i=0; i < imageCount; ++i){
-                               ImageLoader* anImage = sAllImages[i];
-                               if ( anImage->isBundle() && !anImage->hasHiddenExports() ) {
-                                       //dyld::log("dyld: search for %s in %s\n", name, anImage->getPath());
-                                       *sym = anImage->findExportedSymbol(name, NULL, false, image);
-                                       if ( *sym != NULL ) {
-                                               return true;
-                                       }
-                               }
-                       }
-               }
-       }
-
        // search all images in order
        const ImageLoader* firstWeakImage = NULL;
        const ImageLoader::Symbol* firstWeakSym = NULL;
@@ -2471,7 +2597,7 @@ static bool findExportedSymbol(const char* name, bool onlyInCoalesced, const Ima
                                anImage = sAllImages[0];
                }
                if ( ! anImage->hasHiddenExports() && (!onlyInCoalesced || anImage->hasCoalescedExports()) ) {
-                       *sym = anImage->findExportedSymbol(name, NULL, false, image);
+                       *sym = anImage->findExportedSymbol(name, false, image);
                        if ( *sym != NULL ) {
                                // if weak definition found, record first one found
                                if ( ((*image)->getExportedSymbolInfo(*sym) & ImageLoader::kWeakDefinition) != 0 ) {
@@ -2516,7 +2642,7 @@ bool flatFindExportedSymbolWithHint(const char* name, const char* librarySubstri
                ImageLoader* anImage = sAllImages[i];
                // only look at images whose paths contain the hint string (NULL hint string is wildcard)
                if ( ! anImage->isBundle() && ((librarySubstring==NULL) || (strstr(anImage->getPath(), librarySubstring) != NULL)) ) {
-                       *sym = anImage->findExportedSymbol(name, NULL, false, image);
+                       *sym = anImage->findExportedSymbol(name, false, image);
                        if ( *sym != NULL ) {
                                return true;
                        }
@@ -2525,6 +2651,20 @@ bool flatFindExportedSymbolWithHint(const char* name, const char* librarySubstri
        return false;
 }
 
+unsigned int getCoalescedImages(ImageLoader* images[])
+{
+       unsigned int count = 0;
+       for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
+               ImageLoader* image = *it;
+               if ( image->participatesInCoalescing() ) {
+                       *images++ = *it;
+                       ++count;
+               }
+       }
+       return count;
+}
+
+
 static ImageLoader::MappedRegion* getMappedRegions(ImageLoader::MappedRegion* regions)
 {
        ImageLoader::MappedRegion* end = regions;
@@ -2584,17 +2724,18 @@ void registerImageStateBatchChangeHandler(dyld_image_states state, dyld_image_st
        }
 }
 
-static ImageLoader* libraryLocator(const char* libraryName, bool search, bool findDLL, const char* origin, const ImageLoader::RPathChain* rpaths)
+static ImageLoader* libraryLocator(const char* libraryName, bool search, const char* origin, const ImageLoader::RPathChain* rpaths)
 {
        dyld::LoadContext context;
        context.useSearchPaths          = search;
+       context.useFallbackPaths        = search;
        context.useLdLibraryPath        = false;
        context.implicitRPath           = false;
        context.matchByInstallName      = false;
        context.dontLoad                        = false;
        context.mustBeBundle            = false;
        context.mustBeDylib                     = true;
-       context.findDLL                         = findDLL;
+       context.canBePIE                        = false;
        context.origin                          = origin;
        context.rpath                           = rpaths;
        return load(libraryName, context);
@@ -2610,17 +2751,14 @@ static const char* basename(const char* path)
     return last;
 }
 
-static void setContext(const struct mach_header* mainExecutableMH, int argc, const char* argv[], const char* envp[], const char* apple[])
+static void setContext(const macho_header* mainExecutableMH, int argc, const char* argv[], const char* envp[], const char* apple[])
 {
        gLinkContext.loadLibrary                        = &libraryLocator;
        gLinkContext.terminationRecorder        = &terminationRecorder;
        gLinkContext.flatExportFinder           = &flatFindExportedSymbol;
        gLinkContext.coalescedExportFinder      = &findCoalescedExportedSymbol;
+       gLinkContext.getCoalescedImages         = &getCoalescedImages;
        gLinkContext.undefinedHandler           = &undefinedHandler;
-#if IMAGE_NOTIFY_SUPPORT
-       gLinkContext.addImageNeedingNotification = &addImageNeedingNotification;
-       gLinkContext.notifyAdding                       = &notifyAdding;
-#endif
        gLinkContext.getAllMappedRegions        = &getMappedRegions;
        gLinkContext.bindingHandler                     = NULL;
        gLinkContext.notifySingle                       = &notifySingle;
@@ -2629,11 +2767,10 @@ static void setContext(const struct mach_header* mainExecutableMH, int argc, con
        gLinkContext.registerDOFs                       = &registerDOFs;
        gLinkContext.clearAllDepths                     = &clearAllDepths;
        gLinkContext.imageCount                         = &imageCount;
-       gLinkContext.notifySharedCacheInvalid= &notifySharedCacheInvalid;
-#if __i386__
-       gLinkContext.makeSharedCacheImportSegmentsWritable = &makeSharedCacheImportSegmentsWritable;
-#endif
        gLinkContext.setNewProgramVars          = &setNewProgramVars;
+#if DYLD_SHARED_CACHE_SUPPORT
+       gLinkContext.inSharedCache                      = &inSharedCache;
+#endif
 #if SUPPORT_OLD_CRT_INITIALIZATION
        gLinkContext.setRunInitialzersOldWay= &setRunInitialzersOldWay;
 #endif
@@ -2669,6 +2806,53 @@ bool isRosetta()
 }
 #endif
 
+
+#if __LP64__
+       #define LC_SEGMENT_COMMAND              LC_SEGMENT_64
+       #define macho_segment_command   segment_command_64
+       #define macho_section                   section_64
+#else
+       #define LC_SEGMENT_COMMAND              LC_SEGMENT
+       #define macho_segment_command   segment_command
+       #define macho_section                   section
+#endif
+
+
+//
+// Look for a special segment in the mach header. 
+// Its presences means that the binary wants to have DYLD ignore
+// DYLD_ environment variables.
+//
+static bool hasRestrictedSegment(const macho_header* mh)
+{
+       const uint32_t cmd_count = mh->ncmds;
+       const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header));
+       const struct load_command* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               switch (cmd->cmd) {
+                       case LC_SEGMENT_COMMAND:
+                       {
+                               const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
+                               
+                               //dyld::log("seg name: %s\n", seg->segname);
+                               if (strcmp(seg->segname, "__RESTRICT") == 0) {
+                                       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 (strcmp(sect->sectname, "__restrict") == 0) 
+                                                       return true;
+                                       }
+                               }
+                       }
+                       break;
+               }
+               cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
+       }
+               
+       return false;
+}
+       
+                                                                                       
 #if 0
 static void printAllImages()
 {
@@ -2693,15 +2877,6 @@ void link(ImageLoader* image, bool forceLazysBound, const ImageLoader::RPathChai
        if ( !image->isLinked() )
                addRootImage(image);
        
-       // notify ZeroLink of new image with concat of logical and physical name
-       if ( sBundleNotifier != NULL && image->isBundle() ) {
-               const int logicalLen = strlen(image->getLogicalPath());
-               char logAndPhys[strlen(image->getPath())+logicalLen+2];
-               strcpy(logAndPhys, image->getLogicalPath());
-               strcpy(&logAndPhys[logicalLen+1], image->getPath());
-               (*sBundleNotifier)(logAndPhys, image);
-       }
-
        // process images
        try {
                image->link(gLinkContext, forceLazysBound, false, loaderRPaths);
@@ -2710,11 +2885,6 @@ void link(ImageLoader* image, bool forceLazysBound, const ImageLoader::RPathChai
                garbageCollectImages();
                throw;
        }
-       
-#if OLD_GDB_DYLD_INTERFACE
-       // notify gdb that loaded libraries have changed
-       gdb_dyld_state_changed();
-#endif
 }
 
 
@@ -2737,7 +2907,7 @@ void garbageCollectImages()
                                        //dyld::log("garbageCollectImages: deleting %s\n", image->getPath());
                                        image->setBeingRemoved();
                                        removeImage(image);
-                                       delete image;
+                                       ImageLoader::deleteImage(image);
                                }
                                catch (const char* msg) {
                                        dyld::warn("problem deleting image: %s\n", msg);
@@ -2755,7 +2925,7 @@ static void preflight_finally(ImageLoader* image)
 {
        if ( image->isBundle() ) {
                removeImageFromAllImages(image->machHeader());
-               delete image;
+               ImageLoader::deleteImage(image);
        }
        sBundleBeingLoaded = NULL;
        dyld::garbageCollectImages();
@@ -2782,13 +2952,14 @@ static void loadInsertedDylib(const char* path)
        try {
                LoadContext context;
                context.useSearchPaths          = false;
+               context.useFallbackPaths        = false;
                context.useLdLibraryPath        = false;
                context.implicitRPath           = false;
                context.matchByInstallName      = false;
                context.dontLoad                        = false;
                context.mustBeBundle            = false;
                context.mustBeDylib                     = true;
-               context.findDLL                         = false;
+               context.canBePIE                        = false;
                context.origin                          = NULL; // can't use @loader_path with DYLD_INSERT_LIBRARIES
                context.rpath                           = NULL;
                image = load(path, context);
@@ -2806,10 +2977,18 @@ static void loadInsertedDylib(const char* path)
 // Returns address of main() in target program which __dyld_start jumps to
 //
 uintptr_t
-_main(const struct mach_header* mainExecutableMH, uintptr_t mainExecutableSlide, int argc, const char* argv[], const char* envp[], const char* apple[])
+_main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int argc, const char* argv[], const char* envp[], const char* apple[])
 {      
-       setContext(mainExecutableMH, argc, argv, envp, apple);
+#ifdef ALTERNATIVE_LOGFILE
+       sLogfile = open(ALTERNATIVE_LOGFILE, O_WRONLY | O_CREAT | O_APPEND);
+       if ( sLogfile == -1 ) {
+               sLogfile = STDERR_FILENO;
+               dyld::log("error opening alternate log file %s, errno = %d\n", ALTERNATIVE_LOGFILE, errno);
+       }
+#endif
        
+       setContext(mainExecutableMH, argc, argv, envp, apple);
+
        // Pickup the pointer to the exec path.
        sExecPath = apple[0];
        bool ignoreEnvironmentVariables = false;
@@ -2837,8 +3016,12 @@ _main(const struct mach_header* mainExecutableMH, uintptr_t mainExecutableSlide,
        }
        uintptr_t result = 0;
        sMainExecutableMachHeader = mainExecutableMH;
-       sMainExecutableIsSetuid = issetugid();
-       if ( sMainExecutableIsSetuid )
+       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 )
                pruneEnvironmentVariables(envp, &apple);
        else
                checkEnvironmentVariables(envp, ignoreEnvironmentVariables);
@@ -2850,18 +3033,24 @@ _main(const struct mach_header* mainExecutableMH, uintptr_t mainExecutableSlide,
        // install gdb notifier
        stateToHandlers(dyld_image_state_dependents_mapped, sBatchHandlers)->push_back(notifyGDB);
        // make initial allocations large enough that it is unlikely to need to be re-alloced
-       sAllImages.reserve(200);
+       sAllImages.reserve(INITIAL_IMAGE_COUNT);
        sImageRoots.reserve(16);
        sAddImageCallbacks.reserve(4);
        sRemoveImageCallbacks.reserve(4);
        sImageFilesNeedingTermination.reserve(16);
        sImageFilesNeedingDOFUnregistration.reserve(8);
        
+#ifdef WAIT_FOR_SYSTEM_ORDER_HANDSHAKE
+       // <rdar://problem/6849505> Add gating mechanism to dyld support system order file generation process
+       WAIT_FOR_SYSTEM_ORDER_HANDSHAKE(dyld_all_image_infos.systemOrderFlag);
+#endif
+       
        try {
                // instantiate ImageLoader for main executable
                sMainExecutable = instantiateFromLoadedImage(mainExecutableMH, mainExecutableSlide, sExecPath);
                sMainExecutable->setNeverUnload();
                gLinkContext.mainExecutable = sMainExecutable;
+               gLinkContext.processIsRestricted = sProcessIsRestricted;
                // load shared cache
                checkSharedRegionDisable();
        #if DYLD_SHARED_CACHE_SUPPORT
@@ -2910,6 +3099,14 @@ _main(const struct mach_header* mainExecutableMH, uintptr_t mainExecutableSlide,
                dyld::log("dyld: launch failed\n");
        }
 
+#ifdef ALTERNATIVE_LOGFILE
+       // only use alternate log during launch, otherwise file is open forever
+       if ( sLogfile != STDERR_FILENO ) {
+               close(sLogfile);
+               sLogfile = STDERR_FILENO;
+       }
+#endif
+       
        return result;
 }
 
index 44127472fbd1049e71baa541e03f353b39c53b64..22a1f6c7c46d2660ee352fb6dc6447b7703ed208 100644 (file)
@@ -1,5 +1,5 @@
 #
-#  Copyright (c) 2004-2006 Apple Computer, Inc. All rights reserved.
+#  Copyright (c) 2004-2008 Apple Computer, Inc. All rights reserved.
 # 
 #  @APPLE_LICENSE_HEADER_START@
 #  
 
 #
 #  Only the following symbols should be "global". 
-#  gdb and vmutils lookup these symbols in dyld in order to determine what images the process is using 
+#  gdb and Symbolication lookup these symbols in dyld in order to determine what images the process is using 
 #
 
-# Mac OS X 10.4 way to discover a process's images
+# gdb and Symbolication look at these to discover a process's loaded images
 _dyld_all_image_infos
 _dyld_shared_cache_ranges
 
@@ -38,17 +38,3 @@ _dyld_fatal_error
 _dyldVersionString
 _dyldVersionNumber
 
-# Entry points into dyld needed by loaded every image
-_stub_binding_helper
-_dyld_func_lookup
-
-# Old symbols left for compatibility
-_gdb_dyld_version
-_gdb_dyld_state_changed
-_gdb_nobject_images
-_gdb_object_image_size
-_gdb_nlibrary_images
-_gdb_library_image_size
-_object_images
-_library_images
-_send_event
index 1c030c38024dd851b66589b6e636a6ccdcf52dc9..2deab7dbaf58df8faa474fce90f278ea22841264 100644 (file)
@@ -38,13 +38,14 @@ namespace dyld {
        struct LoadContext
        {
                bool                    useSearchPaths;
+               bool                    useFallbackPaths;
                bool                    useLdLibraryPath;
                bool                    implicitRPath;
                bool                    matchByInstallName;
                bool                    dontLoad;
                bool                    mustBeBundle;
                bool                    mustBeDylib;
-               bool                    findDLL;
+               bool                    canBePIE;
                const char*                                             origin;                 // path for expanding @loader_path
                const ImageLoader::RPathChain*  rpath;                  // paths for expanding @rpath
        };
@@ -52,24 +53,18 @@ namespace dyld {
 
 
        typedef void             (*ImageCallback)(const struct mach_header* mh, intptr_t slide);
-       typedef void             (*BundleNotificationCallBack)(const char* imageName, ImageLoader* image);
-       typedef ImageLoader* (*BundleLocatorCallBack)(const char* symbolName);
        typedef void             (*UndefinedHandler)(const char* symbolName);
        typedef const char*      (*ImageLocator)(const char* dllName);
 
 
        extern ImageLoader::LinkContext                 gLinkContext;
        extern bool                                                             gLogAPIs;
-       extern bool                                                             gSharedCacheNotFound;
-       extern bool                                                             gSharedCacheNeedsUpdating;
-       extern bool                                                             gSharedCacheDontNotify;
        extern const struct LibSystemHelpers*   gLibSystemHelpers;
 #if SUPPORT_OLD_CRT_INITIALIZATION
        extern bool                                                             gRunInitializersOldWay;
 #endif
        extern void                                     registerAddCallback(ImageCallback func);
        extern void                                     registerRemoveCallback(ImageCallback func);
-       extern void                                     registerZeroLinkHandlers(BundleNotificationCallBack, BundleLocatorCallBack);
        extern void                                     registerUndefinedHandler(UndefinedHandler);
        extern void                                     initializeMainExecutable();
        extern void                                     preflight(ImageLoader* image, const ImageLoader::RPathChain& loaderRPaths);
@@ -82,6 +77,7 @@ namespace dyld {
        extern uint32_t                         getImageCount();
        extern ImageLoader*                     findImageByMachHeader(const struct mach_header* target);
        extern ImageLoader*                     findImageContainingAddress(const void* addr);
+       extern ImageLoader*                     findImageContainingSymbol(const void* symbol);
        extern ImageLoader*                     findImageByName(const char* path);
        extern ImageLoader*                     findLoadedImageByInstallPath(const char* path);
        extern bool                                     flatFindExportedSymbol(const char* name, const ImageLoader::Symbol** sym, const ImageLoader** image);
@@ -91,7 +87,7 @@ namespace dyld {
        extern void                                     removeImage(ImageLoader* image);
        extern ImageLoader*                     cloneImage(ImageLoader* image);
        extern void                                     forEachImageDo( void (*)(ImageLoader*, void*), void*);
-       extern uintptr_t                        _main(const struct mach_header* mainExecutableMH, uintptr_t mainExecutableSlide, int argc, const char* argv[], const char* envp[], const char* apple[]);
+       extern uintptr_t                        _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, int argc, const char* argv[], const char* envp[], const char* apple[]);
        extern void                                     halt(const char* message)  __attribute__((noreturn));
        extern void                                     setErrorMessage(const char* msg);
        extern const char*                      getErrorMessage();
@@ -102,9 +98,10 @@ namespace dyld {
        extern void                                     registerImageStateSingleChangeHandler(dyld_image_states state, dyld_image_state_change_handler handler);
        extern void                                     registerImageStateBatchChangeHandler(dyld_image_states state, dyld_image_state_change_handler handler);
        extern void                                     garbageCollectImages();
-       extern void                                     registerWinImageLocator(ImageLocator);
        extern int                                      openSharedCacheFile();
        extern const void*                      imMemorySharedCacheHeader();
+       extern uintptr_t                        fastBindLazySymbol(ImageLoader** imageLoaderCache, uintptr_t lazyBindingInfoOffset);
+       extern bool                                     inSharedCache(const char* path);
 
 };
 
diff --git a/src/dyld64.exp b/src/dyld64.exp
deleted file mode 100644 (file)
index 1c2a031..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#
-#  Copyright (c) 2005-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@
-#
-
-#
-#  Only the following symbols should be "global". 
-#  gdb and vmutils lookup these symbols in dyld in order to determine what images the process is using 
-#
-
-# Mac OS X 10.4 way to discover a process's images
-_dyld_all_image_infos
-_dyld_shared_cache_ranges
-
-# CrashReporter uses this to get message as to why dyld terminated the process
-_error_string
-_dyld_fatal_error
-
-# Used by various tools to see build number of dyld
-_dyldVersionString
-_dyldVersionNumber
index c9f0e978c32c6f5f9396e70c66ee8c86b66da185..609f0b32b0b53636ed9285d1414440f8c1c12f0b 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@
  * 
@@ -33,6 +33,7 @@
 #include <string.h>
 #include <sys/param.h>
 #include <sys/mount.h>
+#include <Availability.h>
 
 
 #include <vector>
 #include <mach/mach.h>
 #include <sys/time.h>
 #include <sys/sysctl.h>
+#include <mach/mach_traps.h> // for task_self_trap()
 
-extern "C" mach_port_name_t    task_self_trap(void);  // can't include <System/mach/mach_traps.h> because it is missing extern C
 
 #include "mach-o/dyld_images.h"
 #include "mach-o/dyld.h"
 #include "mach-o/dyld_priv.h"
-#include "mach-o/dyld-update-prebinding.h"
 
 #include "ImageLoader.h"
 #include "dyld.h"
@@ -58,14 +58,19 @@ extern "C" mach_port_name_t task_self_trap(void);  // can't include <System/mach
 #include "dlfcn.h"
 
 
-#ifndef RTLD_DLL
-       #define RTLD_DLL        0x200   /* Mac OS X 10.5 and later */
+// deprecated APIs are still availble on Mac OS X, but not on iPhone OS
+#if __IPHONE_OS_VERSION_MIN_REQUIRED   
+       #define DEPRECATED_APIS_SUPPORTED 0
+#else
+       #define DEPRECATED_APIS_SUPPORTED 1
 #endif
 
+
+#if DEPRECATED_APIS_SUPPORTED
 static char sLastErrorFilePath[1024];
 static NSLinkEditErrors sLastErrorFileCode;
 static int sLastErrorNo;
-
+#endif
 
 // In 10.3.x and earlier all the NSObjectFileImage API's were implemeneted in libSystem.dylib
 // Beginning in 10.4 the NSObjectFileImage API's are implemented in dyld and libSystem just forwards
@@ -75,23 +80,24 @@ 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
 static void _dyld_install_handlers(void* undefined, void* multiple, void* linkEdit);
 #if OLD_LIBSYSTEM_SUPPORT
 static NSModule _dyld_link_module(NSObjectFileImage object_addr, size_t object_size, const char* moduleName, uint32_t options);
 #endif
 static void _dyld_register_binding_handler(void * (*)(const char *, const char *, void *), ImageLoader::BindingOptions);
-static void _dyld_fork_child();
-static void _dyld_make_delayed_module_initializer_calls();
 static bool NSMakePrivateModulePublic(NSModule module);
 static void _dyld_call_module_initializers_for_dylib(const struct mach_header* mh_dylib_header);
-static void registerThreadHelpers(const dyld::LibSystemHelpers*);
-static const struct dyld_all_image_infos* _dyld_get_all_image_infos();
 
 // The following functions are dyld API's, but since dyld links with a static copy of libc.a
 // the public name cannot be used.
 static void            client_dyld_lookup_and_bind(const char* symbolName, void** address, NSModule* module);
 static bool            client_NSIsSymbolNameDefined(const char* symbolName);
-
+#endif // DEPRECATED_APIS_SUPPORTED
+static bool client_dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info);
 
 static void unimplemented()
 {
@@ -104,12 +110,8 @@ struct dyld_func {
 };
 
 static struct dyld_func dyld_funcs[] = {
-       {"__dyld_register_thread_helpers",                                      (void*)registerThreadHelpers },
     {"__dyld_register_func_for_add_image",                             (void*)_dyld_register_func_for_add_image },
     {"__dyld_register_func_for_remove_image",                  (void*)_dyld_register_func_for_remove_image },
-    {"__dyld_make_delayed_module_initializer_calls",   (void*)_dyld_make_delayed_module_initializer_calls },
-    {"__dyld_fork_child",                                                              (void*)_dyld_fork_child },
-       {"__dyld_dyld_register_image_state_change_handler",     (void*)dyld_register_image_state_change_handler },
     {"__dyld_dladdr",                                                                  (void*)dladdr },
     {"__dyld_dlclose",                                                                 (void*)dlclose },
     {"__dyld_dlerror",                                                                 (void*)dlerror },
@@ -121,9 +123,26 @@ static struct dyld_func dyld_funcs[] = {
     {"__dyld_get_image_header",                                                        (void*)_dyld_get_image_header },
     {"__dyld_get_image_vmaddr_slide",                                  (void*)_dyld_get_image_vmaddr_slide },
     {"__dyld_get_image_name",                                                  (void*)_dyld_get_image_name },
+    {"__dyld_get_image_slide",                                                 (void*)_dyld_get_image_slide },
     {"__dyld__NSGetExecutablePath",                                            (void*)_NSGetExecutablePath },
-       
-       // the rest of these are either deprecated or SPIs
+
+       // SPIs
+       {"__dyld_dyld_register_image_state_change_handler",     (void*)dyld_register_image_state_change_handler },
+       {"__dyld_register_thread_helpers",                                      (void*)registerThreadHelpers },
+       {"__dyld_fork_child",                                                           (void*)_dyld_fork_child },
+    {"__dyld_moninit",                                                                 (void*)_dyld_moninit },
+    {"__dyld_make_delayed_module_initializer_calls",   (void*)_dyld_make_delayed_module_initializer_calls },
+       {"__dyld_get_all_image_infos",                                          (void*)_dyld_get_all_image_infos },
+#if !__arm__
+       {"__dyld_find_unwind_sections",                                         (void*)client_dyld_find_unwind_sections },
+#endif
+#if __i386__ || __x86_64__
+       {"__dyld_fast_stub_entry",                                                      (void*)dyld::fastBindLazySymbol },
+#endif
+       {"__dyld_image_path_containing_address",                        (void*)dyld_image_path_containing_address },
+
+       // deprecated
+#if DEPRECATED_APIS_SUPPORTED
     {"__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 },
@@ -133,7 +152,6 @@ static struct dyld_func dyld_funcs[] = {
     {"__dyld_bind_objc_module",                                                (void*)_dyld_bind_objc_module },
     {"__dyld_bind_fully_image_containing_address",  (void*)_dyld_bind_fully_image_containing_address },
     {"__dyld_image_containing_address",                                (void*)_dyld_image_containing_address },
-    {"__dyld_moninit",                                                         (void*)_dyld_moninit },
     {"__dyld_register_binding_handler",                                (void*)_dyld_register_binding_handler },
     {"__dyld_NSNameOfSymbol",                                          (void*)NSNameOfSymbol },
     {"__dyld_NSAddressOfSymbol",                                       (void*)NSAddressOfSymbol },
@@ -154,7 +172,6 @@ static struct dyld_func dyld_funcs[] = {
     {"__dyld_launched_prebound",                                       (void*)_dyld_launched_prebound },
     {"__dyld_all_twolevel_modules_prebound",           (void*)_dyld_all_twolevel_modules_prebound },
     {"__dyld_call_module_initializers_for_dylib",   (void*)_dyld_call_module_initializers_for_dylib },
-    {"__dyld_install_link_edit_symbol_handlers",       (void*)dyld::registerZeroLinkHandlers },
     {"__dyld_NSCreateObjectFileImageFromFile",                 (void*)NSCreateObjectFileImageFromFile },
     {"__dyld_NSCreateObjectFileImageFromMemory",               (void*)NSCreateObjectFileImageFromMemory },
     {"__dyld_NSDestroyObjectFileImage",                                        (void*)NSDestroyObjectFileImage },
@@ -166,17 +183,24 @@ static struct dyld_func dyld_funcs[] = {
     {"__dyld_NSSymbolReferenceNameInObjectFileImage",  (void*)NSSymbolReferenceNameInObjectFileImage },
     {"__dyld_NSSymbolReferenceCountInObjectFileImage", (void*)NSSymbolReferenceCountInObjectFileImage },
     {"__dyld_NSGetSectionDataInObjectFileImage",               (void*)NSGetSectionDataInObjectFileImage },
-    {"__dyld_NSFindSectionAndOffsetInObjectFileImage",  (void*)NSFindSectionAndOffsetInObjectFileImage },
 #if OLD_LIBSYSTEM_SUPPORT
     {"__dyld_link_module",                                                     (void*)_dyld_link_module },
 #endif
-       {"__dyld_dlord",                                                                        (void*)dlord },
-       {"__dyld_get_all_image_infos",                                          (void*)_dyld_get_all_image_infos },
+#endif //DEPRECATED_APIS_SUPPORTED
+
     {NULL, 0}
 };
 
 
 
+#if DEPRECATED_APIS_SUPPORTED
+
+static void dyldAPIhalt(const char* apiName, const char* errorMsg)
+{
+       dyld::log("dyld: %s() error\n", apiName);
+       dyld::halt(errorMsg);
+}
+
 // dyld's abstract type NSSymbol is implemented as const ImageLoader::Symbol*
 inline NSSymbol SymbolToNSSymbol(const ImageLoader::Symbol* sym)
 {
@@ -219,13 +243,6 @@ static std::vector<NSObjectFileImage> sObjectFileImages;
 //
 
 
-static void dyldAPIhalt(const char* apiName, const char* errorMsg)
-{
-       dyld::log("dyld: %s() error\n", apiName);
-       dyld::halt(errorMsg);
-}
-
-
 
 static void setLastError(NSLinkEditErrors code, int errnum, const char* file, const char* message)
 {
@@ -236,6 +253,7 @@ static void setLastError(NSLinkEditErrors code, int errnum, const char* file, co
        sLastErrorNo = errnum;
 }
 
+#endif // DEPRECATED_APIS_SUPPORTED
 
 /*
  *_dyld_NSGetExecutablePath is the dyld side of _NSGetExecutablePath which
@@ -260,6 +278,100 @@ int _NSGetExecutablePath(char* buf, uint32_t *bufsize)
        return 0;
 }
 
+uint32_t _dyld_image_count(void)
+{
+       if ( dyld::gLogAPIs )
+               dyld::log("%s()\n", __func__);
+       return dyld::getImageCount();
+}
+
+const struct mach_header* _dyld_get_image_header(uint32_t image_index)
+{
+       if ( dyld::gLogAPIs )
+               dyld::log("%s(%u)\n", __func__, image_index);
+       ImageLoader* image = dyld::getIndexedImage(image_index);
+       if ( image != NULL )
+               return (struct mach_header*)image->machHeader();
+       else
+               return NULL;
+}
+
+intptr_t _dyld_get_image_vmaddr_slide(uint32_t image_index)
+{
+       if ( dyld::gLogAPIs )
+               dyld::log("%s(%u)\n", __func__, image_index);
+       ImageLoader* image = dyld::getIndexedImage(image_index);
+       if ( image != NULL )
+               return image->getSlide();
+       else
+               return 0;
+}
+
+intptr_t _dyld_get_image_slide(const struct mach_header* mh)
+{
+       if ( dyld::gLogAPIs )
+               dyld::log("%s(%p)\n", __func__, mh);
+       ImageLoader* image = dyld::findImageByMachHeader(mh);
+       if ( image != NULL )
+               return image->getSlide();
+       else
+               return 0;
+}
+
+
+const char* _dyld_get_image_name(uint32_t image_index)
+{
+       if ( dyld::gLogAPIs )
+               dyld::log("%s(%u)\n", __func__, image_index);
+       ImageLoader* image = dyld::getIndexedImage(image_index);
+       if ( image != NULL )
+               return image->getPath();
+       else
+               return NULL;
+}
+
+const struct mach_header * _dyld_get_image_header_containing_address(const void* address)
+{
+       if ( dyld::gLogAPIs )
+               dyld::log("%s(%p)\n", __func__, address);
+       ImageLoader* image = dyld::findImageContainingAddress(address);
+       if ( image != NULL ) 
+               return image->machHeader();
+       return NULL;
+}
+
+
+void _dyld_register_func_for_add_image(void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide))
+{
+       if ( dyld::gLogAPIs )
+               dyld::log("%s(%p)\n", __func__, (void *)func);
+       dyld::registerAddCallback(func);
+}
+
+void _dyld_register_func_for_remove_image(void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide))
+{
+       if ( dyld::gLogAPIs )
+               dyld::log("%s(%p)\n", __func__, (void *)func);
+       dyld::registerRemoveCallback(func);
+}
+
+
+
+// called by crt before main() by programs linked with 10.4 or earlier crt1.o
+static void _dyld_make_delayed_module_initializer_calls()
+{
+       if ( dyld::gLogAPIs )
+               dyld::log("%s()\n", __func__);
+               
+#if SUPPORT_OLD_CRT_INITIALIZATION
+       if ( dyld::gRunInitializersOldWay )
+               dyld::initializeMainExecutable();
+#endif
+}
+
+
+
+#if DEPRECATED_APIS_SUPPORTED
 
 //
 // _dyld_call_module_initializers_for_dylib() is the dyld side of
@@ -387,23 +499,7 @@ NSSymbol NSLookupAndBindSymbolWithHint(const char* symbolName, const char* libra
        return NULL;
 }
 
-uint32_t _dyld_image_count(void)
-{
-       if ( dyld::gLogAPIs )
-               dyld::log("%s()\n", __func__);
-       return dyld::getImageCount();
-}
 
-const struct mach_header* _dyld_get_image_header(uint32_t image_index)
-{
-       if ( dyld::gLogAPIs )
-               dyld::log("%s(%u)\n", __func__, image_index);
-       ImageLoader* image = dyld::getIndexedImage(image_index);
-       if ( image != NULL )
-               return (struct mach_header*)image->machHeader();
-       else
-               return NULL;
-}
 
 
 static __attribute__((noinline)) 
@@ -423,13 +519,14 @@ const struct mach_header* addImage(void* callerAddress, const char* path, bool s
                }
                dyld::LoadContext context;
                context.useSearchPaths          = search;
+               context.useFallbackPaths        = search;
                context.useLdLibraryPath        = false;
                context.implicitRPath           = false;
                context.matchByInstallName      = matchInstallName;
                context.dontLoad                        = dontLoad;
                context.mustBeBundle            = false;
                context.mustBeDylib                     = true;
-               context.findDLL                         = false;
+               context.canBePIE                        = false;
                context.origin                          = callerImage != NULL ? callerImage->getPath() : NULL; // caller's image's path
                context.rpath                           = &callersRPaths;       // rpaths from caller and main executable
                                
@@ -509,12 +606,13 @@ bool NSIsSymbolNameDefinedInImage(const struct mach_header* mh, const char* symb
                dyld::log("%s(%p, \"%s\")\n", __func__, (void *)mh, symbolName);
        ImageLoader* image = dyld::findImageByMachHeader(mh);
        if ( image != NULL ) {
-               if ( image->findExportedSymbol(symbolName, NULL, true, NULL) != NULL)
+               if ( image->findExportedSymbol(symbolName, true, NULL) != NULL)
                        return true;
        }
        return false;
 }
 
+
 NSSymbol NSLookupSymbolInImage(const struct mach_header* mh, const char* symbolName, uint32_t options)
 {
        if ( dyld::gLogAPIs )
@@ -536,7 +634,7 @@ NSSymbol NSLookupSymbolInImage(const struct mach_header* mh, const char* symbolN
                                dyldAPIhalt(__func__, msg);
                        }
                }
-               symbol = image->findExportedSymbol(symbolName, NULL, true, NULL);
+               symbol = image->findExportedSymbol(symbolName, true, NULL);
        }
        if ( dyld::gLogAPIs && (symbol == NULL) )
                dyld::log("%s(%p, \"%s\", 0x%08X) ==> NULL\n", __func__, mh, symbolName, options);
@@ -576,7 +674,7 @@ const char* NSNameOfSymbol(NSSymbol symbol)
        if ( dyld::gLogAPIs )
                dyld::log("%s(%p)\n", __func__, (void *)symbol);
        const char* result = NULL;
-       ImageLoader* image = dyld::findImageContainingAddress(symbol);
+       ImageLoader* image = dyld::findImageContainingSymbol(symbol);
        if ( image != NULL ) 
                result = image->getExportedSymbolName(NSSymbolToSymbol(symbol));
        return result;
@@ -586,8 +684,10 @@ void* NSAddressOfSymbol(NSSymbol symbol)
 {
        if ( dyld::gLogAPIs )
                dyld::log("%s(%p)\n", __func__, (void *)symbol);
+       if ( symbol == NULL )
+               return NULL;
        void* result = NULL;
-       ImageLoader* image = dyld::findImageContainingAddress(symbol);
+       ImageLoader* image = dyld::findImageContainingSymbol(symbol);
        if ( image != NULL ) 
                result = (void*)image->getExportedSymbolAddress(NSSymbolToSymbol(symbol), dyld::gLinkContext);
        return result;
@@ -598,42 +698,20 @@ NSModule NSModuleForSymbol(NSSymbol symbol)
        if ( dyld::gLogAPIs )
                dyld::log("%s(%p)\n", __func__, (void *)symbol);
        NSModule result = NULL;
-       ImageLoader* image = dyld::findImageContainingAddress(symbol);
+       ImageLoader* image = dyld::findImageContainingSymbol(symbol);
        if ( image != NULL ) 
                result = ImageLoaderToNSModule(image);
        return result;
 }
 
 
-intptr_t _dyld_get_image_vmaddr_slide(uint32_t image_index)
-{
-       if ( dyld::gLogAPIs )
-               dyld::log("%s(%u)\n", __func__, image_index);
-       ImageLoader* image = dyld::getIndexedImage(image_index);
-       if ( image != NULL )
-               return image->getSlide();
-       else
-               return 0;
-}
-
-const char* _dyld_get_image_name(uint32_t image_index)
-{
-       if ( dyld::gLogAPIs )
-               dyld::log("%s(%u)\n", __func__, image_index);
-       ImageLoader* image = dyld::getIndexedImage(image_index);
-       if ( image != NULL )
-               return image->getLogicalPath();
-       else
-               return NULL;
-}
-
 
 
 bool _dyld_all_twolevel_modules_prebound(void)
 {
        if ( dyld::gLogAPIs )
                dyld::log("%s()\n", __func__);
-       return FALSE; // fixme
+       return FALSE; 
 }
 
 void _dyld_bind_objc_module(const void *objc_module)
@@ -690,13 +768,14 @@ NSObjectFileImageReturnCode NSCreateObjectFileImageFromFile(const char* pathName
 
                dyld::LoadContext context;
                context.useSearchPaths          = false;
+               context.useFallbackPaths        = false;
                context.useLdLibraryPath        = false;
                context.implicitRPath           = false;
                context.matchByInstallName      = false;
                context.dontLoad                        = false;
                context.mustBeBundle            = true;
                context.mustBeDylib                     = false;
-               context.findDLL                         = false;
+               context.canBePIE                        = false;
                context.origin                          = callerImage != NULL ? callerImage->getPath() : NULL; // caller's image's path
                context.rpath                           = NULL; // support not yet implemented
 
@@ -769,7 +848,7 @@ bool NSDestroyObjectFileImage(NSObjectFileImage objectFileImage)
                        // and we should delete it
                        bool linkedImage = dyld::validImage(objectFileImage->image);
                        if ( ! linkedImage )  {
-                               delete objectFileImage->image;
+                               ImageLoader::deleteImage(objectFileImage->image);
                                objectFileImage->image = NULL;
                        }
                }
@@ -785,7 +864,16 @@ bool NSDestroyObjectFileImage(NSObjectFileImage objectFileImage)
                // if object was created from a memory, release that memory
                // NOTE: this is the way dyld has always done this. NSCreateObjectFileImageFromMemory() hands over ownership of the memory to dyld
                if ( objectFileImage->imageBaseAddress != NULL ) {
-                       vm_deallocate(mach_task_self(), (vm_address_t)objectFileImage->imageBaseAddress, objectFileImage->imageLength);
+                       bool freed = false;
+                       if ( (dyld::gLibSystemHelpers != NULL) && (dyld::gLibSystemHelpers->version >= 6) ) {
+                               size_t sz = (*dyld::gLibSystemHelpers->malloc_size)(objectFileImage->imageBaseAddress);
+                               if ( sz != 0 ) {
+                                       (*dyld::gLibSystemHelpers->free)((void*)(objectFileImage->imageBaseAddress));
+                                       freed = true;
+                               }
+                       }
+                       if ( ! freed )
+                               vm_deallocate(mach_task_self(), (vm_address_t)objectFileImage->imageBaseAddress, objectFileImage->imageLength);
                }
                
                // free ofi object
@@ -832,7 +920,7 @@ const char * NSSymbolReferenceNameInObjectFileImage(NSObjectFileImage objectFile
                dyld::log("%s(%p,%d)\n", __func__, objectFileImage, ordinal);
        const ImageLoader::Symbol* sym = objectFileImage->image->getIndexedImportedSymbol(ordinal);
        if ( tentative_definition != NULL ) {
-               ImageLoader::ReferenceFlags flags = objectFileImage->image->geImportedSymbolInfo(sym);
+               ImageLoader::ReferenceFlags flags = objectFileImage->image->getImportedSymbolInfo(sym);
                if ( (flags & ImageLoader::kTentativeDefinition) != 0 )
                        *tentative_definition = true;
                else
@@ -863,34 +951,10 @@ bool NSIsSymbolDefinedInObjectFileImage(NSObjectFileImage objectFileImage, const
 {
        if ( dyld::gLogAPIs )
                dyld::log("%s(%p,%s)\n", __func__, objectFileImage, symbolName);
-       const ImageLoader::Symbol* sym = objectFileImage->image->findExportedSymbol(symbolName, NULL, true, NULL);
+       const ImageLoader::Symbol* sym = objectFileImage->image->findExportedSymbol(symbolName, true, NULL);
        return ( sym != NULL );
 }
 
-/*
- * Given an imageOffset into an ObjectFileImage, returns 
- * the segment/section name and offset into that section of
- * that imageOffset.  Returns FALSE if the imageOffset is not 
- * in any section.  You can used the resulting sectionOffset to
- * index into the data returned by NSGetSectionDataInObjectFileImage.
- * 
- * First appeared in Mac OS X 10.3 
- *
- * SPI: currently only used by ZeroLink to detect +load methods
- */
-bool 
-NSFindSectionAndOffsetInObjectFileImage(NSObjectFileImage objectFileImage, 
-                                                                               unsigned long imageOffset,
-                                                                               const char** segmentName,       /* can be NULL */
-                                                                               const char** sectionName,       /* can be NULL */
-                                                                               unsigned long* sectionOffset)   /* can be NULL */
-{
-       if ( dyld::gLogAPIs )
-               dyld::log("%s(%p)\n", __func__, objectFileImage);
-       
-       return objectFileImage->image->findSection(((char*)(objectFileImage->image->machHeader()))+imageOffset, segmentName, sectionName, sectionOffset);
-}
-
 
 
 NSModule NSLinkModule(NSObjectFileImage objectFileImage, const char* moduleName, uint32_t options)
@@ -904,24 +968,12 @@ NSModule NSLinkModule(NSObjectFileImage objectFileImage, const char* moduleName,
                // each link causes the bundle to be copied to a new address
                if ( objectFileImage->image->isLinked() ) {
                        // already linked, so clone a new one and link it
-#if 0
-                       dyld::warn("%s(0x%08X, \"%s\", 0x%08X) called more than once for 0x%08X\n",
-                                       __func__, objectFileImage, moduleName, options, objectFileImage); 
-#endif
                        objectFileImage->image = dyld::cloneImage(objectFileImage->image);
                }
-               
-               // if this ofi was made with NSCreateObjectFileImageFromFile() then physical path is already set
-               // if this ofi was create with NSCreateObjectFileImageFromMemory() then the phyiscal path should be set if supplied 
-               if ( (options & NSLINKMODULE_OPTION_TRAILING_PHYS_NAME) != 0 ) {
-                       if ( objectFileImage->imageBaseAddress != NULL ) {
-                               const char* physEnd = &moduleName[strlen(moduleName)+1];
-                               objectFileImage->image->setPath(physEnd);
-                       }
-               }
-       
-               // set moduleName as the name anyone calling _dyld_get_image_name() will see
-               objectFileImage->image->setLogicalPath(moduleName);
+                       
+               // for memory based images, set moduleName as the name anyone calling _dyld_get_image_name() will see
+               if ( objectFileImage->image->getPath() == NULL )
+                       objectFileImage->image->setPath(moduleName);
 
                // support private bundles
                if ( (options & NSLINKMODULE_OPTION_PRIVATE) != 0 )
@@ -933,13 +985,13 @@ NSModule NSLinkModule(NSObjectFileImage objectFileImage, const char* moduleName,
                // load libraries, rebase, bind, to make this image usable
                dyld::link(objectFileImage->image, forceLazysBound, ImageLoader::RPathChain(NULL,NULL));
                
+               // bump reference count to keep this bundle from being garbage collected
+               objectFileImage->image->incrementDlopenReferenceCount();
+
                // run initializers unless magic flag says not to
                if ( (options & NSLINKMODULE_OPTION_DONT_CALL_MOD_INIT_ROUTINES) == 0 )
                        dyld::runInitializers(objectFileImage->image);
 
-               // bump reference count to keep this bundle from being garbage collected
-               objectFileImage->image->incrementDlopenReferenceCount();
-
                return ImageLoaderToNSModule(objectFileImage->image);
        }
        catch (const char* msg) {
@@ -965,15 +1017,9 @@ static NSModule _dyld_link_module(NSObjectFileImage object_addr, size_t object_s
        ImageLoader* image = NULL;
        dyld::clearErrorMessage();
        try {
-               const char* imageName = moduleName;
-               if ( (options & NSLINKMODULE_OPTION_TRAILING_PHYS_NAME) != 0 )
-                       imageName = &moduleName[strlen(moduleName)+1];
-                       
+               const char* imageName = moduleName;                     
                image = dyld::loadFromMemory((const uint8_t*)object_addr, object_size, imageName); 
                
-               if ( (options & NSLINKMODULE_OPTION_TRAILING_PHYS_NAME) != 0 )
-                       image->setLogicalPath(moduleName);
-                       
                if ( image != NULL ) {          
                        // support private bundles
                        if ( (options & NSLINKMODULE_OPTION_PRIVATE) != 0 )
@@ -998,7 +1044,7 @@ static NSModule _dyld_link_module(NSObjectFileImage object_addr, size_t object_s
                // if image was created for this bundle, destroy it
                if ( image != NULL ) {
                        dyld::removeImage(image);
-                       delete image;
+                       ImageLoader::deleteImage(image);
                }
                image = NULL;
                free((void*)msg);
@@ -1014,7 +1060,7 @@ NSSymbol NSLookupSymbolInModule(NSModule module, const char* symbolName)
        ImageLoader* image = NSModuleToImageLoader(module);
        if ( image == NULL ) 
                return NULL;
-       return SymbolToNSSymbol(image->findExportedSymbol(symbolName, NULL, false, NULL));
+       return SymbolToNSSymbol(image->findExportedSymbol(symbolName, false, NULL));
 }
 
 const char* NSNameOfModule(NSModule module)
@@ -1063,7 +1109,7 @@ bool NSUnLinkModule(NSModule module, uint32_t options)
                        found = true;
        }
        if ( !found )
-               delete image;
+               ImageLoader::deleteImage(image);
        
        return true;
 }
@@ -1078,43 +1124,7 @@ static void _dyld_install_handlers(void* undefined, void* multiple, void* linkEd
        // no support for multiple or linkedit handlers
 }
 
-const struct mach_header * _dyld_get_image_header_containing_address(const void* address)
-{
-       if ( dyld::gLogAPIs )
-               dyld::log("%s(%p)\n", __func__, address);
-       ImageLoader* image = dyld::findImageContainingAddress(address);
-       if ( image != NULL ) 
-               return image->machHeader();
-       return NULL;
-}
-
-
-void _dyld_register_func_for_add_image(void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide))
-{
-       if ( dyld::gLogAPIs )
-               dyld::log("%s(%p)\n", __func__, (void *)func);
-       dyld::registerAddCallback(func);
-}
 
-void _dyld_register_func_for_remove_image(void (*func)(const struct mach_header *mh, intptr_t vmaddr_slide))
-{
-       if ( dyld::gLogAPIs )
-               dyld::log("%s(%p)\n", __func__, (void *)func);
-       dyld::registerRemoveCallback(func);
-}
-
-
-// called by crt before main
-static void _dyld_make_delayed_module_initializer_calls()
-{
-       if ( dyld::gLogAPIs )
-               dyld::log("%s()\n", __func__);
-               
-#if SUPPORT_OLD_CRT_INITIALIZATION
-       if ( dyld::gRunInitializersOldWay )
-               dyld::initializeMainExecutable();
-#endif
-}
 
 
 void NSLinkEditError(NSLinkEditErrors* c, int* errorNumber, const char** fileName, const char** errorString)
@@ -1126,6 +1136,8 @@ void NSLinkEditError(NSLinkEditErrors* c, int* errorNumber, const char** fileNam
        *errorString = dyld::getErrorMessage();
 }
 
+
+
 static void _dyld_register_binding_handler(void * (*bindingHandler)(const char *, const char *, void *), ImageLoader::BindingOptions bindingOptions)
 {
        if ( dyld::gLogAPIs )
@@ -1134,6 +1146,8 @@ static void _dyld_register_binding_handler(void * (*bindingHandler)(const char *
        dyld::gLinkContext.bindingOptions = bindingOptions;
 }
 
+#endif //DEPRECATED_APIS_SUPPORTED
+
 
 // Call by fork() in libSystem after the kernel trap is done on the child side
 static void _dyld_fork_child()
@@ -1149,6 +1163,13 @@ static void _dyld_fork_child()
        //
        extern mach_port_t      mach_task_self_;
        mach_task_self_ = task_self_trap();
+       
+       // If dyld is sending load/unload notices to CoreSymbolication, the shared memory
+       // page is not copied on fork. <rdar://problem/6797342>
+       // NULL the CoreSymbolication shared memory pointer to prevent a crash.
+       dyld_all_image_infos.coreSymbolicationShmPage = NULL;
+       // for safety, make sure child starts with clean systemOrderFlag
+       dyld_all_image_infos.systemOrderFlag = 0;
 }
 
 
@@ -1175,6 +1196,7 @@ void _dyld_moninit(MonitorProc proc)
        dyld::forEachImageDo(&monInitCallback, (void*)proc);
 }
 
+#if DEPRECATED_APIS_SUPPORTED
 // returns true if prebinding was used in main executable
 bool _dyld_launched_prebound()
 {
@@ -1205,7 +1227,7 @@ static bool NSMakePrivateModulePublic(NSModule module)
        return false;
 }
 
-
+#endif // DEPRECATED_APIS_SUPPORTED
 
 bool lookupDyldFunction(const char* name, uintptr_t* address)
 {
@@ -1221,59 +1243,12 @@ bool lookupDyldFunction(const char* name, uintptr_t* address)
        return false;
 }
 
-static bool readOnlyBootVolume()
-{
-       struct statfs sfs;
-       if ( statfs("/", &sfs) == 0 ) {
-               return ( sfs.f_flags & MNT_RDONLY );
-       }
-       // if statfs() fails, something is wrong, so don't rebuild dyld cache
-       return true;
-}
-
-
 static void registerThreadHelpers(const dyld::LibSystemHelpers* helpers)
 {
        dyld::gLibSystemHelpers = helpers;
        
-#if DYLD_SHARED_CACHE_SUPPORT
-       // notify dyld server if something is wrong with the shared cache
-       //dyld::log("helpers->version=%lu, gSharedCacheDontNotify=%d, gSharedCacheNotFound=%d, gSharedCacheNeedsUpdating=%d, readOnlyBootVolume()=%d\n",
-       //      helpers->version, dyld::gSharedCacheDontNotify, dyld::gSharedCacheNotFound, dyld::gSharedCacheNeedsUpdating, readOnlyBootVolume());
-       if ( (helpers != NULL) && (helpers->version >= 3) && !dyld::gSharedCacheDontNotify ) {
-               if ( dyld::gSharedCacheNotFound || dyld::gSharedCacheNeedsUpdating ) {
-                       if ( ! readOnlyBootVolume() ) {
-                               if ( dyld::gSharedCacheNotFound )
-                                       (*helpers->dyld_shared_cache_missing)();
-                               else if ( dyld::imMemorySharedCacheHeader() == NULL ) {
-                                       // since shared cache is not mapped and not missing, it must be 
-                                       // corrupt.  Don't need to test contents, just
-                                       // ping launchd to start update_dyld_shared_cache
-                                       // rdar://problem/5694507 
-                                       (*helpers->dyld_shared_cache_out_of_date)();
-                               }
-                               else if ( dyld::gSharedCacheNeedsUpdating ) {
-                                       // To reduce the storm of messages to update_dyld_shared_cache
-                                       // don't message if the cache file is missing (which means the cache is in
-                                       // the process of being regenerated) or if the contents of the cache file
-                                       // don't match what is already in memory (which means the cache has
-                                       // already be regenerated).
-                                       int fd = dyld::openSharedCacheFile();
-                                       if ( fd != -1 ) {
-                                               uint8_t onDiskCache[4096];
-                                               if ( ::read(fd, onDiskCache, 4096) == 4096 ) {
-                                                       if ( ::memcmp(onDiskCache, dyld::imMemorySharedCacheHeader(), 4096) == 0 ) {
-                                                               // ping launchd to start update_dyld_shared_cache
-                                                               (*helpers->dyld_shared_cache_out_of_date)();
-                                                       }
-                                               }
-                                               ::close(fd);
-                                       }
-                               }
-                       }
-               }
-       }
-#endif
+       // let gdb know it is safe to run code in inferior that might call malloc()
+       dyld_all_image_infos.libSystemInitialized = true;       
 }
 
 
@@ -1305,6 +1280,13 @@ bool dlopen_preflight(const char* path)
 
        dlerrorClear();
        
+#if DYLD_SHARED_CACHE_SUPPORT
+       // <rdar://problem/5910137> dlopen_preflight() on image in shared cache leaves it loaded but not objc initialized
+       // if requested path is to something in the dyld shared cache, always succeed
+       if ( dyld::inSharedCache(path) )
+               return true;
+#endif
+       
        bool result = false;
        std::vector<const char*> rpathsFromCallerImage;
        try {
@@ -1319,15 +1301,18 @@ bool dlopen_preflight(const char* path)
                }
 
                ImageLoader*    image = NULL;
+               const bool leafName = (strchr(path, '/') == NULL);
+               const bool absolutePath = (path[0] == '/');
                dyld::LoadContext context;
                context.useSearchPaths  = true;
-               context.useLdLibraryPath= (strchr(path, '/') == NULL);  // a leafname implies should search 
-               context.implicitRPath = (path[0] != '/');                               // a non-absolute path implies try rpath searching 
+               context.useFallbackPaths= leafName;                                     // a partial path implies don't use fallback paths
+               context.useLdLibraryPath= leafName;                                     // a leafname implies should search 
+               context.implicitRPath   = !absolutePath;                        // a non-absolute path implies try rpath searching 
                context.matchByInstallName = true;
                context.dontLoad                = false;
                context.mustBeBundle    = false;
                context.mustBeDylib             = false;
-               context.findDLL                 = false;
+               context.canBePIE                = true;
                context.origin                  = callerImage != NULL ? callerImage->getPath() : NULL; // caller's image's path
                context.rpath                   = &callersRPaths;       // rpaths from caller and main executable
                
@@ -1389,15 +1374,18 @@ void* dlopen(const char* path, int mode)
                        dyld::mainExecutable()->getRPaths(dyld::gLinkContext, rpathsFromCallerImage);
                }
  
+               const bool leafName = (strchr(path, '/') == NULL);
+               const bool absolutePath = (path[0] == '/');
                dyld::LoadContext context;
                context.useSearchPaths  = true;
-               context.useLdLibraryPath= (strchr(path, '/') == NULL);  // a leafname implies should search 
-               context.implicitRPath = (path[0] != '/');                               // a non-absolute path implies try rpath searching 
+               context.useFallbackPaths= leafName;                             // a partial path means no fallback paths
+               context.useLdLibraryPath= leafName;                             // a leafname implies should search 
+               context.implicitRPath   = !absolutePath;                // a non-absolute path implies try rpath searching 
                context.matchByInstallName = true;
                context.dontLoad                = ( (mode & RTLD_NOLOAD) != 0 );
                context.mustBeBundle    = false;
                context.mustBeDylib             = false;
-               context.findDLL                 = ( (mode & RTLD_DLL) != 0 );
+               context.canBePIE                = true;
                context.origin                  = callerImage != NULL ? callerImage->getPath() : NULL; // caller's image's path
                context.rpath                   = &callersRPaths;                               // rpaths from caller and main executable
                
@@ -1469,6 +1457,11 @@ void* dlopen(const char* path, int mode)
                free((void*)str);
        }
        
+       // when context.dontLoad is set, load() returns NULL instead of throwing an exception 
+       if ( (mode & RTLD_NOLOAD) && (result == NULL) ) {
+               dlerrorSet("image not already loaded");
+       }
+       
        if ( lockHeld ) 
                dyld::gLibSystemHelpers->releaseGlobalDyldLock();
        return result;
@@ -1514,30 +1507,24 @@ int dladdr(const void* address, Dl_info* info)
 
        ImageLoader* image = dyld::findImageContainingAddress(address);
        if ( image != NULL ) {
-               info->dli_fname = image->getLogicalPath();
-               info->dli_fbase = (void*)image->machHeader();   
-               // find closest exported symbol in the image
-               const uint32_t exportCount = image->getExportedSymbolCount();
-               const ImageLoader::Symbol* bestSym = NULL;
-               const void* bestAddr = 0;
-               for(uint32_t i=0; i < exportCount; ++i) {
-                       const ImageLoader::Symbol* sym = image->getIndexedExportedSymbol(i);
-                       const void* symAddr = (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
-                       if ( (symAddr <= address) && (bestAddr < symAddr) ) {
-                               bestSym = sym;
-                               bestAddr = symAddr;
-                       }
+               info->dli_fname = image->getPath();
+               info->dli_fbase = (void*)image->machHeader();
+               if ( address == info->dli_fbase ) {
+                       // special case lookup of header
+                       info->dli_sname = "__dso_handle";
+                       info->dli_saddr = info->dli_fbase;
+                       return 1; // success
                }
-               if ( bestSym != NULL ) {
-                       info->dli_sname = image->getExportedSymbolName(bestSym);
+               // find closest symbol in the image
+               info->dli_sname = image->findClosestSymbol(address, (const void**)&info->dli_saddr);
+               if ( info->dli_sname != NULL ) {
                        if ( info->dli_sname[0] == '_' )
                                info->dli_sname = info->dli_sname +1; // strip off leading underscore
-                       info->dli_saddr = (void*)bestAddr;
-               }
-               else {
-                       info->dli_sname = NULL;
-                       info->dli_saddr = NULL;
+                       //dyld::log("dladdr(%p) => %p %s\n", address, info->dli_saddr, info->dli_sname);
+                       return 1; // success
                }
+               info->dli_sname = NULL;
+               info->dli_saddr = NULL;
                return 1; // success
        }
        return 0;  // failure
@@ -1590,7 +1577,7 @@ void* dlsym(void* handle, const char* symbolName)
        // magic "search only main executable" handle
        if ( handle == RTLD_MAIN_ONLY ) {
                image = dyld::mainExecutable();
-               sym = image->findExportedSymbol(underscoredName, NULL, true, &image); // search RTLD_FIRST way
+               sym = image->findExportedSymbol(underscoredName, true, &image); // search RTLD_FIRST way
                if ( sym != NULL ) {
                        return (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
                }
@@ -1630,7 +1617,7 @@ void* dlsym(void* handle, const char* symbolName)
        image = (ImageLoader*)(((uintptr_t)handle) & (-4));     // clear mode bits
        if ( dyld::validImage(image) ) {
                if ( (((uintptr_t)handle) & 1) != 0 )
-                       sym = image->findExportedSymbol(underscoredName, NULL, true, &image); // search RTLD_FIRST way
+                       sym = image->findExportedSymbol(underscoredName, true, &image); // search RTLD_FIRST way
                else
                        sym = image->findExportedSymbolInImageOrDependentImages(underscoredName, dyld::gLinkContext, &image); // search image and what it links against
                
@@ -1649,64 +1636,6 @@ void* dlsym(void* handle, const char* symbolName)
 
 
 
-void* dlord(void* handle, uint32_t ordinal)
-{
-       if ( dyld::gLogAPIs )
-               dyld::log("%s(%p, %u)\n", __func__, handle, ordinal);
-
-       dlerrorClear();
-
-       
-       // magic "search all" handle
-       if ( handle == RTLD_DEFAULT ) {
-               const char* str = dyld::mkstringf("dlord(RTLD_DEFAULT, %u): not supported", ordinal);
-               dlerrorSet(str);
-               free((void*)str);
-               return NULL;
-       }
-       // magic "search only main executable" handle
-       if ( handle == RTLD_MAIN_ONLY ) {
-               const char* str = dyld::mkstringf("dlord(RTLD_MAIN_ONLY, %u): not supported", ordinal);
-               dlerrorSet(str);
-               free((void*)str);
-               return NULL;
-       }
-       // magic "search what I would see" handle
-       if ( handle == RTLD_NEXT ) {
-               const char* str = dyld::mkstringf("dlord(RTLD_NEXT, %u): not supported", ordinal);
-               dlerrorSet(str);
-               free((void*)str);
-               return NULL;
-       }
-       // magic "search me, then what I would see" handle
-       if ( handle == RTLD_SELF ) {
-               const char* str = dyld::mkstringf("dlord(RTLD_SELF, %u): not supported", ordinal);
-               dlerrorSet(str);
-               free((void*)str);
-               return NULL;
-       }
-       
-       // real handle
-       const ImageLoader* image = (ImageLoader*)(((uintptr_t)handle) & (-4));  // clear mode bits
-       if ( dyld::validImage(image) ) {
-               const ImageLoader::Symbol* sym;
-               sym = image->getIndexedExportedSymbol(ordinal-1); // map ordinals to mach-o zero based index
-               
-               if ( sym != NULL ) {
-                       return (void*)image->getExportedSymbolAddress(sym, dyld::gLinkContext);
-               }
-               const char* str = dyld::mkstringf("dlord(%p, %u): ordinal not found", handle, ordinal);
-               dlerrorSet(str);
-               free((void*)str);
-       }
-       else {
-               dlerrorSet("invalid handle passed to dlord()");
-       }
-       return NULL;
-}
-
-
-
 
 
 
@@ -1714,11 +1643,25 @@ void* dlord(void* handle, uint32_t ordinal)
 
 
 
-static const struct dyld_all_image_infos* _dyld_get_all_image_infos()
+const struct dyld_all_image_infos* _dyld_get_all_image_infos()
 {
        return &dyld_all_image_infos;
 }
 
+#if !__arm__
+static bool client_dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info)
+{
+       //if ( dyld::gLogAPIs )
+       //      dyld::log("%s(%p, %p)\n", __func__, addr, info);
+       
+       ImageLoader* image = dyld::findImageContainingAddress(addr);
+       if ( image != NULL ) {
+               image->getUnwindInfo(info);
+               return true;
+       }
+       return false;
+}
+#endif
 
 
 void dyld_register_image_state_change_handler(dyld_image_states state, bool batch, 
@@ -1733,9 +1676,15 @@ void dyld_register_image_state_change_handler(dyld_image_states state, bool batc
 }
 
 
+const char* dyld_image_path_containing_address(const void* address)
+{
+       if ( dyld::gLogAPIs )
+               dyld::log("%s(%p)\n", __func__, address);
 
-
-
-
+       ImageLoader* image = dyld::findImageContainingAddress(address);
+       if ( image != NULL )
+               return image->getPath();
+       return NULL;
+}
 
 
index fbc172f3dda1cd57f22444bb593c9c15095e10c0..e14a6efdd9724cb973fd0ef19d60d927c995a58c 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 
 #include <stddef.h>
 #include <string.h>
+#include <malloc/malloc.h>
+
 #include <crt_externs.h>
+#include <Availability.h>
 
 #include "mach-o/dyld.h"
 #include "mach-o/dyld_priv.h"
 
 extern "C" int __cxa_atexit(void (*func)(void *), void *arg, void *dso);
 
+#define DYLD_SHARED_CACHE_SUPPORT (__ppc__ || __i386__ || __ppc64__ || __x86_64__)
+
+// deprecated APIs are still availble on Mac OS X, but not on iPhone OS
+#if __IPHONE_OS_VERSION_MIN_REQUIRED   
+       #define DEPRECATED_APIS_SUPPORTED 0
+#else
+       #define DEPRECATED_APIS_SUPPORTED 1
+#endif
 
 /*
  * names_match() takes an install_name from an LC_LOAD_DYLIB command and a
@@ -87,6 +98,8 @@ const char* libraryName)
        return(FALSE);
 }
 
+#if DEPRECATED_APIS_SUPPORTED
+
 void NSInstallLinkEditErrorHandlers(
 const NSLinkEditErrorHandlers* handlers)
 {
@@ -294,6 +307,7 @@ uint32_t options)
            _dyld_func_lookup("__dyld_NSAddImage", (void**)&p);
        return(p(image_name, options));
 }
+#endif // DEPRECATED_APIS_SUPPORTED
 
 /*
  * This routine returns the current version of the named shared library the
@@ -385,6 +399,7 @@ const char* libraryName)
        return(-1);
 }
 
+#if DEPRECATED_APIS_SUPPORTED
 /*
  * NSCreateObjectFileImageFromFile() creates an NSObjectFileImage for the
  * specified file name if the file is a correct Mach-O file that can be loaded
@@ -477,31 +492,6 @@ uint32_t options)
 }
 
 
-/*
- * NSFindSectionAndOffsetInObjectFileImage() takes the specified imageOffset
- * into the specified ObjectFileImage and returns the segment/section name and
- * offset into that section of that imageOffset.  Returns FALSE if the
- * imageOffset is not in any section.  You can used the resulting sectionOffset
- * to index into the data returned by NSGetSectionDataInObjectFileImage.
- * 
- * SPI: currently only used by ZeroLink to detect +load methods
- */
-bool 
-NSFindSectionAndOffsetInObjectFileImage(
-NSObjectFileImage objectFileImage, 
-unsigned long imageOffset,
-const char** segmentName,      /* can be NULL */
-const char** sectionName,      /* can be NULL */
-unsigned long* sectionOffset)  /* can be NULL */
-{
-       DYLD_LOCK_THIS_BLOCK;
-    static bool (*p)(NSObjectFileImage, unsigned long, const char**, const char**, unsigned long*) = NULL;
-
-       if(p == NULL)
-           _dyld_func_lookup("__dyld_NSFindSectionAndOffsetInObjectFileImage", (void**)&p);
-               
-       return p(objectFileImage, imageOffset, segmentName, sectionName, sectionOffset);
-}
 
 
 /*
@@ -620,24 +610,6 @@ unsigned long *size) /* can be NULL */
        return p(objectFileImage, segmentName, sectionName, size);
 }
 
-/*
- * NSHasModInitObjectFileImage() returns TRUE if the NSObjectFileImage has any
- * module initialization sections and FALSE it it does not.
- *
- * SPI: currently only used by ZeroLink to detect C++ initializers
- */
-bool
-NSHasModInitObjectFileImage(
-NSObjectFileImage objectFileImage)
-{
-       DYLD_LOCK_THIS_BLOCK;
-    static bool (*p)(NSObjectFileImage) = NULL;
-
-       if(p == NULL)
-           _dyld_func_lookup("__dyld_NSHasModInitObjectFileImage", (void**)&p);
-               
-       return p(objectFileImage);
-}
 
 void
 NSLinkEditError(
@@ -683,6 +655,9 @@ uint32_t options)
 }
 #endif
 
+
+#endif // DEPRECATED_APIS_SUPPORTED
+
 /*
  *_NSGetExecutablePath copies the path of the executable into the buffer and
  * returns 0 if the path was successfully copied in the provided buffer. If the
@@ -705,6 +680,7 @@ uint32_t *bufsize)
        return(p(buf, bufsize));
 }
 
+#if DEPRECATED_APIS_SUPPORTED
 void
 _dyld_lookup_and_bind(
 const char* symbol_name,
@@ -775,6 +751,7 @@ const void* address)
            _dyld_func_lookup("__dyld_bind_fully_image_containing_address", (void**)&p);
        return p(address);
 }
+#endif // DEPRECATED_APIS_SUPPORTED
 
 
 /*
@@ -903,12 +880,14 @@ _dyld_bind_objc_module(const void* objc_module)
 }
 #endif
 
+#if DEPRECATED_APIS_SUPPORTED
 bool
 _dyld_present(void)
 {
        // this function exists for compatiblity only
        return true;
 }
+#endif
 
 uint32_t
 _dyld_image_count(void)
@@ -954,6 +933,18 @@ _dyld_get_image_name(uint32_t image_index)
        return(p(image_index));
 }
 
+// SPI in Mac OS X 10.6
+intptr_t _dyld_get_image_slide(const struct mach_header* mh)
+{
+       DYLD_NO_LOCK_THIS_BLOCK;
+    static intptr_t (*p)(const struct mach_header*) = NULL;
+
+       if(p == NULL)
+           _dyld_func_lookup("__dyld_get_image_slide", (void**)&p);
+       return(p(mh));
+}
+
+
 bool
 _dyld_image_containing_address(const void* address)
 {
@@ -988,6 +979,7 @@ void (*monaddition)(char *lowpc, char *highpc))
        p(monaddition);
 }
 
+#if DEPRECATED_APIS_SUPPORTED
 bool _dyld_launched_prebound(void)
 {
        DYLD_LOCK_THIS_BLOCK;
@@ -1007,6 +999,7 @@ bool _dyld_all_twolevel_modules_prebound(void)
            _dyld_func_lookup("__dyld_all_twolevel_modules_prebound", (void**)&p);
        return(p());
 }
+#endif // DEPRECATED_APIS_SUPPORTED
 
 
 #include <dlfcn.h>
@@ -1016,7 +1009,6 @@ bool _dyld_all_twolevel_modules_prebound(void)
 #include <mach-o/dyld.h>
 #include <servers/bootstrap.h>
 #include "dyldLibSystemInterface.h"
-#include "dyld_shared_cache_user.h"
 
 
 // pthread key used to access per-thread dlerror message
@@ -1061,54 +1053,30 @@ static char* getPerThreadBufferFor_dlerror(uint32_t sizeRequired)
 }
 
 
-
-static bool get_update_dyld_shared_cache_bootstrap_port(mach_port_t& mp)
-{
-       static bool found = false;
-       static mach_port_t port;
-       if ( found ) {
-               mp = port;
-               return true;
-       }
-       if ( bootstrap_look_up(bootstrap_port, "com.apple.dyld", &port) == KERN_SUCCESS ) {
-               found = true;
-               mp = port;
-               return true;
-       }
-       return false;
-}
-
-#if __ppc__
-       #define CUR_ARCH        CPU_TYPE_POWERPC
-#elif __ppc64__
-       #define CUR_ARCH        CPU_TYPE_POWERPC64
-#elif __i386__
-       #define CUR_ARCH        CPU_TYPE_I386
-#elif __x86_64__
-       #define CUR_ARCH        CPU_TYPE_X86_64
-#endif
-
+#if DYLD_SHARED_CACHE_SUPPORT
 static void shared_cache_missing()
 {
-       mach_port_t mp;
-       if ( get_update_dyld_shared_cache_bootstrap_port(mp) )
-               dyld_shared_cache_missing(mp, CUR_ARCH, 0);
+       // leave until dyld's that might call this are rare
 }
 
 static void shared_cache_out_of_date()
 {
-       mach_port_t mp;
-       if ( get_update_dyld_shared_cache_bootstrap_port(mp) )
-               dyld_shared_cache_out_of_date(mp, CUR_ARCH, 0);
+       // leave until dyld's that might call this are rare
 }
+#endif // DYLD_SHARED_CACHE_SUPPORT
 
 
-
-// that table passed to dyld containing thread helpers
-static dyld::LibSystemHelpers sHelpers = { 4, &dyldGlobalLockAcquire, &dyldGlobalLockRelease,  
+// the table passed to dyld containing thread helpers
+static dyld::LibSystemHelpers sHelpers = { 6, &dyldGlobalLockAcquire, &dyldGlobalLockRelease,  
                                                                        &getPerThreadBufferFor_dlerror, &malloc, &free, &__cxa_atexit,
+                                               #if DYLD_SHARED_CACHE_SUPPORT
                                                                        &shared_cache_missing, &shared_cache_out_of_date,
-                                                                       NULL, NULL };
+                                               #else
+                                                                       NULL, NULL,
+                                               #endif
+                                                                       NULL, NULL,
+                                                                       &pthread_key_create, &pthread_setspecific,
+                                                                       &malloc_size };
 
 
 //
@@ -1208,6 +1176,52 @@ void dyld_register_image_state_change_handler(dyld_image_states state,
 }
 
 
+const struct dyld_all_image_infos* _dyld_get_all_image_infos()
+{
+       DYLD_NO_LOCK_THIS_BLOCK;
+    static struct dyld_all_image_infos* (*p)() = NULL;
+
+       if(p == NULL)
+           _dyld_func_lookup("__dyld_get_all_image_infos", (void**)&p);
+       return p();
+}
+
+#if !__arm__
+__attribute__((visibility("hidden"))) 
+bool _dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info)
+{
+       DYLD_NO_LOCK_THIS_BLOCK;
+    static void* (*p)(void*, dyld_unwind_sections*) = NULL;
+
+       if(p == NULL)
+           _dyld_func_lookup("__dyld_find_unwind_sections", (void**)&p);
+       return p(addr, info);
+}
+#endif
+
+
+#if __i386__ || __x86_64__
+__attribute__((visibility("hidden"))) 
+void* _dyld_fast_stub_entry(void* loadercache, long lazyinfo)
+{
+       DYLD_NO_LOCK_THIS_BLOCK;
+    static void* (*p)(void*, long) = NULL;
+
+       if(p == NULL)
+           _dyld_func_lookup("__dyld_fast_stub_entry", (void**)&p);
+       return p(loadercache, lazyinfo);
+}
+#endif
+
+
+const char* dyld_image_path_containing_address(const void* addr)
+{
+       DYLD_NO_LOCK_THIS_BLOCK;
+    static const char* (*p)(const void*) = NULL;
 
+       if(p == NULL)
+           _dyld_func_lookup("__dyld_image_path_containing_address", (void**)&p);
+       return p(addr);
+}
 
 
index 133e978fe2710d8bc926c5caca09b31a90fb5fae..0cf1a18ec44fcc5e76a59a342b340dfc31069889 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-2008 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <string.h>
 #include <mach-o/loader.h>
 #include <unistd.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <pthread.h>
+
+#include "mach-o/dyld_priv.h"
+#include "dyldLibSystemInterface.h"
+
+extern void _ZN4dyld3logEPKcz(const char*, ...);
+extern struct LibSystemHelpers* _ZN4dyld17gLibSystemHelpersE;
+
+
+#if __LP64__
+       #define LC_SEGMENT_COMMAND              LC_SEGMENT_64
+       #define macho_header                    mach_header_64
+       #define macho_segment_command   segment_command_64
+       #define macho_section                   section_64
+       #define getsectdatafromheader   getsectdatafromheader_64
+#else
+       #define LC_SEGMENT_COMMAND              LC_SEGMENT
+       #define macho_header                    mach_header
+       #define macho_segment_command   segment_command
+       #define macho_section                   section
+#endif
+
+
+#if __i386__ || __x86_64 || __ppc__
+
+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)
+{
+       // record location of unwind sections in dyld itself
+    sDyldInfo.mh = mh;    
+       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, "__TEXT") == 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, "__eh_frame") == 0 ) {
+                                               sDyldInfo.dwarf_section = (void*)(sect[j].addr + slide);
+                                               sDyldInfo.dwarf_section_length = sect[j].size;
+                                       }
+                                       else if ( strcmp(sect[j].sectname, "__unwind_info") == 0 ) {
+                                               sDyldInfo.compact_unwind_section = (void*)(sect[j].addr + slide);
+                                               sDyldInfo.compact_unwind_section_length = sect[j].size;
+                                       }
+                               }
+                               sDyldTextEnd = (void*)(seg->vmaddr + seg->vmsize + slide);
+                   }
+               }
+           cmd = (struct load_command*)( (char*)cmd + cmd->cmdsize );
+       }
+}
+
+// called by libuwind code to find unwind information in dyld
+bool _dyld_find_unwind_sections(void* addr, struct dyld_unwind_sections* info)
+{
+       if ( ((void*)sDyldInfo.mh < addr) && (addr < sDyldTextEnd) ) { 
+               *info = sDyldInfo;
+               return true;
+       }
+       else {
+               return false;
+       }
+}
+
+
+
+// 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
+
+
+
+
+
+#else /*  __i386__ || __x86_64 || __ppc__ */
+
+
+
+
+
 
 //
 // BEGIN copy of code from libgcc.a source file unwind-dw2-fde-darwin.c
@@ -158,18 +282,6 @@ void _keymgr_set_per_thread_data(unsigned int key, void *keydata)
        dyld_abort();
 }
 
-#if __LP64__
-       #define LC_SEGMENT_COMMAND              LC_SEGMENT_64
-       #define macho_header                    mach_header_64
-       #define macho_segment_command   segment_command_64
-       #define macho_section                   section_64
-       #define getsectdatafromheader   getsectdatafromheader_64
-#else
-       #define LC_SEGMENT_COMMAND              LC_SEGMENT
-       #define macho_header                    mach_header
-       #define macho_segment_command   segment_command
-       #define macho_section                   section
-#endif
 
 // 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)
@@ -209,4 +321,7 @@ const void* getsectdatafromheader(struct mach_header* mh, const char* segname, c
        }
 #endif
 
+#endif
+
+
 
index 61b23b38d7b03e8881369342c1dae37553a38bd0..a112d18389b88a0dcda1f7f034ebbd4d2b057302 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-2008 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 
 
 #if __LP64__
-       #define macho_header                    mach_header_64
        #define LC_SEGMENT_COMMAND              LC_SEGMENT_64
        #define macho_segment_command   segment_command_64
        #define macho_section                   section_64
        #define RELOC_SIZE                              3
 #else
-       #define macho_header                    mach_header
        #define LC_SEGMENT_COMMAND              LC_SEGMENT
        #define macho_segment_command   segment_command
        #define macho_section                   section
@@ -219,13 +217,19 @@ static void segmentProtectDyld(const struct macho_header* mh, intptr_t slide)
 //
 // re-map the main executable to a new random address
 //
-static const struct mach_header* randomizeExecutableLoadAddress(const struct mach_header* orgMH, uintptr_t* appsSlide)
+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;
@@ -267,6 +271,8 @@ static const struct mach_header* randomizeExecutableLoadAddress(const struct mac
        // 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
@@ -287,11 +293,13 @@ static const struct mach_header* randomizeExecutableLoadAddress(const struct mac
                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 exectable\n");
+                               dyld::warn("could not relocate position independent executable\n");
                                return orgMH;
                        }
                }
@@ -300,7 +308,7 @@ static const struct mach_header* randomizeExecutableLoadAddress(const struct mac
        
                // run with newly mapped executable
                *appsSlide = newBaseAddress - lowestAddressUsed;
-               return (const struct mach_header*)newBaseAddress;
+               return (const struct macho_header*)newBaseAddress;
        }
        
        // can't get new range, so don't slide to random address
@@ -327,7 +335,7 @@ 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 mach_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)
 {
        // _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);
@@ -339,11 +347,7 @@ uintptr_t start(const struct mach_header* appsMachHeader, int argc, const char*
        }
        
        uintptr_t appsSlide = 0;
-       
-       // set pthread keys to dyld range
-       __pthread_tsd_first = 1;
-       _pthread_keys_init();
-       
+               
        // enable C++ exceptions to work inside dyld
        dyld_exceptions_init(dyldsMachHeader, slide);
        
@@ -366,7 +370,7 @@ uintptr_t start(const struct mach_header* appsMachHeader, int argc, const char*
        
        // if main executable was linked -pie, then randomize its load address
        if ( appsMachHeader->flags & MH_PIE )
-               appsMachHeader = randomizeExecutableLoadAddress(appsMachHeader, &appsSlide);
+               appsMachHeader = randomizeExecutableLoadAddress(appsMachHeader, envp, &appsSlide);
        
        // now that we are done bootstrapping dyld, call dyld's main
        return dyld::_main(appsMachHeader, appsSlide, argc, argv, envp, apple);
diff --git a/src/dyldLibSystemGlue.c b/src/dyldLibSystemGlue.c
new file mode 100644 (file)
index 0000000..2628673
--- /dev/null
@@ -0,0 +1,49 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * 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>
+
+//
+// <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.
+
+struct __DATA__dyld { long lazy; int (*lookup)(const char*, void**); };
+
+static struct __DATA__dyld  myDyldSection __attribute__ ((section ("__DATA,__dyld"))) = { 0, NULL };
+
+
+__attribute__((weak, visibility("hidden"))) int _dyld_func_lookup(const char* dyld_func_name, void **address)
+{
+       return (*myDyldSection.lookup)(dyld_func_name, address);
+}
+
+#endif
+
+
+
index c110616e86be1671190945052b3e8ba4fd50db51..94062fc044b7328c6280e5b0ac2b49c91bfb8c93 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@
  * 
@@ -28,8 +28,9 @@
 
 #include <stdint.h>
 
-
+#if __cplusplus
 namespace dyld {
+#endif
        //
        // This file contains the synchronization utilities used by dyld to be thread safe.
        // This struct is implemented in in libSystem (where pthreads is available)
@@ -51,9 +52,15 @@ namespace dyld {
                // addded in version 4
                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*);
+               // added in version 6
+               size_t          (*malloc_size)(const void *ptr);
        };
+#if __cplusplus
 };
-
+#endif
 
 
 
index b94551b3c79f7d61bdfd06ce7f2c87dff68d3536..dad139054a626d2274a92e91f33c827836e78b2f 100644 (file)
@@ -30,6 +30,9 @@
 
 static pthread_mutex_t sGlobalMutex;
 
+// <rdar://problem/6361143> Need a way to determine if a gdb call to dlopen() would block
+int    __attribute__((visibility("hidden")))                   _dyld_global_lock_held = 0;
+
 
 //
 // This initializer can go away once the following is available:
@@ -46,21 +49,23 @@ void dyldGlobalLockInitialize()
 
 LockHelper::LockHelper() 
 { 
-       pthread_mutex_lock(&sGlobalMutex);
+       dyldGlobalLockAcquire();
 }
 
 LockHelper::~LockHelper() 
 { 
-       pthread_mutex_unlock(&sGlobalMutex);
+       dyldGlobalLockRelease();
 }
 
 void dyldGlobalLockAcquire() 
 {
        pthread_mutex_lock(&sGlobalMutex);
+       _dyld_global_lock_held = 1;
 }
 
 void dyldGlobalLockRelease() 
 {
+       _dyld_global_lock_held = 0;
        pthread_mutex_unlock(&sGlobalMutex);
 }
 
index 4a5dcad48f7bcbeaefc5a5e2c816d66ccfa5a79b..fe828eecff14edbedf42e559829ea5cbb1219844 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2008 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -26,6 +26,7 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include <string.h>
+#include <mach/mach.h>
 
 extern "C" void* __dso_handle;
 
@@ -39,13 +40,24 @@ extern "C" void* __dso_handle;
 
 #if __LP64__
        // room for about ~1000 initial dylibs
-       #define DYLD_INITIAL_POOL_SIZE 400*1024
+       #define DYLD_POOL_CHUNK_SIZE 200*1024
 #else
        // room for about ~900 initial dylibs
-       #define DYLD_INITIAL_POOL_SIZE 200*1024
+       #define DYLD_POOL_CHUNK_SIZE 150*1024
 #endif
-static uint8_t dyldPool[DYLD_INITIAL_POOL_SIZE];
-static uint8_t* curPoolPtr = dyldPool;
+
+struct dyld_static_pool {
+       dyld_static_pool*       previousPool;
+       uint8_t*                        current;
+       uint8_t*                        end;
+       uint8_t                         pool[1]; 
+};
+
+// allocate initial pool independently of pool header to take less space on disk
+static uint8_t initialPoolContent[DYLD_POOL_CHUNK_SIZE] __attribute__((__aligned__(16)));
+static dyld_static_pool initialPool = { NULL, initialPoolContent, &initialPoolContent[DYLD_POOL_CHUNK_SIZE] };
+static dyld_static_pool* currentPool = &initialPool;
+
 
 void* malloc(size_t size)
 {
@@ -56,13 +68,29 @@ void* malloc(size_t size)
        }
        else {
                size = (size+sizeof(void*)-1) & (-sizeof(void*)); // pointer align
-               uint8_t* result = curPoolPtr;
-               if ( (curPoolPtr + size) > &dyldPool[DYLD_INITIAL_POOL_SIZE] ) {
-                       dyld::log("initial dyld memory pool exhausted\n");
-                       _exit(1);
+               uint8_t* result = currentPool->current;
+               currentPool->current += size;
+               if ( currentPool->current > currentPool->end ) {
+                       vm_address_t addr = 0;
+                       kern_return_t r = vm_allocate(mach_task_self(), &addr, DYLD_POOL_CHUNK_SIZE, VM_FLAGS_ANYWHERE);
+                       if ( r != KERN_SUCCESS ) {
+                               dyld::log("out of address space for dyld memory pool\n");
+                               exit(1);
+                       }
+                       dyld_static_pool* newPool = (dyld_static_pool*)addr;
+                       newPool->previousPool = NULL;
+                       newPool->current = newPool->pool;
+                       newPool->end = (uint8_t*)(addr + DYLD_POOL_CHUNK_SIZE);
+                       newPool->previousPool = currentPool;
+                       currentPool = newPool;
+                       if ( (currentPool->current + size) > currentPool->end ) {
+                               dyld::log("dyld memory pool exhausted: size=%lu\n", size);
+                               exit(1);
+                       }
+                       result = currentPool->current;
+                       currentPool->current += size;
                }
-               curPoolPtr += size;
-               //dyld::log("%p = malloc(%lu) from pool, total = %d\n", result, size, curPoolPtr-dyldPool);
+               //dyld::log("%p = malloc(%3lu) from pool %p, free space = %lu\n", result, size, currentPool, (long)(currentPool->end - currentPool->current));
                return result;
        }
 }
@@ -71,13 +99,22 @@ void* malloc(size_t size)
 void free(void* ptr)
 {
        // ignore any pointer within dyld (i.e. stuff from pool or static strings)
-       if ( (dyld::gLibSystemHelpers != NULL) && ((ptr < &__dso_handle) || (ptr >= &dyldPool[DYLD_INITIAL_POOL_SIZE])) ) {
+       if ( (dyld::gLibSystemHelpers != NULL) && ((ptr < &__dso_handle) || (ptr >= &initialPoolContent[DYLD_POOL_CHUNK_SIZE])) ) {
+               // ignore stuff in any dynamically alloated dyld pools
+               for (dyld_static_pool* p = initialPool.previousPool; p != NULL; p = p->previousPool) {
+                       if ( (p->pool < ptr) && (ptr < p->end) ) {
+                               // do nothing, pool entries can't be reclaimed
+                               //dyld::log("free(%p) from dynamic pool\n", ptr);
+                               return;
+                       }
+               }
+               
                //dyld::log("free(%p) from libSystem\n", ptr);
                return dyld::gLibSystemHelpers->free(ptr);
        }
        else {
                // do nothing, pool entries can't be reclaimed
-               //dyld::log("free(%p) from pool\n", ptr);
+               //dyld::log("free(%p) from static pool\n", ptr);
        }
 }
 
@@ -85,8 +122,8 @@ void free(void* ptr)
 void* calloc(size_t count, size_t size)
 {
        if ( dyld::gLibSystemHelpers != NULL ) {
-               void* result = dyld::gLibSystemHelpers->malloc(size);
-               bzero(result, size);
+               void* result = dyld::gLibSystemHelpers->malloc(size*count);
+               bzero(result, size*count);
                return result;
        }
        else {
index 1bf79318ccc2aaf644220839f25cc82ed1096589..e1214f80e32d3337883801cbfbd1def670e3e533 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2008 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *     Where arg[i] and env[i] point into the STRING AREA
  */
 
-       .globl __dyld_start
 
 
+       // Hack to make _offset_to_dyld_all_image_infos work
+       // Without this local symbol, assembler will error out about in subtraction expression
+       // The real _dyld_all_image_infos (non-weak) _dyld_all_image_infos is defined in dyld_gdb.o
+       // and the linker with throw this one away and use the real one instead.
+       .section __DATA,__datacoal_nt,coalesced
+       .globl _dyld_all_image_infos
+       .weak_definition _dyld_all_image_infos
+_dyld_all_image_infos: .long 0
+
+
+
+       .globl __dyld_start
+
 #ifdef __i386__
        .data
 __dyld_start_static_picbase: 
@@ -84,7 +96,17 @@ _stub_binding_helper:
        .globl  _dyld_func_lookup
 _dyld_func_lookup:
        jmp     __Z18lookupDyldFunctionPKcPm
+       nop
+       nop
+       nop
+_offset_to_dyld_all_image_infos:
+       .long   _dyld_all_image_infos - . + 0x1010 
+       .long   0
+       # space for future stable entry points
+       .space  16
 
+       
+       
        .text
        .align  4, 0x90
        .globl __dyld_start
@@ -106,7 +128,7 @@ L__dyld_start_picbase:
        pushl   %ebx            # param2 = argc
        movl    4(%ebp),%ebx    
        pushl   %ebx            # param1 = mh
-       call    __ZN13dyldbootstrap5startEPK11mach_headeriPPKcl 
+       call    __ZN13dyldbootstrap5startEPK12macho_headeriPPKcl        
 
        # clean up stack and jump to result
        movl    %ebp,%esp       # restore the unaligned stack pointer
@@ -123,6 +145,7 @@ L_end:
 #endif /* __i386__ */
 
 
+
 #if __x86_64__
        .data
        .align 3
@@ -141,6 +164,15 @@ _stub_binding_helper:
        .globl  _dyld_func_lookup
 _dyld_func_lookup:
        jmp     __Z18lookupDyldFunctionPKcPm
+       nop
+       nop
+       nop
+_offset_to_dyld_all_image_infos:
+       .long   _dyld_all_image_infos - . + 0x1010 
+       .long   0
+       # space for future stable entry points
+       .space  16
+
 
        .text
        .align 2,0x90
@@ -157,7 +189,7 @@ __dyld_start:
        movq    __dyld_start_static(%rip), %r8
        leaq    __dyld_start(%rip), %rcx
        subq     %r8, %rcx      # param4 = slide into %rcx
-       call    __ZN13dyldbootstrap5startEPK11mach_headeriPPKcl 
+       call    __ZN13dyldbootstrap5startEPK12macho_headeriPPKcl        
 
        # clean up stack and jump to result
        movq    %rbp,%rsp       # restore the unaligned stack pointer
@@ -196,7 +228,12 @@ _stub_binding_helper:
        .globl  _dyld_func_lookup
 _dyld_func_lookup:
        b       __Z18lookupDyldFunctionPKcPm
-       
+       nop 
+_offset_to_dyld_all_image_infos:
+       .long   _dyld_all_image_infos - . + 0x1010 
+       .long   0
+       # space for future stable entry points
+       .space  16
        
        
        .text
@@ -219,7 +256,7 @@ 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      __ZN13dyldbootstrap5startEPK11mach_headeriPPKcl 
+       bl      __ZN13dyldbootstrap5startEPK12macho_headeriPPKcl        
        
        ; clean up stack and jump to result
        mtctr   r3              ; Put entry point in count register
@@ -234,6 +271,81 @@ dyld_stub_binding_helper:
 L_end:
 #endif /* __ppc__ */
 
+#if __arm__
+       .data
+       .align 2
+__dyld_start_static_picbase: 
+       .long   L__dyld_start_picbase
+
+       .text
+       .align 2
+       .globl  _stub_binding_helper
+_stub_binding_helper:
+       b       _stub_binding_helper_interface
+       nop 
+       
+       .globl  _dyld_func_lookup
+_dyld_func_lookup:
+       b       _branch_to_lookupDyldFunction
+       nop
+       
+_offset_to_dyld_all_image_infos:
+       .long   _dyld_all_image_infos - . + 0x1010 
+       .long   0
+       # space for future stable entry points
+       .space  16
+    
+    
+       .text
+       .align 2
+__dyld_start:
+       // call dyldbootstrap::start(app_mh, argc, argv, slide)         
+
+       ldr     r3, L__dyld_start_picbase_ptr
+L__dyld_start_picbase:
+       sub     r0, pc, #8      // load actual PC
+       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
+
+       mov     r8, sp          // save stack pointer
+       bic     sp, sp, #7      // force 8-byte alignment
+       
+       bl      __ZN13dyldbootstrap5startEPK12macho_headeriPPKcl
+       
+       // 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
+
+       
+       .text
+       .align 2
+_branch_to_lookupDyldFunction:
+       // arm has no "bx label" instruction, so need this island in case lookupDyldFunction() is in thumb
+       ldr ip, L2
+L1:    ldr pc, [pc, ip]
+L2:    .long   _lookupDyldFunction_ptr-8-L1
+       
+       .data
+       .align 2
+_lookupDyldFunction_ptr:
+       .long   __Z18lookupDyldFunctionPKcPm
+       
+      
+       .text
+       .globl dyld_stub_binding_helper
+dyld_stub_binding_helper:
+       trap
+
+L_end:
+#endif /* __arm__ */
 
 /*
  * dyld calls this function to terminate a process.
@@ -244,10 +356,12 @@ L_end:
        .align 2
        .globl  _dyld_fatal_error
 _dyld_fatal_error:
-#if __ppc__ || __ppc64__
+#if __ppc__ || __ppc64__ || __arm__
     trap
+    nop
 #elif __x86_64__ || __i386__
     int3
+    nop
 #else
     #error unknown architecture
 #endif
index 456f048a8ee86319472b1b08e4771fedd1e5550f..7d79aade137ea0d290d8682b6a1d295bec59318d 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@
  * 
 
 #include "mach-o/dyld_gdb.h"
 #include "mach-o/dyld_images.h"
+#include "ImageLoader.h"
 
-#define OLD_GDB_DYLD_INTERFACE __ppc__ || __i386__
-
-// old gdb interface to dyld only supported on 32-bit ppc and i386
-#if OLD_GDB_DYLD_INTERFACE
-
-unsigned int gdb_dyld_version = 2;
-
-
-/*
- * gdb_dyld_state_changed() is a dummy routine called by dyld after images get
- * added or removed/ Gdb is expected to set a break point at
- * gdb_dyld_state_changed() then re-read dyld internal data as specified in
- * the header file dyld_gdb.h
- */
-void gdb_dyld_state_changed()
-{
-       // do nothing
-}
-
-#define NLIBRARY_IMAGES 200
-#define NOBJECT_IMAGES 1
-
-
-struct image {   
-       const char*                     physical_name;          // physical image name (file name)
-       uint32_t                        vmaddr_slide;           // the slide from the staticly linked address
-       const mach_header*  mh;                                 // address of the mach header of the image
-       uint32_t                        valid;                          // TRUE if this is struct is valid
-       const char*                     name;                           // image name for reporting errors
-};
-
-
-struct library_images { 
-       struct image                    images[NLIBRARY_IMAGES];
-       uint32_t                                nimages;
-       struct library_images*  next_images;
-};
-struct object_images { 
-       struct image                    images[NOBJECT_IMAGES];
-       uint32_t                                nimages;
-       struct library_images*  next_images;
-};
-
-unsigned int gdb_nobject_images                = NOBJECT_IMAGES;
-unsigned int gdb_object_image_size     = sizeof(image);
-unsigned int gdb_nlibrary_images       = NLIBRARY_IMAGES;
-unsigned int gdb_library_image_size    = sizeof(image);
-
-extern "C" {
-object_images   object_images;// = { {}, 0 , NULL };
-library_images library_images;// = { {}, 0 , NULL };
-void send_event(const struct dyld_event* event);
-}
-
-
-enum dyld_event_type {
-    DYLD_IMAGE_ADDED = 0,
-    DYLD_IMAGE_REMOVED = 5
-};
-
-struct dyld_event {
-    enum dyld_event_type               type;
-    const struct mach_header*   header;
-    uintptr_t                                  slide;
-};
-
-
-// gdb only notices changes bundles/dylibs loaded at runtime
-// if the "send_event()" function in dyld is called...
-void send_event(const struct dyld_event* event);
-void (*send_event_ptr)(const struct dyld_event* event) = &send_event;
-
-void addImageForgdb(const mach_header* mh, uintptr_t slide, const char* physicalPath, const char* logicalPath)
-{
-       struct library_images* li = &library_images;
-       while ( li->nimages >= NLIBRARY_IMAGES ) {
-               if ( li->next_images == NULL ) {
-                       struct library_images* li2 = new struct library_images();
-                       li2->nimages = 0;
-                       li2->next_images = NULL;
-                       li->next_images = li2;
-                       li = li2;
-               }
-               else {
-                       li = li->next_images;
-               }
-       }
-       image* info = &li->images[li->nimages++];
-       info->physical_name             = physicalPath;
-       info->vmaddr_slide              = slide;
-       info->mh                                = mh;
-       info->valid                             = 1;
-       info->name                              = logicalPath;
-       
-       // ping gdb about change
-       dyld_event event;
-       event.type = DYLD_IMAGE_ADDED;
-       event.header = mh;
-       event.slide = slide;
-       
-       // we have to indirect through a function pointer to keep gcc-3.5 from inlining away the function call
-       // rdar://problem/3830560
-       (*send_event_ptr)(&event);
-}
-
-// move this to after use, otherwise gcc will see it has an empty implementation and
-// optimize away the call site
-void send_event(const struct dyld_event* event)
-{
-       // This function exists to let gdb set a break point
-       // and catch libraries being added...
-}
-
-
-void removeImageForgdb(const mach_header* mh)
-{
-       for (struct library_images* li = &library_images; li != NULL; li = li->next_images) {
-               for( uint32_t n=0; n < li->nimages; ++n) {
-                       struct image* image = &li->images[n];
-                       if ( image->mh == mh ) {
-                               image->physical_name = NULL;
-                               image->vmaddr_slide = 0;
-                               image->mh                       = 0;
-                               image->valid            = 0;
-                               image->name                     = NULL;
-                               return;
-                       }
-               }
-       }
-}
-
-#endif
 
 static std::vector<dyld_image_info> sImageInfos;
 
-
-
 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
        if ( sImageInfos.size() == 0 )
-               sImageInfos.reserve(200);
+               sImageInfos.reserve(INITIAL_IMAGE_COUNT);
 
        // set infoArray to NULL to denote it is in-use
        dyld_all_image_infos.infoArray = NULL;
@@ -227,10 +94,22 @@ static void gdb_image_notifier(enum dyld_image_mode mode, uint32_t infoCount, co
        //      dyld::log("dyld: %d loading at %p %s\n", i, dyld_all_image_infos.infoArray[i].imageLoadAddress, dyld_all_image_infos.infoArray[i].imageFilePath);
 }
 
+void setAlImageInfosHalt(const char* message, uintptr_t flags)
+{
+       dyld_all_image_infos.errorMessage = message;
+       dyld_all_image_infos.terminationFlags = flags;
+}
 
 
-struct dyld_all_image_infos  dyld_all_image_infos = { 1, 0, NULL, &gdb_image_notifier, false };
+extern void* __dso_handle;
+#define STR(s) # s
+#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 };
 
 struct dyld_shared_cache_ranges dyld_shared_cache_ranges;
 
+
  
diff --git a/src/dyld_stub_binder.s b/src/dyld_stub_binder.s
new file mode 100644 (file)
index 0000000..6d7f182
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2008 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@
+ */
+
+#ifdef __i386__
+
+#define MH_PARAM_OUT                   0
+#define LP_PARAM_OUT                   4
+#define XMMM0_SAVE                     16      /* 16-byte align */
+#define XMMM1_SAVE                     32
+#define XMMM2_SAVE                     48
+#define XMMM3_SAVE                     64
+#define EAX_SAVE                       84
+#define ECX_SAVE                       88
+#define EDX_SAVE                       92
+#define LP_LOCAL                       96
+#define MH_LOCAL                       100
+#define STACK_SIZE                     100     /* must be 4 mod 16 so that stack winds up 16-byte aliged  */
+#define LP_OLD_BP_SAVE                 104
+
+/*    
+ * sp+4        lazy binding info offset
+ * sp+0        address of ImageLoader cache
+ */
+    .text
+    .align 4,0x90
+    .globl dyld_stub_binder
+    .globl _misaligned_stack_error
+dyld_stub_binder:
+       subl            $STACK_SIZE,%esp            # makes stack 16-byte aligned
+       movl            %eax,EAX_SAVE(%esp)     
+       movl            LP_OLD_BP_SAVE(%esp),%eax   # get lazy-pointer meta-parameter
+       movl            %eax,LP_LOCAL(%esp)     
+       movl            %ebp,LP_OLD_BP_SAVE(%esp)   # store epb back chain
+       movl            %esp,%ebp                   # set epb to be this frame
+       add             $LP_OLD_BP_SAVE,%ebp
+       movl            %ecx,ECX_SAVE(%esp)
+       movl            %edx,EDX_SAVE(%esp)
+       .align 0,0x90
+_misaligned_stack_error_:
+       movdqa          %xmm0,XMMM0_SAVE(%esp)
+       movdqa          %xmm1,XMMM1_SAVE(%esp)
+       movdqa          %xmm2,XMMM2_SAVE(%esp)
+       movdqa          %xmm3,XMMM3_SAVE(%esp)
+dyld_stub_binder_:
+       movl            MH_LOCAL(%esp),%eax     # call dyld::fastBindLazySymbol(loadercache, lazyinfo)
+       movl            %eax,MH_PARAM_OUT(%esp)
+       movl            LP_LOCAL(%esp),%eax
+       movl            %eax,LP_PARAM_OUT(%esp)
+       call            __Z21_dyld_fast_stub_entryPvl
+       movdqa          XMMM0_SAVE(%esp),%xmm0  # restore registers
+       movdqa          XMMM1_SAVE(%esp),%xmm1
+       movdqa          XMMM2_SAVE(%esp),%xmm2
+       movdqa          XMMM3_SAVE(%esp),%xmm3
+       movl            ECX_SAVE(%esp),%ecx
+       movl            EDX_SAVE(%esp),%edx
+       movl            %eax,%ebp               # move target address to epb
+       movl            EAX_SAVE(%esp),%eax     # restore eax
+       addl            $STACK_SIZE+4,%esp      # cut back stack
+       xchg            %ebp, (%esp)            # restore ebp and set target to top of stack
+       ret                                     # jump to target
+    
+
+#endif /* __i386__ */
+
+
+#if __x86_64__
+
+#define MH_PARAM_BP                    8
+#define LP_PARAM_BP                    16
+
+#define RDI_SAVE                       0
+#define RSI_SAVE                       8
+#define RDX_SAVE                       16
+#define RCX_SAVE                       24
+#define R8_SAVE                                32
+#define R9_SAVE                                40
+#define RAX_SAVE                       48
+#define XMMM0_SAVE                     64    /* 16-byte align */
+#define XMMM1_SAVE                     80
+#define XMMM2_SAVE                     96
+#define XMMM3_SAVE                     112
+#define XMMM4_SAVE                     128
+#define XMMM5_SAVE                     144
+#define XMMM6_SAVE                     160
+#define XMMM7_SAVE                     176
+#define STACK_SIZE                     192 /*  (XMMM7_SAVE+16) must be 16 byte aligned too */
+    
+
+ /*    
+ * sp+4        lazy binding info offset
+ * sp+0        address of ImageLoader cache
+ */
+    .align 2,0x90
+    .globl dyld_stub_binder
+dyld_stub_binder:
+       pushq           %rbp
+       movq            %rsp,%rbp
+       subq            $STACK_SIZE,%rsp        # at this point stack is 16-byte aligned because two meta-parameters where pushed
+       movq            %rdi,RDI_SAVE(%rsp)     # save registers that might be used as parameters
+       movq            %rsi,RSI_SAVE(%rsp)
+       movq            %rdx,RDX_SAVE(%rsp)
+       movq            %rcx,RCX_SAVE(%rsp)
+       movq            %r8,R8_SAVE(%rsp)
+       movq            %r9,R9_SAVE(%rsp)
+       movq            %rax,RAX_SAVE(%rsp)
+       movdqa          %xmm0,XMMM0_SAVE(%rsp)
+       movdqa          %xmm1,XMMM1_SAVE(%rsp)
+       movdqa          %xmm2,XMMM2_SAVE(%rsp)
+       movdqa          %xmm3,XMMM3_SAVE(%rsp)
+       movdqa          %xmm4,XMMM4_SAVE(%rsp)
+       movdqa          %xmm5,XMMM5_SAVE(%rsp)
+       movdqa          %xmm6,XMMM6_SAVE(%rsp)
+       movdqa          %xmm7,XMMM7_SAVE(%rsp)
+       movq            MH_PARAM_BP(%rbp),%rdi  # call fastBindLazySymbol(loadercache, lazyinfo)
+       movq            LP_PARAM_BP(%rbp),%rsi
+       call            __Z21_dyld_fast_stub_entryPvl
+       movq            %rax,%r11               # save target
+       movdqa          XMMM0_SAVE(%rsp),%xmm0  # restore registers
+       movdqa          XMMM1_SAVE(%rsp),%xmm1
+       movdqa          XMMM2_SAVE(%rsp),%xmm2
+       movdqa          XMMM3_SAVE(%rsp),%xmm3
+       movdqa          XMMM4_SAVE(%rsp),%xmm4
+       movdqa          XMMM5_SAVE(%rsp),%xmm5
+       movdqa          XMMM6_SAVE(%rsp),%xmm6
+       movdqa          XMMM7_SAVE(%rsp),%xmm7
+       movq            RDI_SAVE(%rsp),%rdi
+       movq            RSI_SAVE(%rsp),%rsi
+       movq            RDX_SAVE(%rsp),%rdx
+       movq            RCX_SAVE(%rsp),%rcx
+       movq            R8_SAVE(%rsp),%r8
+       movq            R9_SAVE(%rsp),%r9
+       movq            RAX_SAVE(%rsp),%rax
+       addq            $STACK_SIZE,%rsp
+       popq            %rbp
+       addq            $16,%rsp                # remove meta-parameters
+       jmp             *%r11                   # jmp to target
+
+#endif
+
+
+
index cce096368f7bf2556d6505dee3c7e937c5ea7f7a..399ad2497f6c424a541e61e194ac3a5cacf946c3 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+// from _simple.h in libc
+typedef struct _SIMPLE*        _SIMPLE_STRING;
+extern void                            _simple_vdprintf(int __fd, const char *__fmt, va_list __ap);
+extern void                            _simple_dprintf(int __fd, const char *__fmt, ...);
+extern _SIMPLE_STRING  _simple_salloc(void);
+extern int                             _simple_vsprintf(_SIMPLE_STRING __b, const char *__fmt, va_list __ap);
+extern void                            _simple_sfree(_SIMPLE_STRING __b);
+extern char *                  _simple_string(_SIMPLE_STRING __b);
+
+// dyld::log(const char* format, ...)
+extern void _ZN4dyld3logEPKcz(const char*, ...);
+
+// dyld::halt(const char* msg);
+extern void _ZN4dyld4haltEPKc(const char* msg) __attribute__((noreturn));
+
 
 // abort called by C++ unwinding code
 void abort()
-{
-       _exit(1);
+{      
+       _ZN4dyld4haltEPKc("dyld calling abort()\n");
 }
 
 // std::terminate called by C++ unwinding code
 void _ZSt9terminatev()
 {
-       _exit(1);
+       _ZN4dyld4haltEPKc("dyld std::terminate()\n");
 }
 
 // std::unexpected called by C++ unwinding code
 void _ZSt10unexpectedv()
 {
-       _exit(1);
+       _ZN4dyld4haltEPKc("dyld std::unexpected()\n");
 }
 
 // __cxxabiv1::__terminate(void (*)()) called to terminate process
 void _ZN10__cxxabiv111__terminateEPFvvE()
 {
-       _exit(1);
+       _ZN4dyld4haltEPKc("dyld std::__terminate()\n");
 }
 
 // __cxxabiv1::__unexpected(void (*)()) called to terminate process
 void _ZN10__cxxabiv112__unexpectedEPFvvE()
 {
-       _exit(1);
+       _ZN4dyld4haltEPKc("dyld std::__unexpected()\n");
 }
 
 // __cxxabiv1::__terminate_handler
@@ -65,7 +82,52 @@ void* _ZN10__cxxabiv119__terminate_handlerE  = &_ZSt9terminatev;
 // __cxxabiv1::__unexpected_handler
 void* _ZN10__cxxabiv120__unexpected_handlerE = &_ZSt10unexpectedv;
 
+// libc uses assert()
+void __assert_rtn(const char* func, const char* file, int line, const char* failedexpr)
+{
+       if (func == NULL)
+               _ZN4dyld3logEPKcz("Assertion failed: (%s), file %s, line %d.\n", failedexpr, file, line);
+       else
+               _ZN4dyld3logEPKcz("Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr, func, file, line);
+       abort();
+}
+
+
+// called by libuwind code before aborting
+size_t fwrite(const void* ptr, size_t size, size_t nitme, FILE* stream)
+{
+       return fprintf(stream, "%s", (char*)ptr); 
+}
+
+// called by libuwind code before aborting
+int    fprintf(FILE* file, const char* format, ...)
+{
+       va_list list;
+       va_start(list, format);
+       _simple_vdprintf(STDERR_FILENO, format, list);
+       va_end(list);
+       return 0;
+}
 
+// called by LIBC_ABORT
+void abort_report_np(const char* format, ...)
+{
+       va_list list;
+       const char *str;
+       _SIMPLE_STRING s = _simple_salloc();
+       if ( s != NULL ) {
+               va_start(list, format);
+               _simple_vsprintf(s, format, list);
+               va_end(list);
+               str = _simple_string(s);
+       } 
+       else {
+               // _simple_salloc failed, but at least format may have useful info by itself
+               str = format; 
+       }
+       _ZN4dyld4haltEPKc(str);
+       // _ZN4dyld4haltEPKc doesn't return, so we can't call _simple_sfree
+}
 
 
 // real cthread_set_errno_self() has error handling that pulls in 
@@ -87,3 +149,23 @@ struct tm* localtime(const time_t* t)
 }
 
 
+//
+// 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)
+{
+#if __LP64__
+       __stack_chk_guard = ((long)arc4random() << 32) | arc4random();
+#else
+       __stack_chk_guard = arc4random();
+#endif
+}
+extern void _ZN4dyld4haltEPKc(const char*);
+void __stack_chk_fail()
+{
+       _ZN4dyld4haltEPKc("stack buffer overrun");
+}
+
+
diff --git a/src/strip.exp b/src/strip.exp
deleted file mode 100644 (file)
index 8a2f778..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-
-# local symbols to suppress
-*PE*
-*Win*
index 331a5cd6fabc6656f06c0db625d8f80d4bb627be..aec491f6f4486a4c8aad2e27afed330ce1871689 100644 (file)
@@ -245,6 +245,40 @@ _stub_binding_helper_interface:
 
 #endif /* __ppc__ */
 
+#if __arm__
+/*
+ * This is the interface for the stub_binding_helper for ARM:
+ * The caller has pushed the address of the a lazy pointer to be filled in with
+ * the value for the defined symbol and pushed the address of the the mach
+ * header this pointer comes from.
+ *
+ * sp+4        address of lazy pointer
+ * sp+0        address of mach header
+ * 
+ * After the symbol has been resolved and the pointer filled in this is to pop
+ * these arguments off the stack and jump to the address of the defined symbol.
+ */
+  
+       .text
+       .align 2
+       .globl  _stub_binding_helper_interface
+_stub_binding_helper_interface:
+       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 of mach header to 1st parameter
+       ldr     r1, [sp, #28]                   // move address of lazy pointer to 2nd parameter
+
+       // call dyld::bindLazySymbol(mh, lazy_symbol_pointer_address)
+       bl      __ZN4dyld14bindLazySymbolEPK11mach_headerPm
+       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 c980711a25d32930efed7b2367f7ea35c518c191..a44135022ed41a585c88ef7b62ccf33b2ffa6daa 100755 (executable)
@@ -91,6 +91,7 @@ sub find_callback
        open(STDOUT, ">/tmp/unit-tests-stdout") || die("$!");
        open(STDERR, ">/tmp/unit-tests-stderr") || die("$!");
 
+       $ENV{UNIT_TEST_NAME} = $reldir;
        my $exit = system(@$cmd);
 
        close(STDOUT) || die("$!");
diff --git a/unit-tests/bin/pass-iff-exit-zero.pl b/unit-tests/bin/pass-iff-exit-zero.pl
new file mode 100755 (executable)
index 0000000..07854b5
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/perl -w
+
+#
+# Usage:
+#
+#              ${PASS_IFF} command
+#
+
+use strict;
+
+my $test_name = "";
+if ( exists $ENV{UNIT_TEST_NAME} ) {
+       $test_name = $ENV{UNIT_TEST_NAME};
+}
+
+if(0 != system(@ARGV))
+{
+    printf("FAIL $test_name\n");
+    exit 1;
+}
+
+printf("PASS $test_name\n");
+exit 0;
index 243fc2d0fc314ad2e7ecdd052b7986b77d9f16bc..f94abba7dca7e28b2971aa2f0d9049d119cb7e43 100644 (file)
@@ -6,15 +6,17 @@ SHELL = /bin/sh
 ARCH ?= $(shell arch)
 
 # set default to be all
-VALID_ARCHS ?= "ppc ppc64 i386 x86_64"
+VALID_ARCHS ?= "ppc i386 x86_64"
 
-CC              = gcc-4.0 -arch ${ARCH}
+CC              = gcc-4.2 -arch ${ARCH}
 CCFLAGS = -Wall -std=c99
 
-CXX              = g++-4.0 -arch ${ARCH}
+CXX              = g++-4.2 -arch ${ARCH}
 CXXFLAGS = -Wall 
 
 RM      = rm
 RMFLAGS = -rf
 
 SAFE_RUN       = ${TESTROOT}/bin/fail-if-non-zero.pl
+PASS_IFF       = ${TESTROOT}/bin/pass-iff-exit-zero.pl
+
index 0cfeb450b962c73f2080d0bc9ee0c0051a4d03f1..45f846fb8467e5061aac52ee8dbac5e961e776c5 100755 (executable)
@@ -32,15 +32,18 @@ fi
 # if Intel, then also run all test cases under emulation
 if [ "`sysctl -n hw.machine`" = "i386" ] 
 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
+       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
 
        # if 64-bit capable Intel, then also run all test cases for 64-bits
        if [ `sysctl -n hw.optional.x86_64` = "1" ] 
index 49c689a9488128d23c1d3ea42ce451f2699a355d..2a47c2b97120c105471d01509ea0daec512afc3a 100644 (file)
@@ -23,8 +23,7 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
-       ./main
+all-check: all check
 
 all: main
 
@@ -37,5 +36,8 @@ libfoo.dylib : foo.c libbar.dylib
 libbar.dylib : bar.c
        ${CC}  -I${TESTROOT}/include -dynamiclib bar.c -o libbar.dylib -install_name /usr/local/hide/libbar.dylib
 
+check:
+       ./main
+
 clean:
        ${RM} ${RMFLAGS} *~  main libbar.dylib libfoo.dylib
index 7d4b9f1832b172e1eb0d87d82449ecb3f3b60722..72b6a437f9181b94c29662fb93573601e2a2b609 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main
index f46b18eff8931225cd6027717f9de512c86fc9ed..c31f202536dc5ddf66ee08c87c4753c16b9be4fd 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        export DYLD_FALLBACK_LIBRARY_PATH="hide" && ./main
 
 all: main hide/libzzz.dylib
diff --git a/unit-tests/test-cases/NSAddressOfSymbol-NULL/Makefile b/unit-tests/test-cases/NSAddressOfSymbol-NULL/Makefile
new file mode 100644 (file)
index 0000000..1590fdc
--- /dev/null
@@ -0,0 +1,19 @@
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+all-check: all check
+
+check:
+       ./main
+
+all: main 
+
+main : main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c -Wno-deprecated-declarations
+
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main
+
diff --git a/unit-tests/test-cases/NSAddressOfSymbol-NULL/main.c b/unit-tests/test-cases/NSAddressOfSymbol-NULL/main.c
new file mode 100644 (file)
index 0000000..9ac5211
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2008 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 <string.h>
+
+#include <mach-o/dyld.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+
+int main()
+{
+       NSAddressOfSymbol(NULL);
+       
+       PASS("NSAddressOfSymbol-NULL");
+       return 0;
+}
diff --git a/unit-tests/test-cases/addend/Makefile b/unit-tests/test-cases/addend/Makefile
new file mode 100644 (file)
index 0000000..db2bdbf
--- /dev/null
@@ -0,0 +1,23 @@
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# verify addends work
+#
+
+all-check: all check
+
+check:
+       ./main 
+        
+all: main
+
+main : main.c libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include libfoo.dylib -o main main.c
+
+libfoo.dylib : foo.c
+       ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib 
+
+clean:
+       ${RM} ${RMFLAGS} *~ main  libfoo.dylib
+
diff --git a/unit-tests/test-cases/addend/foo.c b/unit-tests/test-cases/addend/foo.c
new file mode 100644 (file)
index 0000000..efdd301
--- /dev/null
@@ -0,0 +1,7 @@
+
+
+const char a = 10;
+const char b = 11;
+const char c = 12;
+const char d = 13;
+const char e = 14;
diff --git a/unit-tests/test-cases/addend/main.c b/unit-tests/test-cases/addend/main.c
new file mode 100644 (file)
index 0000000..fd8099b
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2008 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 const char a;
+extern const char b;
+extern const char c;
+extern const char d;
+extern const char e;
+
+
+const char* pc   = &c;
+const char* pd_2 = &d - 2;
+const char* pb2  = &b + 2;
+
+
+int main()
+{
+       if (*pc != 12 ) {
+               FAIL("addend: *pc != 12");
+               return 0;
+       }
+       
+       if (*pd_2 != 11 ) {
+               FAIL("addend: *pd_2 != 11");
+               return 0;
+       }
+       
+       if (*pb2 != 13 ) {
+               FAIL("addend: *pb2 != 13");
+               return 0;
+       }
+       
+       PASS("addend");
+}
diff --git a/unit-tests/test-cases/all_image_infos/Makefile b/unit-tests/test-cases/all_image_infos/Makefile
new file mode 100644 (file)
index 0000000..b625c20
--- /dev/null
@@ -0,0 +1,38 @@
+##
+# Copyright (c) 2005-2008 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} foo.c -dynamiclib -o libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libfoo.dylib
+
+clean:
+       ${RM} ${RMFLAGS} main libfoo.dylib
diff --git a/unit-tests/test-cases/all_image_infos/foo.c b/unit-tests/test-cases/all_image_infos/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/all_image_infos/main.c b/unit-tests/test-cases/all_image_infos/main.c
new file mode 100644 (file)
index 0000000..30a8427
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2008 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 <mach-o/dyld.h>
+#include <mach-o/dyld_images.h>
+#include <mach/mach.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()
+{
+       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* infos = getImageInfos();
+       if ( infos->version != 7 ) {
+               FAIL("all_image_infos: dyld_all_image_infos is not version 7");
+               exit(0);
+       }
+
+       if ( infos->infoArrayCount < 2 ) {
+               FAIL("all_image_infos: dyld_all_image_infos.infoArrayCount is  < 2");
+               exit(0);
+       }
+
+       if ( infos->infoArray[0].imageLoadAddress != &__dso_handle ) {
+               FAIL("all_image_infos: dyld_all_image_infos.infoArray for main executable is wrong");
+               exit(0);
+       }
+
+       if ( getImageInfosFromKernel() != infos ) {
+               FAIL("all_image_infos: task_info and dyld disagree");
+               exit(0);
+       }
+
+       PASS("all_image_infos");
+       return EXIT_SUCCESS;
+}
+
+
diff --git a/unit-tests/test-cases/always-libSystem/Makefile b/unit-tests/test-cases/always-libSystem/Makefile
new file mode 100644 (file)
index 0000000..80ee137
--- /dev/null
@@ -0,0 +1,42 @@
+##
+# 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
+       export DYLD_SHARED_REGION=avoid && ./main
+
+all: main
+
+
+main: main.c 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c -mmacosx-version-min=10.5
+
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main  
+       
diff --git a/unit-tests/test-cases/always-libSystem/main.c b/unit-tests/test-cases/always-libSystem/main.c
new file mode 100644 (file)
index 0000000..5626783
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <mach-o/dyld.h>
+#include <string.h>
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+//
+//  <rdar://problem/6563887> app crashes when libSystem cannot be found
+//
+
+int main() 
+{
+       // see if libSystem is in list of images
+       uint32_t count = _dyld_image_count();
+       for(uint32_t i=0; i < count; ++i) {
+               const char*  name = _dyld_get_image_name(i);
+               if ( strstr(name, "/libSystem.") != NULL ) {
+                       PASS("always-libSystem");
+                       return 0;
+               }
+       }
+
+       FAIL("always-libSystem");
+       return 0;
+}
+
index 0fe015bee634ff2159be8b6b5a63f4cd5e98284a..d9682392981ecbbe5ebe5e441f1565ef103bf90e 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main
@@ -32,7 +34,7 @@ all: main
 ### The point of this test is to check an edge case for i386 architecture
 ### with "fast stubs".  We want to verify that a fast stub that ends
 ### near the page boundary for the __IMPORT segment does not cause an
-### accidental read beyou the __IMPORT segment
+### accidental read beyond the __IMPORT segment
 ###  rdar://problem/4653725 
 ###
 
@@ -43,13 +45,13 @@ libtest1.dylib: pointers.c funcs.c libfoo.dylib
        ${CC} ${CCFLAGS}  -dynamiclib pointers.c funcs.c -DCASE=1 -o libtest1.dylib libfoo.dylib
 
 libtest2.dylib: pointers.c funcs.c libfoo.dylib
-       ${CC} ${CCFLAGS}  -dynamiclib pointers.c funcs.c -DCASE=2  -o libtest2.dylib libfoo.dylib
+       ${CC} ${CCFLAGS}  -dynamiclib pointers.c funcs.c -DCASE=2 -o libtest2.dylib libfoo.dylib 
 
 libtest3.dylib: pointers.c funcs.c libfoo.dylib
-       ${CC} ${CCFLAGS}  -dynamiclib pointers.c funcs.c -DCASE=3  -o libtest3.dylib libfoo.dylib
+       ${CC} ${CCFLAGS}  -dynamiclib pointers.c funcs.c -DCASE=3 -o libtest3.dylib libfoo.dylib 
 
 libtest4.dylib: pointers.c funcs.c libfoo.dylib
-       ${CC} ${CCFLAGS}  -dynamiclib pointers.c funcs.c -DCASE=4  -o libtest4.dylib libfoo.dylib
+       ${CC} ${CCFLAGS}  -dynamiclib pointers.c funcs.c -DCASE=4 -o libtest4.dylib libfoo.dylib 
 
 libfoo.dylib: foo.c 
        ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib
index 16c40a2b1f5723fdb0699b7f357b1a248b830b2c..64cd71a19844977d4c09e8d6ac75dc659ec50299 100644 (file)
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
-
+#include <mach/mach_time.h>
+#include <stdio.h>
 #include "foo.h"
 
 static void __attribute__((constructor)) myinit()
 {
+//     uint64_t t1 = mach_absolute_time();
        foo002();
        foo003();
        foo004();
@@ -849,5 +851,9 @@ static void __attribute__((constructor)) myinit()
 #if CASE <= 1
        foo817();
 #endif
+
+//     uint64_t t2 = mach_absolute_time();
+//     fprintf(stderr, "total time = %lld\n", t2-t1);
+
 }
 
index cc85b8598eb5c1f3631b61f65ee9fb18606c914a..b6f9489a6cf9346e3d9c9db7a80857106fc3c4d4 100644 (file)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2006-2008 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+# rosetta does not support very large stack sizes
+STACK_SIZE = 0x83000000
+ifeq "ppc" "$(ARCH)"
+       MACHINE =  $(shell arch)
+       ifeq "i386" "$(MACHINE)"
+               STACK_SIZE = 0x02100000
+       endif
+endif
+
+
+ifeq "armv6" "$(ARCH)"
+       STACK_SIZE = 0x20000000
+endif
+
+
+all-check: all check
+
+check:
        ${TESTROOT}/bin/exit-zero-pass.pl "big stack" "big stack failed" ./main
 
 all:
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c -Wl,-w -Wl,-stack_size -Wl,0x83000000
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c -Wl,-w -Wl,-stack_size -Wl,${STACK_SIZE} -DSTACK_SIZE=${STACK_SIZE}
 
 clean:
        ${RM} ${RMFLAGS} main
index dc1339a9973d1059206a17df2c4a2f5d9cac2e22..003881fe91f20f90e7ce51735387a60678415312 100644 (file)
@@ -31,6 +31,7 @@
 // This builds an executable that needs > 2GB of stack
 //
 
+
 char* keepAlive;       // to keep compiler from optimizing away stack variable
 
 // keep recursing until desired stack size achieved
@@ -38,7 +39,10 @@ void foo(unsigned long long stackSize, char* stackStart)
 {
        char buffer[32*1024*1024];
        keepAlive = buffer;
-       if ( (stackStart - buffer) > stackSize )
+       // only recursive if there is enough room for next buffer
+       intptr_t freeStackSpace = (buffer - sizeof(buffer)) - (stackStart - stackSize);
+       //fprintf(stderr, "&buffer=%p, stackStart=%p, freeStackSpace=0x%lx\n", buffer, stackStart, freeStackSpace); 
+       if ( freeStackSpace < sizeof(buffer) )
                return;
        else
                foo(stackSize, stackStart);
@@ -69,7 +73,7 @@ main()
                foo(0x02000000, &start);        
        else
 #endif 
-               foo(0x81000000, &start);        // 2.1 GB stack
+               foo(STACK_SIZE, &start);        
        return EXIT_SUCCESS;
 }
 
index d2c407c28dccf919861a055a32ffaf7049b58b01..c05f64e142c58a9ddd8ef7743443b21732df63ad 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main test.bundle
index 6728b7a6937e54e72da91a9762d51ddbcfac1a25..5f4f05fde16aa3b8d6fd7e65775e228283e9de8a 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main
index 4b3865db66fa6a0fa359e56b6d525d5cde060e36..a6b0db5530efb692cf0d9dbae89b60324f17672f 100644 (file)
@@ -31,7 +31,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main test.bundle
index 7c573149cfa0389872392ef9131227e14cb54722..687eea699d8a9073c8862adc9cce9e5e576322a7 100644 (file)
@@ -25,7 +25,9 @@ include ${TESTROOT}/include/common.makefile
 
 FATFLAGS = `lipo -detailed_info /usr/lib/libSystem.B.dylib | grep architecture | sed -e 's/architecture/-arch/'`
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main test.bundle
diff --git a/unit-tests/test-cases/bundle-memory-load-malloc/Makefile b/unit-tests/test-cases/bundle-memory-load-malloc/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-malloc/bundle.c b/unit-tests/test-cases/bundle-memory-load-malloc/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-malloc/main.c b/unit-tests/test-cases/bundle-memory-load-malloc/main.c
new file mode 100644 (file)
index 0000000..d00fbde
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+#include <stdbool.h>
+#include <mach-o/dyld.h>
+#include <sys/types.h>
+#include <sys/stat.h> 
+#include <sys/mman.h> 
+#include <unistd.h>
+#include <fcntl.h>
+#include <malloc/malloc.h>
+#include <stdlib.h>
+
+
+#include "test.h" // PASS(), FAIL()
+
+typedef bool (*CheckFunc)();
+
+int main()
+{
+       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 1;
+       }
+
+       void* loadAddress = malloc((stat_buf.st_size+4095) & (-4096));
+       if ( loadAddress == NULL ) {
+               FAIL("malloc failed");
+               return 1;
+       }
+       
+       if ( pread(fd, loadAddress, stat_buf.st_size, 0) != stat_buf.st_size ) {
+               FAIL("pread() failed");
+               return 1;
+       }
+
+       //void* loadAddress2 = mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
+       close(fd);
+
+       NSObjectFileImage ofi;
+       if ( NSCreateObjectFileImageFromMemory(loadAddress, stat_buf.st_size, &ofi) != NSObjectFileImageSuccess ) {
+               FAIL("NSCreateObjectFileImageFromMemory failed");
+               return 1;
+       }
+       
+       NSModule mod = NSLinkModule(ofi, "he_he", NSLINKMODULE_OPTION_NONE);
+       if ( mod == NULL ) {
+               FAIL("NSLinkModule failed");
+               return 1;
+       }
+       
+       NSSymbol sym = NSLookupSymbolInModule(mod, "_checkdata");
+       if ( sym == NULL ) {
+               FAIL("NSLookupSymbolInModule failed");
+               return 1;
+       }
+
+       CheckFunc func = NSAddressOfSymbol(sym);
+       if ( !func() ) {
+               FAIL("NSAddressOfSymbol failed");
+               return 1;
+       }
+
+       if ( !NSUnLinkModule(mod, NSUNLINKMODULE_OPTION_NONE) ) {
+               FAIL("NSUnLinkModule failed");
+               return 1;
+       }
+
+       if ( !NSDestroyObjectFileImage(ofi) ) {
+               FAIL("NSDestroyObjectFileImage failed");
+               return 1;
+       }
+       //fprintf(stderr, "loadAddress=%p\n", loadAddress);
+       //fprintf(stderr, "malloc_size(loadAddress) => 0x%08X\n", malloc_size(loadAddress));
+       //fprintf(stderr, "loadAddress2=%p\n", loadAddress2);
+       //fprintf(stderr, "malloc_size(loadAddress2) => 0x%08X\n", malloc_size(loadAddress2));
+       
+       
+       //free(loadAddress);
+       //fprintf(stderr, "malloc_size(loadAddress) => 0x%08X\n", malloc_size(loadAddress));
+       if ( malloc_size(loadAddress) != 0 ) {
+               FAIL("malloc_size(loadAddress) => 0x%08X", malloc_size(loadAddress));
+               FAIL("malloc still thinks it owns this block");
+               return 1;
+       }
+       
+       
+       
+       // Should check that loadAddress is unmmaped now (by call to NSDestroyObjectFileImage)
+
+       PASS("bundle-memory-load-malloc");
+       return 0;
+}
\ No newline at end of file
index a44aecad6f09d29aa2e0470a295c6561b0ce99b5..0a4e679117ac68da6b53bcce547c3cf059737d47 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main test.bundle
index c044f7f0bebba115492e1ca00a2bfa0f56641def..02b7dca5dc0ecc3b47f37bcf1e2f0ccfedf2e75b 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main test.bundle
index c044f7f0bebba115492e1ca00a2bfa0f56641def..02b7dca5dc0ecc3b47f37bcf1e2f0ccfedf2e75b 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main test.bundle
index f2d2d0a7a8358a467f3d8c4d2454cd980a549cdc..d5b047f088e8334a3beb9ec4c9eac56f36a506d1 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main test.bundle
index 29d5d415e459ed5600d5bd141a139151a784036f..72ca40362b287c463feaaea9ee8ecbbed1b6a842 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main test.bundle
index 97eb0d5ca5b05c1dfd11eb4bfc0df779bc11ca18..723c2c65fbaf2125bb7a7f98877415c85eda29a0 100644 (file)
@@ -29,7 +29,9 @@ else
        CXX_VERSION = ${CXX} 
 endif
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main test.bundle
index bb9c30d350cf5ac5d748f054ae0e650c1f5c9979..b872e6ca1e23f9fbbc3d25c6590d267857d7b7f0 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main test.bundle
index f2d2d0a7a8358a467f3d8c4d2454cd980a549cdc..d5b047f088e8334a3beb9ec4c9eac56f36a506d1 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main test.bundle
index 952c3a5b3963fb66076db76ecdabbc0e9aa04346..e70688302359e1a0d6e20007f83d1bdca32d7eb7 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main 
index 3cf265b0d5260034a488e8b56060d76a8dfe8d63..7cdc1709211451f7551cb2c951892ccb008e1ca7 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main test.bundle
index 2de9a58be998ea13e22e6ab302f28abfaab84fdd..814c4064dc6e187d9a2b61a4c2ef7bb343e7a223 100644 (file)
@@ -33,7 +33,7 @@ int main()
 {
        void* handle = dlopen("test.bundle", RTLD_LAZY);
        if ( handle == NULL ) {
-               FAIL("dlopen(\test.bundle\") failed");
+               FAIL("dlopen(\"test.bundle\") failed: %s", dlerror());
                return 0;
        }
        
index 0905421642d725ef245e29e0dd8626f8d16cfddd..893e25bca74b9a946acb88bbd3586d3a4e3af8d2 100644 (file)
@@ -27,7 +27,9 @@ include ${TESTROOT}/include/common.makefile
 # verify that apple[0] parameter is correct by comparing to argv[1]
 #
 
-run: all
+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
index 9df7f9bb912e91443eb4511c0596196d311a7a6a..9d8dd599fa30983017aac9bf7f44c19a503df72a 100644 (file)
@@ -27,7 +27,9 @@ include ${TESTROOT}/include/common.makefile
 # verifies that crt glue can handle  argv[0] = NULL
 #
 
-run: all
+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
 
index d07ac32e3cd11f58448eadb5fff06d4887d7c856..491d480726183b277c9295f5a4d8c1b9d2347af0 100644 (file)
@@ -28,7 +28,9 @@ include ${TESTROOT}/include/common.makefile
 # have the entry point called before initializers are run
 #
 
-run: all
+all-check: all check
+
+check:
        ./main-10.4
        ./main-10.5
 
index 8d8b832249894d1ddfd0c883cb27114292dc8f54..6f30df5137be587b2633e322ba6e07db66ffca7b 100644 (file)
@@ -28,13 +28,17 @@ include ${TESTROOT}/include/common.makefile
 # the mechanism for 10.4 and 10.5 is different 
 #
 
-run: all
+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.4.stripped main-10.5.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
@@ -48,7 +52,13 @@ main-10.5: main.c
 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-10.6.stripped: main-10.6
+       strip main-10.6 -o main-10.6.stripped
+
 clean:
-       ${RM} ${RMFLAGS} *~ main-10.4 main-10.5 main-10.4.stripped main-10.5.stripped
+       ${RM} ${RMFLAGS} *~ main-10.4 main-10.5 main-10.6 main-10.4.stripped main-10.5.stripped main-10.6.stripped
  
 
index 8e7cbf380853aed15db94291d6a889d101a56d06..0e4bd7b46628703c8da7fe1b8f4042dfdecbb115 100644 (file)
@@ -28,7 +28,9 @@ include ${TESTROOT}/include/common.makefile
 # for both crt1.0 and crt1.10.5.o
 #
 
-run: all
+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
diff --git a/unit-tests/test-cases/cxa_finalize/Makefile b/unit-tests/test-cases/cxa_finalize/Makefile
new file mode 100644 (file)
index 0000000..44b4c0c
--- /dev/null
@@ -0,0 +1,44 @@
+##
+# 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 libfoo.dylib
+
+main : main.c 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+
+
+libfoo.dylib : foo.cxx
+       ${CXX} ${CXXFLAGS} -dynamiclib foo.cxx -o libfoo.dylib
+
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libfoo.dylib
+
diff --git a/unit-tests/test-cases/cxa_finalize/foo.cxx b/unit-tests/test-cases/cxa_finalize/foo.cxx
new file mode 100644 (file)
index 0000000..0399be1
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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@
+ */
+
+
+class A
+{
+public:
+       A() { f = 10; }
+       ~A() { f = 0; }
+       int get() { return f; }
+private:
+       int f;  
+};
+
+A a;
+
+
+int test()
+{
+       return a.get();
+}
diff --git a/unit-tests/test-cases/cxa_finalize/main.c b/unit-tests/test-cases/cxa_finalize/main.c
new file mode 100644 (file)
index 0000000..d1b62d5
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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 <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+
+int main()
+{
+       void* handle = dlopen("libfoo.dylib", RTLD_LAZY);
+       if ( handle == NULL ) {
+               FAIL("dlopen(\"%s\") failed with: %s", "libfoo.dylib", dlerror());
+               return EXIT_SUCCESS;
+       }
+               
+       dlclose(handle);
+  
+       PASS("cxa_finalize");
+       return EXIT_SUCCESS;
+}
index c21045d23d5f99cd7923c439fa59507ce052eaab..c01b46dfa201be4a6c8511083e0b43a15befdef3 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main 
diff --git a/unit-tests/test-cases/dladdr-stripped/Makefile b/unit-tests/test-cases/dladdr-stripped/Makefile
new file mode 100644 (file)
index 0000000..a3ac2a4
--- /dev/null
@@ -0,0 +1,38 @@
+##
+# Copyright (c) 2009 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+all-check: all check
+
+check:
+       ./main
+
+all:
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c 
+       strip main
+       
+
+clean:
+       ${RM} ${RMFLAGS} *~ main 
+
diff --git a/unit-tests/test-cases/dladdr-stripped/main.c b/unit-tests/test-cases/dladdr-stripped/main.c
new file mode 100644 (file)
index 0000000..4f8901a
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2009 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 <string.h> 
+#include <dlfcn.h> 
+#include <mach-o/dyld.h> 
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+///
+/// verify dladdr() returns NULL for a symbol name in a fully stripped 
+/// main executable (and not _mh_execute_header+nnn).
+///
+
+int main()
+{
+       Dl_info info;
+       if ( dladdr(&main, &info) == 0 ) {
+               FAIL("dladdr(&main, xx) failed");
+               exit(0);
+       }
+
+       if ( info.dli_sname != NULL ){
+               FAIL("dladdr() returned: \"%s\" instead of NULL", info.dli_sname);
+               exit(0);
+       }
+  
+       PASS("dladdr-stripped");
+       return EXIT_SUCCESS;
+}
index fcb934dbda1536b39cc7298a9fb2b9dcd6badb07..3a6122055579a269893161b6ec0d669e243bfaed 100644 (file)
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all:
-       ${CC} ${CCFLAGS} -Wno-deprecated-declarations  -I${TESTROOT}/include -o main main.c
+       ${CC} ${CCFLAGS} -Wno-deprecated-declarations -g -I${TESTROOT}/include -o main main.c -mmacosx-version-min=10.5
+       
 
 clean:
-       ${RM} ${RMFLAGS} *~ main
+       ${RM} ${RMFLAGS} *~ main main.dSYM
 
index a57e7080772e237c037d4174a2530a35e9ce89ff..ab88475bafe8c684b9f605447580970c37c67209 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2008 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -40,7 +40,7 @@ static int foo()
        return 3;
 }
 
-int bar2()
+__attribute__((visibility("hidden"))) int hide()
 {
        return 4;
 }
@@ -72,7 +72,7 @@ static void verifybar()
        }
 }
 
-// checks local symbol (should resolve to previoius global symbol bar)
+// checks local symbol 
 static void verifyfoo()
 {
        Dl_info info;
@@ -80,21 +80,38 @@ static void verifyfoo()
                FAIL("dladdr(&foo, xx) failed");
                exit(0);
        }
-       if ( strcmp(info.dli_sname, "bar") != 0 ) {
-               if ( strcmp(info.dli_sname, "_bar") == 0 ) {
-                       XFAIL("dladdr()->dli_sname is \"%s\" instead of \"bar\"", info.dli_sname);
-               } 
-               else {
-                       FAIL("dladdr()->dli_sname is \"%s\" instead of \"bar\"", info.dli_sname);
-                       exit(0);
-               }
+       if ( strcmp(info.dli_sname, "foo") != 0 ) {
+               FAIL("dladdr()->dli_sname is \"%s\" instead of \"foo\"", info.dli_sname);
+               exit(0);
        }
-       if ( info.dli_saddr != &bar) {
-               FAIL("dladdr()->dli_saddr is not &bar");
+       if ( info.dli_saddr != &foo) {
+               FAIL("dladdr()->dli_saddr is not &foo");
                exit(0);
        }
-       if ( info.dli_fbase != _dyld_get_image_header_containing_address(&bar) ) {
-               FAIL("dladdr()->dli_fbase is not image that contains &bar");
+       if ( info.dli_fbase != _dyld_get_image_header_containing_address(&foo) ) {
+               FAIL("dladdr()->dli_fbase is not image that contains &foo");
+               exit(0);
+       }
+}
+
+// checks hidden symbol 
+static void verifyhide()
+{
+       Dl_info info;
+       if ( dladdr(&hide, &info) == 0 ) {
+               FAIL("dladdr(&hide, xx) failed");
+               exit(0);
+       }
+       if ( strcmp(info.dli_sname, "hide") != 0 ) {
+               FAIL("dladdr()->dli_sname is \"%s\" instead of \"hide\"", info.dli_sname);
+               exit(0);
+       }
+       if ( info.dli_saddr != &hide) {
+               FAIL("dladdr()->dli_saddr is not &hide");
+               exit(0);
+       }
+       if ( info.dli_fbase != _dyld_get_image_header_containing_address(&hide) ) {
+               FAIL("dladdr()->dli_fbase is not image that contains &hide");
                exit(0);
        }
 }
@@ -103,6 +120,7 @@ static void verifyfoo()
 int main()
 {
        verifybar();
+       verifyhide();
        verifyfoo();
 
   
index 73451f0caaea7d627517d8ffdd28886e57d28f7d..8aeb01408f15c114e5278fec6a874d71cbb104f0 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main 
index 84fc5b4449b04630f25a5d2a12e7db937b44ffa8..c3d1b06ada8dd58d742c387e17772a6ffa1c72ee 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main test.bundle
index 2597b532e2f00faae0fa5f460101e33c0634a11d..bba1b659540f4c3f2431ed7a508ecc216021d5c2 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main libfoo.dylib 
index 4f19e3f9bc9295d5ff5d675e65af2aaeb925e537..0c9b579e45361b3a14fa566ca4cb3f9dc81e6ccb 100644 (file)
@@ -27,7 +27,9 @@ include ${TESTROOT}/include/common.makefile
 # <rdar://problem/5366233> Leopard (9a499): dyld crash with recursive calls to dlclose()
 
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main libfoo.dylib 
index 8cce77ebf7553e7c415f63273e0c7b0f66c8cb03..35530b64c1fa4fc7143c4334b858cb0178422056 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main libfoo.dylib libbar.dylib
diff --git a/unit-tests/test-cases/dlclose-unmap/Makefile b/unit-tests/test-cases/dlclose-unmap/Makefile
new file mode 100644 (file)
index 0000000..5f24149
--- /dev/null
@@ -0,0 +1,47 @@
+##
+# Copyright (c) 2005-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 test.bundle test.dylib
+
+main : main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+
+
+test.bundle : foo.c
+       ${CC} ${CCFLAGS} -bundle foo.c -o test.bundle
+
+test.dylib : foo.c
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o test.dylib
+
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main test.bundle test.dylib
+
diff --git a/unit-tests/test-cases/dlclose-unmap/foo.c b/unit-tests/test-cases/dlclose-unmap/foo.c
new file mode 100644 (file)
index 0000000..8826cba
--- /dev/null
@@ -0,0 +1,2 @@
+
+void foo() {}
\ No newline at end of file
diff --git a/unit-tests/test-cases/dlclose-unmap/main.c b/unit-tests/test-cases/dlclose-unmap/main.c
new file mode 100644 (file)
index 0000000..a2c3cbf
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2005-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>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <string.h>
+#include <dlfcn.h>
+#include <mach/mach.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+///
+/// This tests that dlclose() actually unmmaps the image
+///
+
+static void trySO(const char* path)
+{      
+       void* handle = dlopen(path, RTLD_LAZY);
+       if ( handle == NULL ) {
+               const char* msg = dlerror();
+               FAIL("dlopen(\"%s\" RTLD_LAZY) failed but it should have worked: %s", path, msg);
+               exit(0);
+       }
+       void* sym = dlsym(handle, "foo");
+       if ( sym == NULL ) {
+               const char* msg = dlerror();
+               FAIL("dlsym(handle, \"foo\") failed but it should have worked: %s", msg);
+               exit(0);
+       }
+       
+       int result = dlclose(handle);
+       if ( result != 0 ) {
+               FAIL("dlclose(handle) returned %d", result);
+               exit(0);
+       }       
+       
+       // now try to create a page where foo() was
+       vm_address_t addr = ((uintptr_t)sym) & (-4096);
+       kern_return_t r = vm_allocate(mach_task_self(), &addr, 4096, VM_FLAGS_FIXED);
+       if ( r != KERN_SUCCESS )  {
+               FAIL("dlclose-unmap: could not allocate page where SO was previously mapped", result);
+               exit(0);
+       }
+}
+
+
+int main()
+{
+       trySO("test.bundle");
+       trySO("test.dylib");
+       
+       PASS("dlclose-unmap");
+       return 0;
+}
index 7337131483f6579deafa8695cd138f475e1c9665..48710233ff723d922fb6749b1a6f26e85cd791ac 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main 
index 7337131483f6579deafa8695cd138f475e1c9665..48710233ff723d922fb6749b1a6f26e85cd791ac 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main 
diff --git a/unit-tests/test-cases/dlopen-DYLD_FALLBACK_LIBRARY_PATH/Makefile b/unit-tests/test-cases/dlopen-DYLD_FALLBACK_LIBRARY_PATH/Makefile
new file mode 100644 (file)
index 0000000..30d9778
--- /dev/null
@@ -0,0 +1,31 @@
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+PWD = $(shell pwd)
+
+#
+# Test that DYLD_FALLBACK_LIBRARY_PATH does not apply to dlopen() of a full path
+# <rdar://problem/5951327> DYLD_FALLBACK_LIBRARY_PATH man page misleading
+#
+
+
+all-check: all check
+
+check:
+       export DYLD_FALLBACK_LIBRARY_PATH="${PWD}/hide" && ./main 
+
+all: main hide/libfoo.dylib
+
+main : main.c hide/libfoo.dylib 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c  
+
+
+hide/libfoo.dylib : foo.c
+       mkdir -p hide
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o "${PWD}/hide/libfoo.dylib" 
+
+
+
+clean:
+       ${RM} -rf  *~  main  hide 
+
diff --git a/unit-tests/test-cases/dlopen-DYLD_FALLBACK_LIBRARY_PATH/foo.c b/unit-tests/test-cases/dlopen-DYLD_FALLBACK_LIBRARY_PATH/foo.c
new file mode 100644 (file)
index 0000000..33c0685
--- /dev/null
@@ -0,0 +1,6 @@
+
+
+int foo()
+{
+       return 0;
+}
diff --git a/unit-tests/test-cases/dlopen-DYLD_FALLBACK_LIBRARY_PATH/main.c b/unit-tests/test-cases/dlopen-DYLD_FALLBACK_LIBRARY_PATH/main.c
new file mode 100644 (file)
index 0000000..d2ca85e
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2008 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 <dlfcn.h>
+#include <string.h>
+#include <stdlib.h> // for getenv()
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+
+int main(int argc, const char* argv[])
+{
+       void* handle = dlopen("/junk/path/libfoo.dylib", RTLD_LAZY);
+       if ( handle != NULL ) 
+               FAIL("dlopen-DYLD_FALLBACK_LIBRARY_PATH unexpected found dylib");
+       else
+               PASS("dlopen-DYLD_FALLBACK_LIBRARY_PATH");
+               
+       return EXIT_SUCCESS;
+}
index b20f99c5c5c717ee99dceab178fef6411cc437da..9ea36677af6d322ed183d06a184afccdf88ea776 100644 (file)
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
-       ./main "`pwd`/libfoo.dylib"
-       export DYLD_LIBRARY_PATH="`pwd`/alt" && ./main "`pwd`/libfoo.dylib"
+PWD = $(shell pwd)
+
+all-check: all check
+
+check:
+       ./main "${PWD}/libfoo.dylib"
+       export DYLD_LIBRARY_PATH="${PWD}/alt" && ./main "${PWD}/libfoo.dylib"
 
 all: main alt/libfoo.dylib
 
@@ -35,10 +39,10 @@ main : main.c libfoo.dylib
 
 alt/libfoo.dylib : foo.c
        mkdir -p alt
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o "`pwd`/alt/libfoo.dylib" -DALT 
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o "${PWD}/alt/libfoo.dylib" -DALT 
 
 libfoo.dylib : foo.c
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o "`pwd`/libfoo.dylib"
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o "${PWD}/libfoo.dylib"
 
 
 
index 6a3e391617ce41767ec5dfd2d100db8d05309124..dddef710e7172312ab8dd4c8af647bb0b7b4c446 100644 (file)
@@ -23,6 +23,7 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
+PWD = $(shell pwd)
 
 #
 # tests combinations of dlopen() and LD_LIBRARY_PATH
@@ -37,13 +38,15 @@ include ${TESTROOT}/include/common.makefile
 # 6) fullpath and LD_LIBRARY_PATH set to alt
 #
 
-run: all
+all-check: all check
+
+check:
        cd alt1 && ../main "libfoo.dylib" 1 "leafname found in cwd"
        ./main "./alt1/libfoo.dylib" 1 "relative path"
-       ./main "`pwd`/alt2/libfoo.dylib" 2 "fullpath"
-       export LD_LIBRARY_PATH="`pwd`/alt1" && ./main "libfoo.dylib" 1 "leafname and LD_LIBRARY_PATH overrides cwd"
-       export LD_LIBRARY_PATH="`pwd`/alt1" && cd alt3 && ../main "libfoo.dylib" 1 "leafname and alt LD_LIBRARY_PATH"
-       export LD_LIBRARY_PATH="`pwd`/alt1" && ./main "`pwd`/alt2/libfoo.dylib" 2 "fullpath and LD_LIBRARY_PATH"
+       ./main "${PWD}/alt2/libfoo.dylib" 2 "fullpath"
+       export LD_LIBRARY_PATH="${PWD}/alt1" && ./main "libfoo.dylib" 1 "leafname and LD_LIBRARY_PATH overrides cwd"
+       export LD_LIBRARY_PATH="${PWD}/alt1" && cd alt3 && ../main "libfoo.dylib" 1 "leafname and alt LD_LIBRARY_PATH"
+       export LD_LIBRARY_PATH="${PWD}/alt1" && ./main "${PWD}/alt2/libfoo.dylib" 2 "fullpath and LD_LIBRARY_PATH"
 
 all: main alt1/libfoo.dylib alt2/libfoo.dylib alt3
 
@@ -53,14 +56,14 @@ main : main.c libfoo.dylib
 
 alt1/libfoo.dylib : foo.c
        mkdir -p alt1
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o "`pwd`/alt1/libfoo.dylib" -DVALUE=1
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o "${PWD}/alt1/libfoo.dylib" -DVALUE=1
 
 alt2/libfoo.dylib : foo.c
        mkdir -p alt2
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o "`pwd`/alt2/libfoo.dylib" -DVALUE=2
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o "${PWD}/alt2/libfoo.dylib" -DVALUE=2
 
 libfoo.dylib : foo.c
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o "`pwd`/libfoo.dylib" -DVALUE=0
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o "${PWD}/libfoo.dylib" -DVALUE=0
 
 alt3 :
        mkdir -p alt3
index aee8633cf6fca22df93a8020e4858d9e6de1a9cc..6d7266a15d735f6e1d974b4c58befdd8cb1b9026 100644 (file)
@@ -25,7 +25,9 @@ include ${TESTROOT}/include/common.makefile
 
 PWD = `pwd`
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main 
index 170c483da64f34abde3022b1853dbdacf478faed..c1e199b00eb46481f3edce70c1149a7e4bc34d89 100644 (file)
@@ -25,7 +25,9 @@ include ${TESTROOT}/include/common.makefile
 
 PWD = `pwd`
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main 
index 260c1e04745c317ae6663e074bd712fd26e7ff4d..e6a5e5a1eb6db6d13ed3a70f7282cfb7e053d99b 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main foo.bundle bar.bundle
        ./main foo.dylib bar.bundle
 
index d7b6978df9b352bad94e0a4800767b60917ae7c3..823d5de5061a5cb088f8a9d2d8c3a3baf023a56d 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main 
 
 all: main 
diff --git a/unit-tests/test-cases/dlopen-RTLD_LOCAL-weak/Makefile b/unit-tests/test-cases/dlopen-RTLD_LOCAL-weak/Makefile
new file mode 100644 (file)
index 0000000..48bf4c4
--- /dev/null
@@ -0,0 +1,31 @@
+
+
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# verifes that RTLD_LOCAL suppresses weak symbol coalescing
+#
+
+
+
+all-check: all check
+
+check:
+       ./main 
+
+all: main libfoo.dylib libbar.dylib
+
+main : main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+
+libfoo.dylib : foo.c
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib
+
+libbar.dylib  : bar.c
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib 
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libfoo.dylib libbar.dylib
+
diff --git a/unit-tests/test-cases/dlopen-RTLD_LOCAL-weak/bar.c b/unit-tests/test-cases/dlopen-RTLD_LOCAL-weak/bar.c
new file mode 100644 (file)
index 0000000..b4ae377
--- /dev/null
@@ -0,0 +1,5 @@
+int __attribute__((weak)) A[] = { 1, 2, 3, 4 };
+
+
+int* getA() { return A; }
+
diff --git a/unit-tests/test-cases/dlopen-RTLD_LOCAL-weak/foo.c b/unit-tests/test-cases/dlopen-RTLD_LOCAL-weak/foo.c
new file mode 100644 (file)
index 0000000..c8ea49b
--- /dev/null
@@ -0,0 +1,5 @@
+
+
+int __attribute__((weak)) A[] = { 5, 6, 7, 8 };
+
+int* getA() { return A; }
diff --git a/unit-tests/test-cases/dlopen-RTLD_LOCAL-weak/main.c b/unit-tests/test-cases/dlopen-RTLD_LOCAL-weak/main.c
new file mode 100644 (file)
index 0000000..0340138
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2008 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 "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+// this strong A should not override weak
+// As in loaded code because of RTLD_LOCAL
+int A[] = { 10, 11, 12, 13 };
+
+typedef int* (*getproc)(void);
+
+int main(int argc, const char* argv[])
+{
+       // open first object 
+       void* fooHandle = dlopen("libfoo.dylib", RTLD_LOCAL);
+       if ( fooHandle == NULL ) {
+               FAIL("dlopen-RTLD_LOCAL-weak: dlopen(\"libfoo.dylib\", RTLD_LOCAL) failed: %s", dlerror());
+               return EXIT_SUCCESS;
+       }
+
+       // open second object 
+       void* barHandle = dlopen("libbar.dylib", RTLD_LOCAL);
+       if ( barHandle == NULL ) {
+               FAIL("dlopen-RTLD_LOCAL-weak: dlopen(\"libbar.dylib\", RTLD_LOCAL) failed: %s", dlerror());
+               return EXIT_SUCCESS;
+       }
+       
+       // get functions
+       getproc fooproc = (getproc)dlsym(fooHandle, "getA");
+       if ( fooproc == NULL ) {
+               FAIL("dlopen-RTLD_LOCAL-weak: dlsym(getA) failed: %s", dlerror());
+               return EXIT_SUCCESS;
+       }
+       getproc barproc = (getproc)dlsym(barHandle, "getA");
+       if ( barproc == NULL ) {
+               FAIL("dlopen-RTLD_LOCAL-weak: dlsym(getA) failed: %s", dlerror());
+               return EXIT_SUCCESS;
+       }
+       
+       // get values
+       int* fooA = (*fooproc)();
+       int* barA = (*barproc)();
+       
+       if ( fooA == A )
+               FAIL("dlopen-RTLD_LOCAL-weak: fooA == A");
+       else if ( barA == A )
+               FAIL("dlopen-RTLD_LOCAL-weak: barA == A");
+       else if ( fooA == barA )
+               FAIL("dlopen-RTLD_LOCAL-weak: fooA == barA");
+       else
+               PASS("dlopen-RTLD_LOCAL-weak");
+       return EXIT_SUCCESS;
+}
index 260c1e04745c317ae6663e074bd712fd26e7ff4d..e6a5e5a1eb6db6d13ed3a70f7282cfb7e053d99b 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main foo.bundle bar.bundle
        ./main foo.dylib bar.bundle
 
index 776d67669ba7ae07294c2f15fc2362b1839ba168..800a40c235cefc6007260e627897151a04e79f75 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main test.bundle test.dylib
index 3cbb8e53ccb85d39d7d9c54b38690fa67859ba0a..b6a476e9f5799f16d1a114a66e479b5dc771da5b 100644 (file)
@@ -34,7 +34,9 @@ include ${TESTROOT}/include/common.makefile
 ###
 
 
-run: all
+all-check: all check
+
+check:
        export DYLD_FALLBACK_LIBRARY_PATH=hide && ./main /foo/bar/libfoo.dylib
 
 all: main 
index 3bb5738e0db0998ed59cc2e4edeb5f9f7547f2b1..75479e482ccdde84535af4e3fa41d87b1932b230 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main 
 
 all: main 
index 92a0b7914afb18d150155e27d13fd3fd907d5178..eb6db508290f62817784257c0f01c40202913a54 100644 (file)
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
+PWD = $(shell pwd)
 
 ###
 ### Test that RTLD_NOLOAD finds existing image 
 ### even when symlinks are used to obscure it
 ###
 
-run: all
+all-check: all check
+
+check:
        ./main libfoosym.dylib
        ./main2 libbar.dylib
 
@@ -43,7 +46,7 @@ libfoosym.dylib : libfoo.dylib
        ln -sf libfoo.dylib libfoosym.dylib
 
 libfoo.dylib : foo.c
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o `pwd`/libfoo.dylib 
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o ${PWD}/libfoo.dylib 
 
 main2 : main.c libbarsym.dylib
        ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c libbarsym.dylib -o main2 
@@ -52,7 +55,7 @@ libbarsym.dylib : libbar.dylib
        ln -sf libbar.dylib libbarsym.dylib
 
 libbar.dylib : bar.c
-       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -install_name `pwd`/libbarsym.dylib 
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -install_name ${PWD}/libbarsym.dylib 
 
 clean:
        ${RM} ${RMFLAGS} *~ main main2 libfoo.dylib libfoosym.dylib libbar.dylib libbarsym.dylib
index 624f4f1127b26f959cb53dab8c9357fb8efd0206..f634e7b98afcd322f78b6c08a3ae6aed37db9b64 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main libfoo.dylib
index 0d2ffe26e3be8639596270f786c3d8ec76cae023..3b639ea9b4f8ab51f7f3144cb070d60a23494692 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main test.bundle foo.dylib foo_foo2.dylib
index 776d67669ba7ae07294c2f15fc2362b1839ba168..800a40c235cefc6007260e627897151a04e79f75 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main test.bundle test.dylib
index 9902a73518596017054dcd3d53319b67d7048fcf..dcf5be4986e47b8b314b76751744b5a72278f3b3 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main libbar.dylib
index 4f842dc5c50c6521cd2823492157f8f7647170bf..6947d3159e03e9c65b716de3c6a51ea6ccd4ebe1 100644 (file)
@@ -41,6 +41,7 @@ static void __attribute__((constructor)) myinit()
 
 void waitForState(int value)
 {
+       //fprintf(stderr, "waitForState(%d), currently %d\n", value, sValue);
        pthread_mutex_lock(&sBarrierMutex);
        while ( sValue < value ) {
                struct timeval        tvNow;
@@ -49,7 +50,7 @@ void waitForState(int value)
                TIMEVAL_TO_TIMESPEC(&tvNow, &tsTimeout);
                tsTimeout.tv_sec += 2;    // fail if block for 2 seconds
                if ( pthread_cond_timedwait(&sBarrierFree, &sBarrierMutex, &tsTimeout) == ETIMEDOUT ) {
-                       FAIL("dlsym-dyld-locking");
+                       FAIL("dlopen-dyld-locking: lock timed out");
                        exit(0);
                }
        }
@@ -60,6 +61,7 @@ void waitForState(int value)
 void setState(int value)
 {
        pthread_mutex_lock(&sBarrierMutex);
+       //fprintf(stderr, "setState(%d)\n", value);
        sValue = value; 
        pthread_cond_broadcast(&sBarrierFree);
        pthread_mutex_unlock(&sBarrierMutex);
index 795261373d013e014300296cfb5a1993660bc0f6..3c68a9d50f937b31422815dcdbfc82dc864e44be 100644 (file)
@@ -61,7 +61,7 @@ int main()
                exit(0);
        }
 
-       PASS("dlsym-dyld-locking");
+       PASS("dlopen-dyld-locking");
        return EXIT_SUCCESS;
 }
 
diff --git a/unit-tests/test-cases/dlopen-error/Makefile b/unit-tests/test-cases/dlopen-error/Makefile
new file mode 100644 (file)
index 0000000..797e0c4
--- /dev/null
@@ -0,0 +1,38 @@
+##
+# Copyright (c) 2008 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+all-check: all check
+
+check:
+       ./main
+
+all:  
+       ${CC} ${CCFLAGS} -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
+
diff --git a/unit-tests/test-cases/dlopen-error/foo.c b/unit-tests/test-cases/dlopen-error/foo.c
new file mode 100644 (file)
index 0000000..0fd6c1e
--- /dev/null
@@ -0,0 +1,2 @@
+
+void foo() {}
diff --git a/unit-tests/test-cases/dlopen-error/main.c b/unit-tests/test-cases/dlopen-error/main.c
new file mode 100644 (file)
index 0000000..481db0c
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2008 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> // strstr()
+#include <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+
+int main()
+{
+       // test error message of a dylib that does not exist
+       void* handle = dlopen("libdoesnotexist.dylib", RTLD_LAZY);
+       if ( handle != NULL ) {
+               FAIL("dlopen-error: dlopen(libdoesnotexist.dylib, RTLD_LAZY) should have failed");
+               return 0;
+       }
+       if ( strstr(dlerror(), "image not found") == NULL ) {
+               FAIL("dlopen-error: expected 'image not found' in dlerror() string");
+               return 0;
+       }
+       
+       // test error message of a dylib that is not readabble
+       handle = dlopen("libnoread.dylib", RTLD_LAZY);
+       if ( handle != NULL ) {
+               FAIL("dlopen-error: dlopen(libnoread.dylib, RTLD_LAZY) should have failed");
+               return 0;
+       }
+       if ( strstr(dlerror(), "failed with errno=13") == NULL ) {
+               FAIL("dlopen-error: expected 'failed with errno=13' in dlerror() string");
+               return 0;
+       }
+       
+
+       PASS("dlopen-error");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/dlopen-executable/Makefile b/unit-tests/test-cases/dlopen-executable/Makefile
new file mode 100644 (file)
index 0000000..a3afc96
--- /dev/null
@@ -0,0 +1,47 @@
+##
+# Copyright (c) 2008 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 foo.exe foo.pie
+
+main : main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+
+
+foo.exe : foo.c
+       ${CC} ${CCFLAGS} foo.c -o foo.exe
+
+foo.pie : foo.c
+       ${CC} ${CCFLAGS} foo.c -o foo.pie -Wl,-pie
+
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main foo.exe foo.pie
+
diff --git a/unit-tests/test-cases/dlopen-executable/foo.c b/unit-tests/test-cases/dlopen-executable/foo.c
new file mode 100644 (file)
index 0000000..d639011
--- /dev/null
@@ -0,0 +1,10 @@
+int foo()
+{
+       return 10;
+}
+
+int main()
+{
+       return 0;
+}
+
diff --git a/unit-tests/test-cases/dlopen-executable/main.c b/unit-tests/test-cases/dlopen-executable/main.c
new file mode 100644 (file)
index 0000000..a9a6f21
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+typedef int (*fooproc)(void);
+
+int main()
+{
+       // dlopen of regular executable should fail
+       void* handle = dlopen("./foo.exe", RTLD_LAZY);
+       if ( handle != NULL ) {
+               FAIL("dlopen-executable: dlopen(\"./foo.exe\") did not fail");
+               return EXIT_SUCCESS;
+       }
+       
+       // dlopen of pie should work
+       handle = dlopen("./foo.pie", RTLD_LAZY);
+       if ( handle == NULL ) {
+               FAIL("dlopen-executable: dlopen(\"./foo.pie\") failed with: %s", dlerror());
+               return EXIT_SUCCESS;
+       }
+       
+       fooproc pfoo = (fooproc)dlsym(handle, "foo");
+       if ( pfoo == NULL ) {
+               FAIL("dlopen-executable: dlsym(handle, \"foo\") failed");
+               return EXIT_SUCCESS;
+       }
+       
+       if ( (*pfoo)() != 10 ) {
+               FAIL("dlopen-executable: foo() != 10");
+               return EXIT_SUCCESS;
+       }
+       
+       int result = dlclose(handle);
+       if ( result != 0 ) {
+               FAIL("dlopen-executable: dlclose(handle) returned %d", result);
+               return EXIT_SUCCESS;
+       }
+  
+       PASS("dlopen-executable");
+       return EXIT_SUCCESS;
+}
index cc201a6128d9f735af45d91a32241fef73697396..fec01768c772d5018c134ceba119212c69f17136 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main foo.bundle 
index d3dd9c2b10efc0f7520fcec043e541026eff1362..8623188df56f7b416f5e3a58d4a3732d15716f2d 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main || echo "FAIL dlopen-in-initializer" 
 
 all: main test.bundle test.dylib
diff --git a/unit-tests/test-cases/dlopen-init-dlopen-notify/Makefile b/unit-tests/test-cases/dlopen-init-dlopen-notify/Makefile
new file mode 100644 (file)
index 0000000..b24fa5f
--- /dev/null
@@ -0,0 +1,62 @@
+all-check: all check
+
+check:##
+# 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
+
+
+### <rdar://problem/5504633> ADOBE: Premiere Pro crashes on quit
+### 
+### libfoo depends on libfoo1 and libfoo2.  main dlopens(libfoo).
+### libfoo1 has an initializer that calls dlopen(libbar).
+### libbar depends on libfoo2
+###
+
+all-check: all check
+
+check:
+       ./main 
+
+all: main 
+
+main : main.cxx  libfoo.dylib 
+       ${CXX} ${CCXXFLAGS} -I${TESTROOT}/include -o main main.cxx
+
+
+libfoo.dylib : foo.c libfoo1.dylib libfoo2.dylib
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib libfoo1.dylib libfoo2.dylib
+
+libfoo1.dylib : foo1.c libbar.dylib 
+       ${CC} ${CCFLAGS} -dynamiclib foo1.c -o libfoo1.dylib
+
+libfoo2.dylib : foo2.c
+       ${CC} ${CCFLAGS} -dynamiclib foo2.c -o libfoo2.dylib
+
+libbar.dylib : bar.c libfoo2.dylib
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib libfoo2.dylib
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libbar.dylib libfoo.dylib libfoo1.dylib libfoo2.dylib
+
diff --git a/unit-tests/test-cases/dlopen-init-dlopen-notify/bar.c b/unit-tests/test-cases/dlopen-init-dlopen-notify/bar.c
new file mode 100644 (file)
index 0000000..e425999
--- /dev/null
@@ -0,0 +1 @@
+void bar() {}
diff --git a/unit-tests/test-cases/dlopen-init-dlopen-notify/foo.c b/unit-tests/test-cases/dlopen-init-dlopen-notify/foo.c
new file mode 100644 (file)
index 0000000..edbdbc4
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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 <dlfcn.h>
+
+
+
+int foo()
+{
+       return 10;
+}
diff --git a/unit-tests/test-cases/dlopen-init-dlopen-notify/foo1.c b/unit-tests/test-cases/dlopen-init-dlopen-notify/foo1.c
new file mode 100644 (file)
index 0000000..c24996b
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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 <dlfcn.h>
+
+static void myInit() __attribute__((constructor));
+
+static void myInit() 
+{              
+       // call dlopen to verify that initializer lock can be held recursively
+       dlopen("libbar.dylib", RTLD_LAZY);
+}
+
+
+int foo1()
+{
+       return 10;
+}
diff --git a/unit-tests/test-cases/dlopen-init-dlopen-notify/foo2.c b/unit-tests/test-cases/dlopen-init-dlopen-notify/foo2.c
new file mode 100644 (file)
index 0000000..5dd0a2a
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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 <dlfcn.h>
+
+static void myInit() __attribute__((constructor));
+
+static void myInit() 
+{              
+
+}
+
+
+int foo2()
+{
+       return 10;
+}
diff --git a/unit-tests/test-cases/dlopen-init-dlopen-notify/main.cxx b/unit-tests/test-cases/dlopen-init-dlopen-notify/main.cxx
new file mode 100644 (file)
index 0000000..cb916f2
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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 <dlfcn.h>
+#include <mach-o/dyld.h>
+#include <set>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+static void trySO(const char* path)
+{
+       void* handle = dlopen(path, RTLD_LAZY);
+       if ( handle == NULL ) {
+               FAIL("dlopen(\"%s\") failed with: %s", path, dlerror());
+               exit(0);
+       }
+       
+       void* sym = dlsym(handle, "foo");
+       if ( sym == NULL ) {
+               FAIL("dlsym(handle, \"foo\") failed");
+               exit(0);
+       }
+       
+       int result = dlclose(handle);
+       if ( result != 0 ) {
+               if ( result == 1 ) {
+                       // panther dyld returns 1 if you try to dlclose() a dylib
+                       XFAIL("dlclose(handle) returned %d", result);
+               }
+               else {
+                       FAIL("dlclose(handle) returned %d", result);
+                       exit(0);
+               }
+       }
+
+}
+
+static std::set<const struct mach_header*> sCurrentImages;
+
+static void notify(const struct mach_header *mh, intptr_t vmaddr_slide) 
+{
+  //fprintf(stderr, "mh=%p\n", mh);
+  if ( sCurrentImages.count(mh) != 0 ) {
+    FAIL("notified twice about %p", mh);
+    exit(0);
+  }
+  sCurrentImages.insert(mh);
+}
+
+
+
+int main()
+{
+  _dyld_register_func_for_add_image(&notify);
+
+       trySO("libfoo.dylib");
+  
+       PASS("dlopen-init-dlopen-notify");
+       return EXIT_SUCCESS;
+}
index 723ff976fa0952d56477eb1ecb8e5604b4fb658c..8144bce22a2c1ad2cfa37449544263a2bae0ded7 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main || echo "FAIL dlopen-init-dlopen-up" 
 
 all: main 
index 4a35562c20fd632eba5926bcd751ad2a2d0a3058..67d3a633205524919099128ef339e202f8d8e2fb 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main || echo "FAIL dlopen-init-dlopen" 
 
 all: main 
index 3991ab4ac9341cb687794f011464d174c65149f8..104e51b25c39c3aa0642806c6fbe6416404f099a 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main || echo "FAIL dlopen-init-dlopen-up" 
 
 all: main 
index e307053cc542e917d1c069249aad3d65606a539e..a4bc8a5b1941be07c34a46ab46cec547bb464d79 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main test1.dylib test2.dylib
diff --git a/unit-tests/test-cases/dlopen-leak-threaded/Makefile b/unit-tests/test-cases/dlopen-leak-threaded/Makefile
new file mode 100644 (file)
index 0000000..1afad69
--- /dev/null
@@ -0,0 +1,61 @@
+##
+# 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
+
+
+#
+# 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:
+       ${TESTROOT}/bin/exit-zero-pass.pl "dlopen-leak" "dlopen-leak" "DYLD_LIBRARY_PATH=hide && ./main | grep '0 leaks for 0 total leaked bytes' > /dev/null"
+       ${TESTROOT}/bin/exit-zero-pass.pl "dlopen-leak" "dlopen-leak" "./main | grep '0 leaks for 0 total leaked bytes' > /dev/null"
+
+check-xfail:
+       echo "XFAIL dlopen-leak"; 
+       
+       
+all: main
+
+
+main : main.c 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c -o main 
+
+
+
+clean:
+       ${RM} ${RMFLAGS} *~  main 
diff --git a/unit-tests/test-cases/dlopen-leak-threaded/main.c b/unit-tests/test-cases/dlopen-leak-threaded/main.c
new file mode 100644 (file)
index 0000000..c7fc150
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * 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 <stdlib.h>
+#include <dlfcn.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+  
+#include "test.h"
+
+
+///
+/// Test that the dyld copy of the unwinder keeps each thread's
+/// exception object seperate.
+///
+
+static void* work(void* arg)
+{
+       // will fail and cause exception to be thrown inside dyld
+       dlopen((char*)arg, RTLD_LAZY);
+       return NULL;
+}
+
+
+int main()
+{
+       pthread_t worker1;
+       if ( pthread_create(&worker1, NULL, work, "/frazzle/bar") != 0 ) {
+               FAIL("pthread_create failed");
+               exit(0);
+       }
+
+       pthread_t worker2;
+       if ( pthread_create(&worker2, NULL, work, "/frazzle/foo") != 0 ) {
+               FAIL("pthread_create failed");
+               exit(0);
+       }
+       
+       pthread_t worker3;
+       if ( pthread_create(&worker3, NULL, work, "/frazzle/dazzle") != 0 ) {
+               FAIL("pthread_create failed");
+               exit(0);
+       }
+
+       
+       void* result;
+       //fprintf(stderr, "waiting for worker 1\n");
+       pthread_join(worker1, &result);
+       //fprintf(stderr, "waiting for worker 2\n");
+       pthread_join(worker2, &result);
+       //fprintf(stderr, "waiting for worker 3\n");
+       pthread_join(worker3, &result);
+
+       // 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-leak/Makefile b/unit-tests/test-cases/dlopen-leak/Makefile
new file mode 100644 (file)
index 0000000..b3a47a3
--- /dev/null
@@ -0,0 +1,68 @@
+##
+# 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
+
+
+#
+# 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:
+       ${TESTROOT}/bin/exit-zero-pass.pl "dlopen-leak" "dlopen-leak" "DYLD_LIBRARY_PATH=hide && ./main | grep '0 leaks for 0 total leaked bytes' > /dev/null"
+       ${TESTROOT}/bin/exit-zero-pass.pl "dlopen-leak" "dlopen-leak" "./main | grep '0 leaks for 0 total leaked bytes' > /dev/null"
+
+check-xfail:
+       echo "XFAIL dlopen-leak"; 
+       
+       
+all: main
+
+
+hide/libbar.dylib : bar.c
+       mkdir -p hide
+       ${CC} bar.c -dynamiclib -o hide/libbar.dylib -install_name libbar.dylib 
+
+libfoo.dylib : foo.c hide/libbar.dylib
+       ${CC} foo.c hide/libbar.dylib -dynamiclib -o libfoo.dylib 
+
+main : main.c libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c -o main 
+
+
+
+clean:
+       ${RM} ${RMFLAGS} *~  main libfoo.dylib hide
diff --git a/unit-tests/test-cases/dlopen-leak/bar.c b/unit-tests/test-cases/dlopen-leak/bar.c
new file mode 100644 (file)
index 0000000..b72a1a5
--- /dev/null
@@ -0,0 +1,3 @@
+void bar()
+{
+}
diff --git a/unit-tests/test-cases/dlopen-leak/foo.c b/unit-tests/test-cases/dlopen-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-leak/main.c b/unit-tests/test-cases/dlopen-leak/main.c
new file mode 100644 (file)
index 0000000..511a140
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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 <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);
+               dlopen("libnotthere.dylib", RTLD_LAZY);
+       }
+       
+       // execute leaks command on myself
+       char cmd[512];
+       sprintf(cmd, "leaks %u\n", getpid());
+       system(cmd);
+               
+       return EXIT_SUCCESS;
+}
index 90f8872d2641846787b82ddd8e5e501fabeacd0b..dae1997c9f275283798b53ed56fbede32146e4b3 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main-local-first  
        ./main-global-first 
 
index 776d67669ba7ae07294c2f15fc2362b1839ba168..800a40c235cefc6007260e627897151a04e79f75 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main test.bundle test.dylib
diff --git a/unit-tests/test-cases/dlopen-notify-bind/Makefile b/unit-tests/test-cases/dlopen-notify-bind/Makefile
new file mode 100644 (file)
index 0000000..5844be2
--- /dev/null
@@ -0,0 +1,51 @@
+##
+# 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
+
+
+### <rdar://problem/5565230> CFSTRs cause crashes in Leopard
+### 
+### main registers for notification and then dlopens(libfoo).
+### In the notification callback, main calls NSLookupSymbolInImage(BIND)
+### which double bound libfoo
+###
+
+all-check: all check
+
+check:
+       ./main 
+
+all: main 
+
+main : main.c  libfoo.dylib 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c -mmacosx-version-min=10.4
+
+
+libfoo.dylib : foo.c
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib 
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libfoo.dylib 
+
diff --git a/unit-tests/test-cases/dlopen-notify-bind/foo.c b/unit-tests/test-cases/dlopen-notify-bind/foo.c
new file mode 100644 (file)
index 0000000..8dab6be
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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 <stdlib.h>
+
+
+void* externalRlocToMalloc = &malloc;
+
+void* foo()
+{
+       return externalRlocToMalloc;
+}
diff --git a/unit-tests/test-cases/dlopen-notify-bind/main.c b/unit-tests/test-cases/dlopen-notify-bind/main.c
new file mode 100644 (file)
index 0000000..d99436a
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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 <dlfcn.h>
+#include <mach-o/dyld.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+typedef void* (*fooProc)();
+
+
+static void notify(const struct mach_header *mh, intptr_t vmaddr_slide) 
+{
+       //fprintf(stderr, "mh=%p\n", mh);
+       NSLookupSymbolInImage(mh, "_bar", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
+}
+
+
+int main()
+{
+       _dyld_register_func_for_add_image(&notify);
+
+       void* handle = dlopen("libfoo.dylib", RTLD_LAZY);
+       if ( handle == NULL ) {
+               FAIL("dlopen(\"%s\") failed with: %s", "libfoo.dylib", dlerror());
+               exit(0);
+       }
+       
+       fooProc fooPtr = (fooProc)dlsym(handle, "foo");
+       if ( fooPtr == NULL ) {
+               FAIL("dlsym(handle, \"foo\") failed");
+               exit(0);
+       }
+       
+       void* foosMalloc = (*fooPtr)();
+       //fprintf(stderr, "foo says &malloc=%p\n", foosMalloc);
+       //fprintf(stderr, "&malloc=%p\n", &malloc);
+       
+       dlclose(handle);
+  
+       if ( foosMalloc == &malloc )
+               PASS("dlopen-notify-bind");
+       else
+               FAIL("dlopen-notify-bind libfoo.dylib double bound");
+       return EXIT_SUCCESS;
+}
index 92ea1b0675e42e2dc3113263e5d4fff29824d889..b8a5145e4bbb99610ce9047124127536387e734c 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main 
index 7240521da985135796a14780fe4f59c43a8a0e95..81977a420136ae20e9b310d5f07d2b271f8c4769 100644 (file)
@@ -49,6 +49,7 @@ int main()
                FAIL("dlsym(handle, \"foo\") failed");
                exit(1);
        }
+       
        if ( sym != &foo ) {
                FAIL("dlsym(handle, \"foo\") returned wrong address");
                exit(1);
index 4b1d3e7dfd5f75b12f11abd2061e4c0eea2bc888..285779f05b96119f020d7179e070f6f24f1738f9 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
        ./main batch
 
diff --git a/unit-tests/test-cases/dlopen_preflight-leak-image-deny-single/Makefile b/unit-tests/test-cases/dlopen_preflight-leak-image-deny-single/Makefile
new file mode 100644 (file)
index 0000000..9562ac5
--- /dev/null
@@ -0,0 +1,63 @@
+##
+# Copyright (c) 2007-2008 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_preflight() if a non-batch image state handler
+# denies the load
+# <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight
+#
+
+
+# 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:
+       ${TESTROOT}/bin/exit-zero-pass.pl "dlopen_preflight-leak-image-deny-single" "dlopen_preflight-leak-image-deny-single" "./main | grep '0 leaks for 0 total leaked bytes' > /dev/null"
+
+check-xfail:
+       echo "XFAIL dlopen-leak"; 
+
+all: main
+
+libfoo.dylib : foo.c 
+       ${CC} foo.c -dynamiclib -o libfoo.dylib 
+
+main : main.c libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c -o main 
+
+
+clean:
+       ${RM} ${RMFLAGS} *~  main libfoo.dylib 
diff --git a/unit-tests/test-cases/dlopen_preflight-leak-image-deny-single/foo.c b/unit-tests/test-cases/dlopen_preflight-leak-image-deny-single/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_preflight-leak-image-deny-single/main.c b/unit-tests/test-cases/dlopen_preflight-leak-image-deny-single/main.c
new file mode 100644 (file)
index 0000000..a7ffa59
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007-2008 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 <string.h>
+#include <mach-o/dyld.h>  
+#include <mach-o/dyld_priv.h>  
+#include <dlfcn.h>  
+  
+#include "test.h"
+
+static bool doCheck = false;
+
+static const char* batchMappedHandler(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+{
+       if ( doCheck ) 
+               return "can't load";
+       return NULL;
+}
+
+
+int main()
+{
+       // tell dyld we want to know when images are mapped
+       dyld_register_image_state_change_handler(dyld_image_state_mapped, false, batchMappedHandler);
+       doCheck = true;
+
+       for (int i=0; i < 10; ++i) {
+               dlopen_preflight("libfoo.dylib");
+       }
+
+       // 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-leak/Makefile b/unit-tests/test-cases/dlopen_preflight-leak/Makefile
new file mode 100644 (file)
index 0000000..eff03d8
--- /dev/null
@@ -0,0 +1,65 @@
+##
+# 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
+
+
+#
+# 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:
+       ${TESTROOT}/bin/exit-zero-pass.pl "dlopen_preflight-leak" "dlopen_preflight-leak" "DYLD_LIBRARY_PATH=hide && ./main | grep '0 leaks for 0 total leaked bytes' > /dev/null"
+       ${TESTROOT}/bin/exit-zero-pass.pl "dlopen_preflight-leak" "dlopen_preflight-leak" "./main | grep '0 leaks for 0 total leaked bytes' > /dev/null"
+
+check-xfail:
+       echo "XFAIL dlopen-leak"; 
+
+all: main
+
+hide/libbar.dylib : bar.c
+       mkdir -p hide
+       ${CC} bar.c -dynamiclib -o hide/libbar.dylib -install_name libbar.dylib 
+
+libfoo.dylib : foo.c hide/libbar.dylib
+       ${CC} foo.c hide/libbar.dylib -dynamiclib -o libfoo.dylib 
+
+main : main.c libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include main.c -o main 
+
+
+clean:
+       ${RM} ${RMFLAGS} *~  main libfoo.dylib hide
diff --git a/unit-tests/test-cases/dlopen_preflight-leak/bar.c b/unit-tests/test-cases/dlopen_preflight-leak/bar.c
new file mode 100644 (file)
index 0000000..b72a1a5
--- /dev/null
@@ -0,0 +1,3 @@
+void bar()
+{
+}
diff --git a/unit-tests/test-cases/dlopen_preflight-leak/foo.c b/unit-tests/test-cases/dlopen_preflight-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_preflight-leak/main.c b/unit-tests/test-cases/dlopen_preflight-leak/main.c
new file mode 100644 (file)
index 0000000..612e141
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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 <stdlib.h>
+#include <dlfcn.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+  
+#include "test.h"
+
+
+int main()
+{
+       for (int i=0; i < 100; ++i) {
+               dlopen_preflight("libfoo.dylib");
+       }
+       
+       // 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
new file mode 100644 (file)
index 0000000..8a5e93a
--- /dev/null
@@ -0,0 +1,42 @@
+##
+# 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
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/unit-tests/test-cases/dlopen_preflight-shared-cache/main.c b/unit-tests/test-cases/dlopen_preflight-shared-cache/main.c
new file mode 100644 (file)
index 0000000..6c69905
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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 d029efe694b3a553ed69292631a1efb5f14857c6..d1f6bf087ee5039ab371afb51d9f93dfb4d3e684 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main test.bundle test.dylib
diff --git a/unit-tests/test-cases/dlsym-RTLD_MAIN_ONLY/Makefile b/unit-tests/test-cases/dlsym-RTLD_MAIN_ONLY/Makefile
new file mode 100644 (file)
index 0000000..9e2b6da
--- /dev/null
@@ -0,0 +1,22 @@
+
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+all-check: all check
+
+check:
+       ./main
+
+all: main 
+
+main : main.c libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include libfoo.dylib -o main main.c
+
+libfoo.dylib : foo.c
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libfoo.dylib
+
diff --git a/unit-tests/test-cases/dlsym-RTLD_MAIN_ONLY/foo.c b/unit-tests/test-cases/dlsym-RTLD_MAIN_ONLY/foo.c
new file mode 100644 (file)
index 0000000..a82c67d
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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;
+}
+
+int bar()
+{
+       return 10;
+}
diff --git a/unit-tests/test-cases/dlsym-RTLD_MAIN_ONLY/main.c b/unit-tests/test-cases/dlsym-RTLD_MAIN_ONLY/main.c
new file mode 100644 (file)
index 0000000..65aacee
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2008 Apple, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+int foo()
+{
+       return 0;
+}
+
+
+int main()
+{
+       // make sure we get the foo() in main and not the one in libfoo.dylib
+       if ( dlsym(RTLD_MAIN_ONLY, "foo") != &foo ) {
+               FAIL("dlsym(RTLD_MAIN_ONLY, \"foo\") returned wrong value");
+       }
+       
+       // make sure don't find bar() in libfoo.dylib
+       if ( dlsym(RTLD_MAIN_ONLY, "bar") != NULL ) {
+               FAIL("dlsym(RTLD_MAIN_ONLY, \"bar\") returned non-NULL");
+       }
+       
+       
+       PASS("dlsym-RTLD_MAIN_ONLY");
+       return EXIT_SUCCESS;
+}
index 980ce61550b2c05265609356070c3783056f863f..8be62117a52c45bbd743f34eaa7831b1b1452a92 100644 (file)
@@ -34,7 +34,9 @@ endif
 
 
 
-run: all
+all-check: all check
+
+check:
        ${TESTROOT}/bin/exit-zero-pass.pl "dlsym-RTLD_NEXT-missing with circular libraries" "dlsym-RTLD_NEXT-missing with circular libraries" ${PROG}
 
 all:  main
index af0dec0924e4a4afbb36ad087d377a843c98d3e9..4a148d81b7095902663c0e9f8a9903cce77ace05 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main 
index af0dec0924e4a4afbb36ad087d377a843c98d3e9..4a148d81b7095902663c0e9f8a9903cce77ace05 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main 
index 92ea1b0675e42e2dc3113263e5d4fff29824d889..b8a5145e4bbb99610ce9047124127536387e734c 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main 
index b363103bcfb50e62ee864f1bbc000db8999d722d..f806baa618f926935ff5da00482e828bb9149de7 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main foo.dylib
        ./main foo.bundle
 
diff --git a/unit-tests/test-cases/dtrace-static-probes/Makefile b/unit-tests/test-cases/dtrace-static-probes/Makefile
new file mode 100644 (file)
index 0000000..3c40c6f
--- /dev/null
@@ -0,0 +1,52 @@
+##
+# Copyright (c) 2008 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 dtrace probes fire 
+#
+
+all-check: all check
+
+check:
+       if [ `sudo dtrace -q -n 'Foo$$target:::count { printf("%u\n", arg0); } ' -c ./main | wc -w` == 5 ]; \
+       then \
+               echo "PASS dtrace-static-probes"; \
+       else \
+               echo "FAIL dtrace-static-probes"; \
+       fi; \
+
+       
+
+all: main 
+
+
+main: main.c 
+       dtrace -h -s foo.d
+       ${CC} ${CCFLAGS} main.c -o main -dead_strip
+
+
+clean:
+       rm -rf main foo.h
+       
diff --git a/unit-tests/test-cases/dtrace-static-probes/foo.d b/unit-tests/test-cases/dtrace-static-probes/foo.d
new file mode 100644 (file)
index 0000000..930965b
--- /dev/null
@@ -0,0 +1,7 @@
+
+provider Foo {
+       probe count(int);
+};
+
+
+#pragma D attributes Evolving/Evolving/Common provider Foo args
diff --git a/unit-tests/test-cases/dtrace-static-probes/main.c b/unit-tests/test-cases/dtrace-static-probes/main.c
new file mode 100644 (file)
index 0000000..851bb33
--- /dev/null
@@ -0,0 +1,13 @@
+
+#include <stdio.h>
+
+#include "foo.h"
+
+
+int main() {
+       for (int i=0; i < 5; ++i) {
+               FOO_COUNT(i);
+       }
+
+       return 0;
+}
index 56ebee5c367ecdaddd25cdc80603aca88fee3193..00ad15684b7ac4419ebafac904766d65dacf43b7 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
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main test.bundle test.dylib
 
 main : main.c foo.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c foo.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c foo.c -mmacosx-version-min=10.5
 
 
 test.bundle : foo.c
-       ${CC} ${CCFLAGS} -bundle foo.c -o test.bundle
+       ${CC} ${CCFLAGS} -bundle foo.c -o test.bundle -mmacosx-version-min=10.5
 
 test.dylib : foo.c
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o test.dylib
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o test.dylib -mmacosx-version-min=10.5
 
 
 
index 723309619c3f145def018b2d9bb7494f4dbd7aa0..61f202b0794887120b869f32185124c3798e07b2 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ${TESTROOT}/bin/exit-zero-pass.pl "_dyld_launched_prebound() was implemented" "_dyld_launched_prebound() was not implemented" ./main
 
 all:
index 98fd14df8ddf34dfa47f625fec06aada056916b3..d17bbaa9f8f50121c3cd792d685a456770048ca6 100644 (file)
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+STACK_BASE = 0x8fe01000
+
+ifeq "armv6" "$(ARCH)"
+       STACK_BASE = 0x2fe01000
+endif
+ifeq "ppc64" "$(ARCH)"
+       STACK_BASE = 0x7fff5fc00000
+endif
+ifeq "x86_64" "$(ARCH)"
+       STACK_BASE = 0x7fff5fc00000
+endif
+
+
+
+all-check: all check
+
+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 -pagezero_size 0x40000000
+       ${CC} ${CCFLAGS} -Wno-deprecated-declarations -I${TESTROOT}/include -o main main.c -Wl,-stack_addr,${STACK_BASE} -Wl,-stack_size,0x00100000
 
 clean:
        ${RM} ${RMFLAGS} main
index 957dfef08388fdedea2f202b28221bd54849efb4..2bd67bad01ea25948eb8b7619ad436f3a56da6ab 100644 (file)
 //
 // This builds an executable that is just big enough to force dyld to slide a bit
 //
+#if __arm__
+       #define ARRAY_SIZE  66582528
+#else
+       #define ARRAY_SIZE 335400000
+#endif
 
-#define ARRAY_SIZE 335400000
-
-int bigarray1[ARRAY_SIZE];
+//int bigarray1[ARRAY_SIZE];
 
 int
 main()
diff --git a/unit-tests/test-cases/dynamic_cast-basic/Makefile b/unit-tests/test-cases/dynamic_cast-basic/Makefile
new file mode 100644 (file)
index 0000000..79e8be6
--- /dev/null
@@ -0,0 +1,24 @@
+
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+all-check: all check
+
+check:
+       ./main
+
+all: main
+
+main: main.cxx librealmain.dylib 
+       ${CXX} ${CXXFLAGS} -I${TESTROOT}/include -o main main.cxx librealmain.dylib 
+
+librealmain.dylib: realmain.cxx  libfoo.dylib
+       ${CXX} ${CXXFLAGS} -I${TESTROOT}/include -dynamiclib -o librealmain.dylib realmain.cxx libfoo.dylib
+
+libfoo.dylib: foo.cxx  
+       ${CXX} ${CXXFLAGS} -I${TESTROOT}/include -dynamiclib -o libfoo.dylib foo.cxx  
+
+clean:
+       ${RM} ${RMFLAGS} *~ main  libfoo.dylib  librealmain.dylib
+
diff --git a/unit-tests/test-cases/dynamic_cast-basic/foo.cxx b/unit-tests/test-cases/dynamic_cast-basic/foo.cxx
new file mode 100644 (file)
index 0000000..5c824bb
--- /dev/null
@@ -0,0 +1,15 @@
+
+#include <stdlib.h> 
+
+#include "foo.h"
+
+test* maketestsub()
+{
+       return new testsub();
+}
+
+bool istestsub(test* t)
+{
+       return (dynamic_cast<testsub*>(t) != NULL);
+}
+
diff --git a/unit-tests/test-cases/dynamic_cast-basic/foo.h b/unit-tests/test-cases/dynamic_cast-basic/foo.h
new file mode 100644 (file)
index 0000000..940e356
--- /dev/null
@@ -0,0 +1,32 @@
+
+
+class test
+{
+public:
+       virtual void aa() {}
+
+       int             f;
+};
+
+class testsub : public test
+{
+public:
+                       testsub() : g(0) {}
+       virtual void aa() {}
+
+       int             g;
+};
+
+
+class testsubother : public test
+{
+public:
+                       testsubother() : h(0) {}
+       virtual void aa() {}
+
+       int             h;
+};
+
+extern test* maketestsub();
+
+extern bool istestsub(test* t);
\ No newline at end of file
diff --git a/unit-tests/test-cases/dynamic_cast-basic/main.cxx b/unit-tests/test-cases/dynamic_cast-basic/main.cxx
new file mode 100644 (file)
index 0000000..a25c448
--- /dev/null
@@ -0,0 +1,10 @@
+
+extern void realmain();
+
+int main()
+{
+       realmain();
+       return 0;
+}
+
+
diff --git a/unit-tests/test-cases/dynamic_cast-basic/realmain.cxx b/unit-tests/test-cases/dynamic_cast-basic/realmain.cxx
new file mode 100644 (file)
index 0000000..e951768
--- /dev/null
@@ -0,0 +1,24 @@
+
+
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+#include "foo.h"
+
+
+void realmain()
+{
+       test* t1 = maketestsub();
+       test* t2 = new testsub();
+       test* t3 = new testsubother();
+       testsub* t1a = dynamic_cast<testsub*>(t1);
+       testsubother* t3a = dynamic_cast<testsubother*>(t3);
+       if ( (t1a == NULL) || (t3a == NULL) || !istestsub(t2) )
+               FAIL("dynamic_cast-basic");
+       else
+               PASS("dynamic_cast-basic");
+}
+
+
diff --git a/unit-tests/test-cases/env-DYLD_FALLBACK_LIBRARY_PATH/Makefile b/unit-tests/test-cases/env-DYLD_FALLBACK_LIBRARY_PATH/Makefile
new file mode 100644 (file)
index 0000000..ab33f8c
--- /dev/null
@@ -0,0 +1,44 @@
+##
+# Copyright (c) 2008 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:
+       export DYLD_FALLBACK_LIBRARY_PATH=`pwd`/hide && ./main hide/libz.dylib
+       ./main /usr/lib/libz
+       export DYLD_FALLBACK_LIBRARY_PATH=""  && ${TESTROOT}/bin/exit-non-zero-pass.pl "env-DYLD_FALLBACK_LIBRARY_PATH" "env-DYLD_FALLBACK_LIBRARY_PATH with empty env" ./main2
+       
+       
+all:
+       mkdir -p hide
+       ${CC} compress.c -dynamiclib -o hide/libz.dylib -install_name /other/libz.dylib
+       ${CC} -I${TESTROOT}/include main.c -o main hide/libz.dylib
+       ${CC} -I${TESTROOT}/include main.c -DSHOULD_FAIL=1 -o main2 hide/libz.dylib
+       
+
+clean:
+       ${RM} -rf *~  main main2 hide
diff --git a/unit-tests/test-cases/env-DYLD_FALLBACK_LIBRARY_PATH/compress.c b/unit-tests/test-cases/env-DYLD_FALLBACK_LIBRARY_PATH/compress.c
new file mode 100644 (file)
index 0000000..b45d613
--- /dev/null
@@ -0,0 +1,4 @@
+int compress()
+{
+       return 0;
+}
diff --git a/unit-tests/test-cases/env-DYLD_FALLBACK_LIBRARY_PATH/main.c b/unit-tests/test-cases/env-DYLD_FALLBACK_LIBRARY_PATH/main.c
new file mode 100644 (file)
index 0000000..3534032
--- /dev/null
@@ -0,0 +1,24 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+
+#include "test.h"
+
+extern void compress();
+
+int main(int argc, const char* argv[])
+{
+#if !SHOULD_FAIL
+       Dl_info info;
+       if ( dladdr(&compress, &info) ) {
+               //fprintf(stderr, "_compress found in %s\n", info.dli_fname);
+               if ( strstr(info.dli_fname, argv[1]) != 0 ) {
+                       PASS("env-DYLD_FALLBACK_LIBRARY_PATH");
+                       exit(0);
+               }
+       }
+       FAIL("env-DYLD_FALLBACK_LIBRARY_PATH");
+#endif
+       return EXIT_SUCCESS;
+}
index ae7321e9581e4781f8c69fdb5eeef583a0004b76..b85494dfc03637df65bde4cfb6b21d4a211936c8 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        #export DYLD_INSERT_LIBRARIES=libfoo.dylib && ./main
        ./main
 
index 8b4d218f4a607a60627bbe6cf34af7ad73ee8c6f..1992633bebb62342c88e5022358ef9dc8c852d9d 100644 (file)
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-all :  main 
-       export DYLD_FALLBACK_LIBRARY_PATH=$$PWD && ./main
+PWD = $(shell pwd)
+
+
+all-check: all check
+
+
+all:  main 
 
 main : main.c libfoo.dylib libbar.dylib
        ${CC} -I${TESTROOT}/include main.c libfoo.dylib libbar.dylib -o main 
 
 libfoo.dylib : foo.c
-       ${CC} -I${TESTROOT}/include  foo.c -DFOO=1 -dynamiclib -o $$PWD/libfoo.dylib
+       ${CC} -I${TESTROOT}/include  foo.c -DFOO=1 -dynamiclib -install_name ${PWD}/libfoo.dylib -o libfoo.dylib
 
 libbar.dylib : bar.c other/libfoo.dylib
-       ${CC} -I${TESTROOT}/include  bar.c -dynamiclib other/libfoo.dylib -o $$PWD/libbar.dylib
-
+       ${CC} -I${TESTROOT}/include  bar.c -dynamiclib other/libfoo.dylib -install_name ${PWD}/libbar.dylib -o libbar.dylib
+       
 other/libfoo.dylib : foo.c
-       mkdir -p $$PWD/other
-       ${CC} -I${TESTROOT}/include  foo.c -DFOO=2 -dynamiclib  -o $$PWD/other/libfoo.dylib
+       mkdir -p ${PWD}/other
+       ${CC} -I${TESTROOT}/include  foo.c -DFOO=2 -dynamiclib  -install_name ${PWD}/other/libfoo.dylib -o other/libfoo.dylib
+
+
+
+check: 
+       export DYLD_FALLBACK_LIBRARY_PATH=${PWD} && ./main
 
 
 clean:
index 6fd0158a349c2e787ef0ecf16e6bc0abd241f361..af3f2b9ea49dd67228d9c357084228032de0bf08 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ${TESTROOT}/bin/exit-non-zero-pass.pl "fallback-with-suid" "fallback-with-suid" ./main-suid
        
 all: main-suid
index 5f54e4b3f286e8b0acd8770edbdaec796f850582..392ffaa9ddb57f8d4a0e2dc407fa38a5eb76c2f8 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main 
index ff17213668c6a39d2d47ef65f9933ba091f08b79..9ce9b26f184c5ab6917b6ed049a462da3d8d65f5 100644 (file)
@@ -26,7 +26,9 @@ include ${TESTROOT}/include/common.makefile
 
 ### verify inserted libraries override with flat namespace
 
-run: all
+all-check: all check
+
+check:
        export DYLD_INSERT_LIBRARIES="libfoo.dylib" && ./main
 
 all:
index 160955c91b61276b92eef4ca792f237ac1d022eb..14cb600fc8363dd9b69ddc2236fed606d65d2551 100644 (file)
@@ -37,7 +37,7 @@ int main(int argc, const char* argv[])
 }
 
 // inserted library has another copy of foo() that should
-// overridde this one and return 42
+// override this one and return 42
 int foo()
 {
        return 0;
index 872792161b1658395a5467a14352d1a5486b01bc..caf93e98bdccf66c47f9ed8cc26bae1ca2feb734 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main 
@@ -33,11 +35,11 @@ main : main.c libfoo.dylib
 
 
 libfoo.dylib : foo.c libbar.dylib
-       export MACOSX_DEPLOYMENT_TARGET=10.2 && ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib libbar.dylib -flat_namespace -prebind -seg1addr 20000
+       ${CC} ${CCFLAGS} -mmacosx-version-min=10.2 -dynamiclib foo.c -o libfoo.dylib libbar.dylib -flat_namespace -prebind -seg1addr 20000
 
 
 libbar.dylib : bar.c
-       export MACOSX_DEPLOYMENT_TARGET=10.2 && ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -prebind -seg1addr 30000
+       ${CC} ${CCFLAGS} -mmacosx-version-min=10.2 -dynamiclib bar.c -o libbar.dylib -prebind -seg1addr 30000
 
 
 
index c68be00ea1f082d9d52b55ebb87abb8bf1d19da1..fe7dbc14befb36cc72d25695fda1b064448855bb 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main 
index 44cfad135b5827c20d5487021247dfefb1ad9d12..f29fb627975ebde676ac40c1de28a32e830c9741 100644 (file)
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
-all : main
+all: main
 
 main: main.c
        ${CC} ${CCFLAGS} -Wno-deprecated-declarations  main.c -o main  -I${TESTROOT}/include
index 13f8146616019d04582275a206d0c9c5061a49a3..904aeb38438d11a28b68eeb32bdcf8d4e2606ef9 100644 (file)
@@ -39,12 +39,12 @@ main(int argc, const char* argv[])
 {
        const struct mach_header *image;
 
-       image = NSAddImage("Carbon.framework/Carbon",
+       image = NSAddImage("AppKit.framework/AppKit",
                        NSADDIMAGE_OPTION_RETURN_ON_ERROR | NSADDIMAGE_OPTION_WITH_SEARCHING);
        if ( image != NULL )
-               PASS("Carbon loaded");
+               PASS("AppKit loaded");
        else
-               FAIL("Could not load Carbon");
+               FAIL("Could not load AppKit");
 
        return 0;
 }
index b5c0a4c4cac2c969b81bc56abbde65f5f1c57e4a..b1810071ab4c4d49fc32bc0f5dfe3db46b1454cb 100644 (file)
@@ -30,7 +30,9 @@ include ${TESTROOT}/include/common.makefile
 #
 
 
-run: all
+all-check: all check
+
+check:
        export DYLD_LIBRARY_PATH=locations/datafile:locations/exec:locations/dir && ${TESTROOT}/bin/exit-non-zero-pass.pl "ignore-bad-files intended failure" "ignore-bad-files intended failure" ./main
        export DYLD_LIBRARY_PATH=locations/datafile:locations/exec:locations/dir:locations/real && ${TESTROOT}/bin/exit-zero-pass.pl "ignore-bad-files intended success" "ignore-bad-files intended success" ./main
 
index a1ad36d925b0de6382612d65d5f635c449ed92ab..0e1b901c96bb0d08dc84a2838a25c5279a6bbae1 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main foo.bundle
diff --git a/unit-tests/test-cases/image-slide/Makefile b/unit-tests/test-cases/image-slide/Makefile
new file mode 100644 (file)
index 0000000..9c791ea
--- /dev/null
@@ -0,0 +1,38 @@
+##
+# Copyright (c) 2005-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:
+       ./main
+
+all:
+       ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libfoo.dylib
+
+clean:
+       ${RM} ${RMFLAGS} main libfoo.dylib
diff --git a/unit-tests/test-cases/image-slide/foo.c b/unit-tests/test-cases/image-slide/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-slide/main.c b/unit-tests/test-cases/image-slide/main.c
new file mode 100644 (file)
index 0000000..f4fb318
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2008 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 <mach-o/dyld.h>
+#include <mach-o/dyld_priv.h>
+#include <dlfcn.h>
+
+#include "test.h"
+
+extern void foo();
+
+intptr_t findSlide(const struct mach_header* mh)
+{
+       int count = _dyld_image_count();
+       for(int i=0; i < count; ++i) {
+               if ( mh == _dyld_get_image_header(i) ) {
+                       return _dyld_get_image_vmaddr_slide(i);
+               }
+       }
+       return -1;
+}
+
+
+int
+main()
+{
+       // find mach_header for libfoo.dylib
+       const struct mach_header* mh;
+       Dl_info info;
+       if ( dladdr(&foo, &info) ) {
+               mh = info.dli_fbase;
+       }
+       else {
+               FAIL("dladdr() could not find foo()");
+               exit(0);
+       }
+       
+       
+       intptr_t slide1 = _dyld_get_image_slide(mh);
+       intptr_t slide2 = findSlide(mh);
+       if ( slide1 == slide2 )
+               PASS("image-slide");
+       else
+               FAIL("image-slide: 0x%lX != 0x%lX", slide1, slide2);
+       
+       return EXIT_SUCCESS;
+}
+
+
index b2876062cd999e4bc81737915e4e02c9527171e0..d4e91c84f10def6c4c9b0375fff22e7cd8aaf5f2 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main foo.bundle
index 0a6673d8f0ffc2bb265131198cfed6bf94e212ca..6ee6a622cba5897f8cd04f05534823d537133a6e 100644 (file)
@@ -34,7 +34,7 @@
 
 static int singleMappedCount = 0;
 static int batchMappedCount = 0;
-
+static int singleUnMappedCount = 0;
 
 
 static const char* batchMappedHandler(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
@@ -64,6 +64,21 @@ static const char* singleMappedHandler(enum dyld_image_states state, uint32_t in
        return NULL;
 }
 
+static const char* singleUnmappedHandler(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+{
+       printf("singleUnmappedHandler(%s)\n", info[0].imageFilePath);
+       if ( state != dyld_image_state_terminated ) {
+               FAIL("image-state-change: singleUnmappedHandler passed state %d", state);
+               exit(0);
+       }
+       if ( infoCount != 1 ) {
+               FAIL("image-state-change: singleUnmappedHandler given %d images", infoCount);
+               exit(0);
+       }
+       ++singleUnMappedCount;
+       return NULL;
+}
+
 static void loadAndUnLoad()
 {
        void* handle = dlopen("foo.bundle", RTLD_LAZY);
@@ -85,6 +100,7 @@ int main(int argc, const char* argv[])
        // tell dyld we want to know when images are mapped
        dyld_register_image_state_change_handler(dyld_image_state_dependents_mapped, true, batchMappedHandler);
        dyld_register_image_state_change_handler(dyld_image_state_mapped, false, singleMappedHandler);
+       dyld_register_image_state_change_handler(dyld_image_state_terminated, false, singleUnmappedHandler);
        // with batch mode we get notified of existing images, but not with single mode, so re-sync counts
        batchMappedCount=0;
        
@@ -92,7 +108,7 @@ int main(int argc, const char* argv[])
 
        loadAndUnLoad();
        
-       if ( singleMappedCount == batchMappedCount )
+       if ( (singleMappedCount == batchMappedCount) && (singleMappedCount == singleUnMappedCount) )
                PASS("image-state-change");
        else
                FAIL("image-state-change: batch count=%d, single count=%d", batchMappedCount, singleMappedCount);
index 5ad9359bd7fd40ef9c7648ce8b0da176dc14f94b..a89cbf98cb5345aae8bb5313ba335b0c2ff12b88 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
        ./main batch
 
index ed884958a9c114c3dea93b15e2184d60952bc8cc..a67d74153c980acf88e34739a453349c22f3c44d 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main
index 4bff29935c53b0258c12a2742ab5a15de3bd05f9..04973bc5b251c91d2a128fe8a342d7f26c8f653e 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
        ./main batch
 
index 91b2ef1a3ad11d3292fc4454fcece1d778e80263..86f01d8339e27551d9b9b1a69a994f2171fdfaef 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main
index 43172041f3dbb9f6abf02761e38b225a3c238594..87e7bc86602b9f85728ec8848c2328a844bfa7b6 100644 (file)
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run :  check1 check2 check3 check4 check5 check6 check7 check8  
+PWD = $(shell pwd)
 
-all :  main1 main2 main3 main4 main5 main6 main7 main8  
+
+all-check: all check
+
+check:  check1 check2 check3 check4 check5 check6 check7 check8  
+
+all:  main1 main2 main3 main4 main5 main6 main7 main8  
 
 main : main.c libfoo.dylib
        ${CC} -Wno-deprecated-declarations -I${TESTROOT}/include main.c -o main libfoo.dylib
 
 libfoo.dylib : foo.c
-       ${CC} -I${TESTROOT}/include  foo.c -dynamiclib -o $$PWD/libfoo.dylib
+       ${CC} -I${TESTROOT}/include  foo.c -dynamiclib -o $(PWD)/libfoo.dylib
 
 libfoo_debug.dylib : foo.c
-       ${CC} -I${TESTROOT}/include  foo.c -dynamiclib  -DDEBUG -o $$PWD/libfoo_debug.dylib -install_name $$PWD/libfoo.dylib
+       ${CC} -I${TESTROOT}/include  foo.c -dynamiclib  -DDEBUG -o libfoo_debug.dylib -install_name $(PWD)/libfoo.dylib
 
 hide/libfoo.dylib : foo.c
-       mkdir -p $$PWD/hide
-       ${CC} -I${TESTROOT}/include  foo.c -dynamiclib  -o $$PWD/hide/libfoo.dylib -install_name $$PWD/libfoo.dylib
+       mkdir -p $(PWD)/hide
+       ${CC} -I${TESTROOT}/include  foo.c -dynamiclib  -o hide/libfoo.dylib -install_name $(PWD)/libfoo.dylib
 
 hide/libfoo_debug.dylib : foo.c
-       mkdir -p $$PWD/hide
-       ${CC} -I${TESTROOT}/include  foo.c -dynamiclib  -o $$PWD/hide/libfoo_debug.dylib -install_name $$PWD/libfoo.dylib
+       mkdir -p $(PWD)/hide
+       ${CC} -I${TESTROOT}/include  foo.c -dynamiclib  -o hide/libfoo_debug.dylib -install_name $(PWD)/libfoo.dylib
 
 # bar_debug has bar_debug as install name
 libbar.dylib : foo.c
-       ${CC} -I${TESTROOT}/include  foo.c -dynamiclib -o $$PWD/libbar.dylib
+       ${CC} -I${TESTROOT}/include  foo.c -dynamiclib -o libbar.dylib
 
 libbar_debug.dylib : foo.c
-       ${CC} -I${TESTROOT}/include  foo.c -dynamiclib  -DDEBUG -o $$PWD/libbar_debug.dylib 
+       ${CC} -I${TESTROOT}/include  foo.c -dynamiclib  -DDEBUG -o libbar_debug.dylib 
 
 hide/libbar.dylib : foo.c
-       mkdir -p $$PWD/hide
-       ${CC} -I${TESTROOT}/include  foo.c -dynamiclib  -o $$PWD/hide/libbar.dylib -install_name $$PWD/libbar.dylib
+       mkdir -p $(PWD)/hide
+       ${CC} -I${TESTROOT}/include  foo.c -dynamiclib  -o hide/libbar.dylib -install_name $(PWD)/libbar.dylib
 
 hide/libbar_debug.dylib : foo.c
-       mkdir -p $$PWD/hide
-       ${CC} -I${TESTROOT}/include  foo.c -dynamiclib  -o $$PWD/hide/libbar_debug.dylib -install_name $$PWD/libbar_debug.dylib
+       mkdir -p $(PWD)/hide
+       ${CC} -I${TESTROOT}/include  foo.c -dynamiclib  -o hide/libbar_debug.dylib -install_name $(PWD)/libbar_debug.dylib
 
 clean:
        rm -rf libfoo.dylib libfoo_debug.dylib hide libbar.dylib libbar_debug.dylib main1 main2 main3 main4 main5 main6 main7 main8
@@ -70,9 +75,9 @@ clean:
 main1 : main.c libfoo.dylib
        ${CC} -Wno-deprecated-declarations -I${TESTROOT}/include  main.c -o main1 libfoo.dylib
 
-check1:        main1
+check1:        
        DYLD_IMAGE_SUFFIX=_debug && export DYLD_IMAGE_SUFFIX && ./main1 libfoo.dylib
-       DYLD_IMAGE_SUFFIX=_debug && export DYLD_IMAGE_SUFFIX && ./main1 $$PWD/libfoo.dylib
+       DYLD_IMAGE_SUFFIX=_debug && export DYLD_IMAGE_SUFFIX && ./main1 $(PWD)/libfoo.dylib
 
 
 #
@@ -81,11 +86,11 @@ check1:     main1
 main2 : main.c libfoo_debug.dylib
        ${CC} -Wno-deprecated-declarations -I${TESTROOT}/include  main.c -o main2 libfoo_debug.dylib
 
-check2:        main2
+check2:        
        echo "pwd-1 is ${PWD}"
-       echo "pwd-2 is $$PWD"
+       echo "pwd-2 is $(PWD)"
        pwd
-       ./main2 $$PWD/libfoo.dylib
+       ./main2 $(PWD)/libfoo.dylib
 
 
 #
@@ -94,8 +99,8 @@ check2:       main2
 main3 : main.c libfoo.dylib
        ${CC} -Wno-deprecated-declarations -Wno-deprecated-declarations -I${TESTROOT}/include  main.c -o main3 libfoo.dylib
 
-check3:        main3
-       DYLD_LIBRARY_PATH=$$PWD/hide && export DYLD_LIBRARY_PATH && ./main3 $$PWD/libfoo.dylib
+check3:        
+       DYLD_LIBRARY_PATH=$(PWD)/hide && export DYLD_LIBRARY_PATH && ./main3 $(PWD)/libfoo.dylib
 
 
 #
@@ -105,8 +110,8 @@ check3:     main3
 main4 : main.c libfoo.dylib
        ${CC} -Wno-deprecated-declarations -I${TESTROOT}/include  main.c -o main4 libfoo.dylib
 
-check4:        main4
-       DYLD_LIBRARY_PATH=$$PWD/hide && export DYLD_LIBRARY_PATH && DYLD_IMAGE_SUFFIX=_debug && export DYLD_IMAGE_SUFFIX && ./main4 $$PWD/libfoo.dylib
+check4:        
+       DYLD_LIBRARY_PATH=$(PWD)/hide && export DYLD_LIBRARY_PATH && DYLD_IMAGE_SUFFIX=_debug && export DYLD_IMAGE_SUFFIX && ./main4 $(PWD)/libfoo.dylib
 
 
 #
@@ -116,8 +121,8 @@ check4:     main4
 main5 : main.c libbar.dylib libbar_debug.dylib
        ${CC} -Wno-deprecated-declarations -I${TESTROOT}/include  main.c -o main5 libbar.dylib
 
-check5:        main5
-       DYLD_IMAGE_SUFFIX=_debug && export DYLD_IMAGE_SUFFIX && ./main5 $$PWD/libbar.dylib
+check5:        
+       DYLD_IMAGE_SUFFIX=_debug && export DYLD_IMAGE_SUFFIX && ./main5 $(PWD)/libbar.dylib
 
 
 #
@@ -127,8 +132,8 @@ check5:     main5
 main6 : main.c libbar_debug.dylib
        ${CC} -Wno-deprecated-declarations -I${TESTROOT}/include  main.c -o main6 libbar_debug.dylib
 
-check6:        main6
-        DYLD_IMAGE_SUFFIX=_debug && export DYLD_IMAGE_SUFFIX && ./main6 $$PWD/libbar.dylib
+check6:        
+        DYLD_IMAGE_SUFFIX=_debug && export DYLD_IMAGE_SUFFIX && ./main6 $(PWD)/libbar.dylib
 
 
 #
@@ -137,8 +142,8 @@ check6:     main6
 main7 : main.c libbar.dylib
        ${CC} -Wno-deprecated-declarations -I${TESTROOT}/include  main.c -o main7 libbar.dylib
 
-check7:        main7
-       DYLD_LIBRARY_PATH=$$PWD/hide && export DYLD_LIBRARY_PATH && ./main7 $$PWD/libbar.dylib
+check7:        
+       DYLD_LIBRARY_PATH=$(PWD)/hide && export DYLD_LIBRARY_PATH && ./main7 $(PWD)/libbar.dylib
 
 
 #
@@ -148,5 +153,5 @@ check7:     main7
 main8 : main.c libbar.dylib
        ${CC} -Wno-deprecated-declarations -I${TESTROOT}/include  main.c -o main8 libbar.dylib
 
-check8:        main8
-       DYLD_LIBRARY_PATH=$$PWD/hide && export DYLD_LIBRARY_PATH && DYLD_IMAGE_SUFFIX=_debug && export DYLD_IMAGE_SUFFIX && ./main8 $$PWD/libbar.dylib
+check8:        
+       DYLD_LIBRARY_PATH=$(PWD)/hide && export DYLD_LIBRARY_PATH && DYLD_IMAGE_SUFFIX=_debug && export DYLD_IMAGE_SUFFIX && ./main8 $(PWD)/libbar.dylib
diff --git a/unit-tests/test-cases/image_path_containing_address/Makefile b/unit-tests/test-cases/image_path_containing_address/Makefile
new file mode 100644 (file)
index 0000000..a9c79c1
--- /dev/null
@@ -0,0 +1,38 @@
+##
+# 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} foo.c -dynamiclib -o libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libfoo.dylib
+       
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libfoo.dylib
+
diff --git a/unit-tests/test-cases/image_path_containing_address/foo.c b/unit-tests/test-cases/image_path_containing_address/foo.c
new file mode 100644 (file)
index 0000000..85e6cd8
--- /dev/null
@@ -0,0 +1 @@
+void foo() {}
diff --git a/unit-tests/test-cases/image_path_containing_address/main.c b/unit-tests/test-cases/image_path_containing_address/main.c
new file mode 100644 (file)
index 0000000..2025b1d
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2005-2008 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 <string.h> 
+#include <dlfcn.h> 
+#include <mach-o/dyld.h> 
+#include <mach-o/dyld_priv.h> 
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+extern void foo();
+
+
+// checks dladdr() and dyld_image_path_containing_address() return same path
+static void verify(void* addr)
+{
+       Dl_info info;
+       if ( dladdr(addr, &info) == 0 ) {
+               FAIL("dladdr(%p, xx) failed", addr);
+               exit(0);
+       }
+       const char* path = dyld_image_path_containing_address(addr);
+       if ( path != info.dli_fname ) {
+               FAIL("dladdr's  dli_fname != dyld_image_path_containing_address()");
+               exit(0);
+       }
+}
+
+
+int main()
+{
+       verify(&main);
+       verify(&foo);
+       
+       int x;
+       if ( dyld_image_path_containing_address(&x) != NULL ) {
+               FAIL("dyld_image_path_containing_address() of stack variable not NULL");
+               exit(0);
+       }
+  
+       PASS("image_path_containing_address");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/init-libSystem-first/Makefile b/unit-tests/test-cases/init-libSystem-first/Makefile
new file mode 100644 (file)
index 0000000..67424c7
--- /dev/null
@@ -0,0 +1,43 @@
+##
+# Copyright (c) 2008 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 -o main main.c  libfoo.dylib
+
+libfoo.dylib: foo.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib foo.c -nostdlib -ldylib1.o -flat_namespace -undefined suppress -o libfoo.dylib 
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main  libfoo.dylib
+       
diff --git a/unit-tests/test-cases/init-libSystem-first/foo.c b/unit-tests/test-cases/init-libSystem-first/foo.c
new file mode 100644 (file)
index 0000000..1affc43
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2008 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>
+
+
+extern char***  _NSGetArgv(void);
+static bool libSystemAlreadyInited = false;
+
+
+
+// 
+static __attribute__((constructor)) void myInit() 
+{
+       libSystemAlreadyInited = ( _NSGetArgv() != NULL );
+}
+
+
+
+bool foo()
+{
+       return libSystemAlreadyInited;
+}
diff --git a/unit-tests/test-cases/init-libSystem-first/main.c b/unit-tests/test-cases/init-libSystem-first/main.c
new file mode 100644 (file)
index 0000000..28a4db3
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <stdbool.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+extern bool foo();
+
+int main()
+{
+       if ( foo() )
+               PASS("init-libSystem-first");
+       else
+               FAIL("init-libSystem-first");
+               
+       return EXIT_SUCCESS;
+}
+
+
index dfa47dd6b63ebc7edebbaac67d485fa58319a122..6525dc6bdc37ea4319a777dea71b483158f11bb3 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main
index 1afdb745fcdfc68154b13a014987619c7ebe958a..3f4e4d0bb65a059ca71a2b472adc6144b3410797 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main arg1 arg2
 
 all:
diff --git a/unit-tests/test-cases/insert-libraries-weak-symbols/Makefile b/unit-tests/test-cases/insert-libraries-weak-symbols/Makefile
new file mode 100644 (file)
index 0000000..be551ef
--- /dev/null
@@ -0,0 +1,49 @@
+##
+# 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
+
+#
+# verifies that weak symbols in inserted libraries work
+#
+
+
+all-check: all check
+
+check:
+       export DYLD_INSERT_LIBRARIES=libinsert.dylib && ./main
+       
+all: main libinsert.dylib
+
+
+main: main.c 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c  
+
+
+libinsert.dylib: insert.c 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib  -o libinsert.dylib  insert.c  
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main  lib*.dylib
+       
diff --git a/unit-tests/test-cases/insert-libraries-weak-symbols/insert.c b/unit-tests/test-cases/insert-libraries-weak-symbols/insert.c
new file mode 100644 (file)
index 0000000..9bfcca7
--- /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>
+
+
+void __attribute__((weak)) foo()
+{
+
+}
+
+
+static __attribute__((constructor)) void init() 
+{
+       // have intializer call weak function
+       foo();
+}
+
diff --git a/unit-tests/test-cases/insert-libraries-weak-symbols/main.c b/unit-tests/test-cases/insert-libraries-weak-symbols/main.c
new file mode 100644 (file)
index 0000000..8593697
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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 "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+// since both main and insert.dylib have a weak _foo,
+// dyld will coalesce.
+void __attribute__((weak)) foo()
+{
+
+}
+
+
+int main()
+{
+       PASS("insert-libraries-weak-symbols");
+       return EXIT_SUCCESS;
+}
+
index f4ae30ace4523fd3cad2194039a4dd5d537d5221..fc9269f7dc1050db953b4a2b334ba308f345cb40 100644 (file)
@@ -29,7 +29,9 @@ include ${TESTROOT}/include/common.makefile
 #
 
 
-run: all
+all-check: all check
+
+check:
        export DYLD_INSERT_LIBRARIES=libinsert.dylib && ./main
 
 all: main libinsert.dylib
index 7e6ad2ab1d58314b7f0cd73148b6b4134e2edc2d..1380ba99c43451bbf5e3effdd0bb813cbdeb1169 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        export DYLD_INSERT_LIBRARIES="/usr/lib/libldap.dylib:/usr/lib/libpcap.dylib" && ./main
 
 all: main
index 5c35a899a0d30550642d62c036746d7f357b8b24..c98a29b9cb4632f728b31bdd90f8e2e2fa98fa15 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        export DYLD_INSERT_LIBRARIES="libmystrdup.dylib" && ./main
 
 all: main libmystrdup.dylib
index 0bd0312a49d286c8efb39d259c742df793f1dd9a..1ea53853d02e982a625cf597d514ca95b76728e9 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        export DYLD_INSERT_LIBRARIES="libmystrdup.dylib" && ./main
 
 all: main libmystrdup.dylib
index dd89247e877d7c6538565476f02fab66f322bdd5..2920a5c96bd794004838272d2b7f1697ff803434 100644 (file)
@@ -36,7 +36,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        export DYLD_INSERT_LIBRARIES="libfoo1.dylib:libfoo2.dylib:libfoo3.dylib" && ./main
 
 all: main libfoo1.dylib libfoo2.dylib libfoo3.dylib
index 9b9ae730d6bd01c44a14c7d3523bba17e0324f39..33e6b2a067261daf2bf3647c8cdc0e225f627f91 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        export DYLD_INSERT_LIBRARIES="libmyfree.dylib" && ./main
 
 all: main libmyfree.dylib
diff --git a/unit-tests/test-cases/interpose-shared-cache/Makefile b/unit-tests/test-cases/interpose-shared-cache/Makefile
new file mode 100644 (file)
index 0000000..c1cb7dd
--- /dev/null
@@ -0,0 +1,43 @@
+##
+# Copyright (c) 2005-2008 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:
+       export DYLD_INSERT_LIBRARIES="libmymalloc.dylib" && ./main
+
+all: main libmymalloc.dylib
+
+main : main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+
+libmymalloc.dylib : mymalloc.c
+       ${CC} ${CCFLAGS} -dynamiclib mymalloc.c -o libmymalloc.dylib
+
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libmymalloc.dylib
+
diff --git a/unit-tests/test-cases/interpose-shared-cache/main.c b/unit-tests/test-cases/interpose-shared-cache/main.c
new file mode 100644 (file)
index 0000000..192b3b6
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2005-2008 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 "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+int main()
+{
+       const char* x = strdup("123");
+  
+       if ( (strcmp(&x[-16], "hello") == 0) )
+               PASS("interpose-basic-shared-cache");
+       else
+               FAIL("interpose-basic-shared-cache");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/interpose-shared-cache/mymalloc.c b/unit-tests/test-cases/interpose-shared-cache/mymalloc.c
new file mode 100644 (file)
index 0000000..9afe7f1
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2005-2008 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 <string.h>
+#include <mach-o/dyld-interposing.h>
+
+// return blocks that have preceeding 16-bytes filled with "hello"
+void* my_malloc(size_t size)
+{
+       char* x = malloc(size+16);
+       strcpy(x, "hello");
+       return &x[16];
+}
+
+DYLD_INTERPOSE(my_malloc, malloc)
index 04d3fb6caeacac24a368b25e01202a75182e104d..e21b78421af9e0f83dbeacb49509583bd7a747d4 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main libfoo.dylib
index abb48395b09b2a4cb1995131daced2a9d14e7cf9..273748c4439f6a9b7013566faaecabdedfa7ebc2 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main
index 558fc57d0d082c9c99aacf17ede7fb4eb7315e6e..73ce20331fb3418dc90e2d8f68b562a173eab2a8 100644 (file)
@@ -45,7 +45,9 @@ endif
 
 
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main 
index 7270f66c7ed606b705d0b0587192d969972258b8..e2683b39843394f71d6cfe023021f47649e5382d 100644 (file)
@@ -77,6 +77,9 @@ bool dofloattest(double p1, double p2, double p3, double p4, double p5, double p
 #endif
 
 
+
+#if __i386__ || __x86_64__ || __ppc__ || __ppc64__
+
 static bool comparevFloat(vFloat p1, vFloat p2)
 {
        return (memcmp(&p1, &p2, 16) == 0);
@@ -103,6 +106,8 @@ bool dovectortest(vFloat p1, vFloat p2, vFloat p3, vFloat p4, vFloat p5)
        return true;
 }
 
+#endif
+
 
 
 
index 007f11de7a670fa5438893b2683e47cdb3854358..8b76407db6391c65902eb556d865f7c190149ed0 100644 (file)
@@ -12,11 +12,14 @@ extern bool dofloattest(double,double,double,double,double,double,double,double,
 #endif
 
 
-#if __i386__ || __x86_64__
-       typedef float               vFloat  __attribute__ ((__vector_size__ (16)));
-#elif __ppc__ || __ppc64__
-       typedef __vector float          vFloat;
-#endif
+#if __i386__ || __x86_64__ || __ppc__ || __ppc64__
+
+       #if __i386__ || __x86_64__
+               typedef float               vFloat  __attribute__ ((__vector_size__ (16)));
+       #elif __ppc__ || __ppc64__
+               typedef __vector float          vFloat;
+       #endif
 
-extern bool dovectortest(vFloat, vFloat, vFloat, vFloat, vFloat);
+       extern bool dovectortest(vFloat, vFloat, vFloat, vFloat, vFloat);
 
+#endif
\ No newline at end of file
index 44c98b2eee139c8509639cc24ec729b2f90b6d9f..fc66bd17af1b50963ee77352f497f7f1ffa43ba3 100644 (file)
@@ -48,13 +48,14 @@ static bool floattest()
 {
 #if __ppc__ || __ppc64__
        return dofloattest(1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0);
-#elif __i386__ || __x86_64__ 
+#elif __i386__ || __x86_64__ || __arm__
        return true;
 #else
-       #error unknown architecture
+       #error unknown arch
 #endif
 }
 
+#if __i386__ || __x86_64__ || __ppc__ || __ppc64__
 static bool vectorSupport()
 {
 #if __ppc__
@@ -68,7 +69,6 @@ static bool vectorSupport()
 #endif
 }
 
-
 static bool vectortest()
 {
        vFloat p1 = { 1.1, 1.2, 1.3, 1.4 };
@@ -78,6 +78,7 @@ static bool vectortest()
        vFloat p5 = { 5.1, 5.2, 5.3, 5.4 };
        return dovectortest(p1, p2, p3, p4, p5);
 }
+#endif
 
 int main()
 {
@@ -91,11 +92,13 @@ int main()
                return EXIT_SUCCESS;
        }
 
+#if __i386__ || __x86_64__ || __ppc__ || __ppc64__
        if ( vectorSupport() && ! vectortest() ) {
                FAIL("lazy-binding-reg-params vector parameters");
                return EXIT_SUCCESS;
        }
-               
+#endif
+
        PASS("lazy-binding-reg-params");
        return EXIT_SUCCESS;
 }
diff --git a/unit-tests/test-cases/lazy-dylib-init-order/Makefile b/unit-tests/test-cases/lazy-dylib-init-order/Makefile
new file mode 100644 (file)
index 0000000..f3e0ed5
--- /dev/null
@@ -0,0 +1,42 @@
+##
+# Copyright (c) 2008 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 that a lazy loaded dylib has initializers run in correct order
+#
+
+all-check: all check
+
+check:
+       ./main > actual.out
+       ${PASS_IFF} diff expected.out actual.out
+
+all:
+       ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib
+       ${CC} ${CCFLAGS} main.c -Wl,-lazy_library,libfoo.dylib -o main
+
+
+clean:
+       rm -f libfoo.dylib main actual.out
diff --git a/unit-tests/test-cases/lazy-dylib-init-order/expected.out b/unit-tests/test-cases/lazy-dylib-init-order/expected.out
new file mode 100644 (file)
index 0000000..3302190
--- /dev/null
@@ -0,0 +1,6 @@
+main_init
+main
+foo_init
+foo
+foo_term
+main_term
diff --git a/unit-tests/test-cases/lazy-dylib-init-order/foo.c b/unit-tests/test-cases/lazy-dylib-init-order/foo.c
new file mode 100644 (file)
index 0000000..1047dce
--- /dev/null
@@ -0,0 +1,21 @@
+
+#include <stdio.h>
+
+int foo() 
+{ 
+    printf("foo\n");
+    return 1; 
+}
+int bar() { return 1; }
+
+
+static __attribute__((constructor)) void foo_init()
+{
+    printf("foo_init\n");
+}
+
+static __attribute__((destructor)) void foo_term()
+{
+    printf("foo_term\n");
+}
+
diff --git a/unit-tests/test-cases/lazy-dylib-init-order/main.c b/unit-tests/test-cases/lazy-dylib-init-order/main.c
new file mode 100644 (file)
index 0000000..06b33ce
--- /dev/null
@@ -0,0 +1,25 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+
+extern int foo();
+extern int bar();
+
+static __attribute__((constructor)) void main_init()
+{
+    printf("main_init\n");
+}
+
+static __attribute__((destructor)) void main_term()
+{
+    printf("main_term\n");
+}
+
+
+int main()
+{
+    printf("main\n");
+       foo();
+       return 0;
+}
+
diff --git a/unit-tests/test-cases/lazy-dylib-missing-dylib/Makefile b/unit-tests/test-cases/lazy-dylib-missing-dylib/Makefile
new file mode 100644 (file)
index 0000000..4cddd76
--- /dev/null
@@ -0,0 +1,43 @@
+##
+# Copyright (c) 2008 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 that a lazy loaded dylib that can't be found errors out cleanly
+#
+
+all-check: all check
+
+check:
+       ./main
+       ./main2
+
+all:
+       ${CC} ${CCFLAGS} foo.c -DBAR=1 -dynamiclib -o libfoo.dylib.full -install_name libfoo.dylib
+       ${CC} ${CCFLAGS} main.c -I${TESTROOT}/include  -Wl,-lazy_library,libfoo.dylib.full -o main
+       ${CC} ${CCFLAGS} main.c -I${TESTROOT}/include -DLAZY_HANDLER=1 -Wl,-lazy_library,libfoo.dylib.full -o main2
+
+
+clean:
+       rm -f libfoo.dylib.full main main2
diff --git a/unit-tests/test-cases/lazy-dylib-missing-dylib/foo.c b/unit-tests/test-cases/lazy-dylib-missing-dylib/foo.c
new file mode 100644 (file)
index 0000000..f41dbba
--- /dev/null
@@ -0,0 +1,6 @@
+
+
+int foo() 
+{ 
+    return 1; 
+}
diff --git a/unit-tests/test-cases/lazy-dylib-missing-dylib/main.c b/unit-tests/test-cases/lazy-dylib-missing-dylib/main.c
new file mode 100644 (file)
index 0000000..9ff0032
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2008 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 "test.h"
+
+
+#if LAZY_HANDLER
+// If a linkage unit defines dyld_lazy_dylib_proxy()
+// then when binding lazy symbols, if one 
+// cannot be bound, it is bound to this function
+// instead.
+int dyld_lazy_dylib_proxy()
+{
+       return 7;
+}
+#endif
+
+
+extern int foo();      // should not exist
+
+int main()
+{
+#if LAZY_HANDLER
+       // sanity check that foo was not found
+       // dyld_lazy_dylib_proxy returns 7 when function cannot be found
+       if ( foo() != 7 ) {
+               FAIL("lazy-dylib-missing-dylib: dyld_lazy_dylib_proxy() not used for foo");
+               return 0;
+       }
+#else
+       // sanity check that foo was not found
+       // lazy loading return 0 when function cannot be found
+       if ( foo() != 0 ) {
+               FAIL("lazy-dylib-missing-dylib: foo found");
+               return 0;
+       }
+#endif
+       PASS("lazy-dylib-missing-dylib");
+       return 0;
+}
+
diff --git a/unit-tests/test-cases/lazy-dylib-missing-symbol/Makefile b/unit-tests/test-cases/lazy-dylib-missing-symbol/Makefile
new file mode 100644 (file)
index 0000000..cd631ce
--- /dev/null
@@ -0,0 +1,44 @@
+##
+# Copyright (c) 2008 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 that a lazy loaded dylib has initializers run in correct order
+#
+
+all-check: all check
+
+check:
+       ./main
+       ./main2
+
+all:
+       ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib -install_name libfoo.dylib
+       ${CC} ${CCFLAGS} foo.c -DBAR=1 -dynamiclib -o libfoo.dylib.full -install_name libfoo.dylib
+       ${CC} ${CCFLAGS} main.c -I${TESTROOT}/include  -Wl,-lazy_library,libfoo.dylib.full -o main
+       ${CC} ${CCFLAGS} main.c -I${TESTROOT}/include -DLAZY_HANDLER=1 -Wl,-lazy_library,libfoo.dylib.full -o main2
+
+
+clean:
+       rm -f libfoo.dylib libfoo.dylib.full main main2
diff --git a/unit-tests/test-cases/lazy-dylib-missing-symbol/foo.c b/unit-tests/test-cases/lazy-dylib-missing-symbol/foo.c
new file mode 100644 (file)
index 0000000..2c56b39
--- /dev/null
@@ -0,0 +1,15 @@
+
+
+int foo() 
+{ 
+    return 1; 
+}
+
+#if BAR
+int bar() 
+{ 
+       return 1; 
+}
+#endif
+
+
diff --git a/unit-tests/test-cases/lazy-dylib-missing-symbol/main.c b/unit-tests/test-cases/lazy-dylib-missing-symbol/main.c
new file mode 100644 (file)
index 0000000..934e48a
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2008 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 "test.h"
+
+
+#if LAZY_HANDLER
+// If a linkage unit defines dyld_lazy_dylib_proxy()
+// then when binding lazy symbols, if one 
+// cannot be bound, it is bound to this function
+// instead.
+int dyld_lazy_dylib_proxy()
+{
+       return 7;
+}
+#endif
+
+
+extern int foo();      // should exist
+extern int bar();      // should not exist
+
+int main()
+{
+       // sanity check that foo was found
+       if ( foo() != 1 ) {
+               FAIL("lazy-dylib-missing-symbol: foo not found");
+               return 0;
+       }
+       
+#if LAZY_HANDLER
+       // sanity check that bar was not found
+       // lazy loading return 7 when function cannot be found
+       if ( bar() != 7 ) {
+               FAIL("lazy-dylib-missing-symbol: dyld_lazy_dylib_proxy() not used for bar");
+               return 0;
+       }
+#else
+       // sanity check that bar was not found
+       // lazy loading return 0 when function cannot be found
+       if ( bar() != 0 ) {
+               FAIL("lazy-dylib-missing-symbol: bar found");
+               return 0;
+       }
+#endif
+       PASS("lazy-dylib-missing-symbol");
+       return 0;
+}
+
index 9a7f756349e104afaa211b0449d76ceacee68a6a..6d42f96c378b44af5c6e9670ae7f70e5fb4edea1 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main 
index 52c2e502d68c7f6078521e2bea4c08cef263513b..c5a211f3153975caaedc167741bc62de35c2696e 100644 (file)
@@ -35,24 +35,25 @@ include ${TESTROOT}/include/common.makefile
 
 PWD = `pwd`
 
+all-check: all check
 
-run : all
+check:
        # verify it runs as-is
        ./main
        # verify dyld doesn't hang on the circularity
        DYLD_LIBRARY_PATH=$(PWD) && export DYLD_LIBRARY_PATH && ${TESTROOT}/bin/exit-zero-pass.pl "lib-name-overload" "lib-name-overload" ./main
 
-all : main 
+all: main 
 
 other/libfoo.dylib : foo2.c
        mkdir -p other
-       gcc foo2.c -dynamiclib  -o $(PWD)/other/libfoo.dylib 
+       ${CC} foo2.c -dynamiclib  -o $(PWD)/other/libfoo.dylib 
 
 libfoo.dylib : foo.c other/libfoo.dylib
-       gcc foo.c -dynamiclib $(PWD)/other/libfoo.dylib -sub_library libfoo -o $(PWD)/libfoo.dylib 
+       ${CC} foo.c -dynamiclib $(PWD)/other/libfoo.dylib -sub_library libfoo -o $(PWD)/libfoo.dylib 
 
 main : main.c libfoo.dylib
-       gcc main.c -I${TESTROOT}/include -o main libfoo.dylib
+       ${CC} main.c -I${TESTROOT}/include -o main libfoo.dylib
 
        
 clean:
index a89a431dae40743f6d624dc55737f29fa09c57e8..61d36e4a9c0cdf9986295a0a45b283009fbc8fac 100644 (file)
@@ -23,6 +23,8 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
+PWD = $(shell pwd)
+
 ### 
 ### This test case is to verify that two different dylibs with the same name  
 ### and each loaded via the same @loader_path does not confuse dyld
@@ -32,14 +34,16 @@ include ${TESTROOT}/include/common.makefile
 ## Note, until ld understands @loader_path we have to do a funky make
 
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main
 
 foo/libfoo.dylib : foo.c foo/libbase.dylib
        mkdir -p foo
-       ${CC} foo.c foo/libbase.dylib -dynamiclib -o "`pwd`/foo/libfoo.dylib" 
+       ${CC} foo.c foo/libbase.dylib -dynamiclib -o "${PWD}/foo/libfoo.dylib" 
        
 foo/libbase.dylib : base.c 
        mkdir -p foo
@@ -48,7 +52,7 @@ foo/libbase.dylib : base.c
 
 bar/libbar.dylib : bar.c bar/libbase.dylib
        mkdir -p bar
-       ${CC} bar.c bar/libbase.dylib -dynamiclib -o "`pwd`/bar/libbar.dylib" 
+       ${CC} bar.c bar/libbase.dylib -dynamiclib -o "${PWD}/bar/libbar.dylib" 
        
 bar/libbase.dylib : base.c 
        mkdir -p bar
index 694cd9d678b99cc85f971576ad5b519e2c7ed996..7e646d1cea5e8735742f218f5b62c1453d671ab0 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main
index 4cfeb686a053458c18501d418652c4f93bd2d7d9..217074c34dc1bee88508cf43ffa5f0b4968be78a 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        export DYLD_FALLBACK_FRAMEWORK_PATH="dir" && ${TESTROOT}/bin/exit-zero-pass.pl "pass message" "fail message" ./main
 
 all: main dir/Foo.framework/Versions/Current/Foo
diff --git a/unit-tests/test-cases/non-lazy-slide/Makefile b/unit-tests/test-cases/non-lazy-slide/Makefile
new file mode 100644 (file)
index 0000000..2cf9c9a
--- /dev/null
@@ -0,0 +1,43 @@
+##
+# Copyright (c) 2008 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 libfoo.dylib
+
+main : main.c libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libfoo.dylib
+
+libfoo.dylib : foo.c bar.c
+       ${CC} ${CCFLAGS} -dynamiclib foo.c bar.c -o libfoo.dylib
+
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libfoo.dylib
+
diff --git a/unit-tests/test-cases/non-lazy-slide/bar.c b/unit-tests/test-cases/non-lazy-slide/bar.c
new file mode 100644 (file)
index 0000000..fa8deff
--- /dev/null
@@ -0,0 +1,3 @@
+
+
+int bar = 10;
diff --git a/unit-tests/test-cases/non-lazy-slide/foo.c b/unit-tests/test-cases/non-lazy-slide/foo.c
new file mode 100644 (file)
index 0000000..1b2c9f7
--- /dev/null
@@ -0,0 +1,7 @@
+
+extern int bar;
+
+int foo()
+{
+       return bar;
+}
diff --git a/unit-tests/test-cases/non-lazy-slide/main.c b/unit-tests/test-cases/non-lazy-slide/main.c
new file mode 100644 (file)
index 0000000..a73a1db
--- /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()
+
+// libfoo.dylib is built from multiple source files
+// It internally uses non-lazy pointer to compute
+// the result for foo()
+
+
+extern int foo();
+
+int main()
+{
+       if ( foo() == 10 )
+               PASS("non-lazy-slide");
+       else
+               FAIL("non-lazy-slide");
+       return EXIT_SUCCESS;
+}
+
+
diff --git a/unit-tests/test-cases/non-lazy-weak/Makefile b/unit-tests/test-cases/non-lazy-weak/Makefile
new file mode 100644 (file)
index 0000000..2cf9c9a
--- /dev/null
@@ -0,0 +1,43 @@
+##
+# Copyright (c) 2008 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 libfoo.dylib
+
+main : main.c libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libfoo.dylib
+
+libfoo.dylib : foo.c bar.c
+       ${CC} ${CCFLAGS} -dynamiclib foo.c bar.c -o libfoo.dylib
+
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libfoo.dylib
+
diff --git a/unit-tests/test-cases/non-lazy-weak/bar.c b/unit-tests/test-cases/non-lazy-weak/bar.c
new file mode 100644 (file)
index 0000000..91a216d
--- /dev/null
@@ -0,0 +1,3 @@
+
+
+__attribute__((weak)) int bar = 10;
diff --git a/unit-tests/test-cases/non-lazy-weak/foo.c b/unit-tests/test-cases/non-lazy-weak/foo.c
new file mode 100644 (file)
index 0000000..1b2c9f7
--- /dev/null
@@ -0,0 +1,7 @@
+
+extern int bar;
+
+int foo()
+{
+       return bar;
+}
diff --git a/unit-tests/test-cases/non-lazy-weak/main.c b/unit-tests/test-cases/non-lazy-weak/main.c
new file mode 100644 (file)
index 0000000..16a78b7
--- /dev/null
@@ -0,0 +1,20 @@
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <dlfcn.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+// libfoo.dylib has a weak global variable that foo() returns
+
+extern int foo();
+
+int main()
+{
+       if ( foo() == 10 )
+               PASS("non-lazy-weak");
+       else
+               FAIL("non-lazy-weak");
+       return EXIT_SUCCESS;
+}
+
+
index 2c49d4f69163ebb9aad22294549c01e379f1594f..540909d1329306c7bcb122856ca873205a8697c9 100644 (file)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2005-2008 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        cd absent/  && ../${TESTROOT}/bin/exit-non-zero-pass.pl "non-weak-library" "non-weak-library" ./main
        cd present/ && ./main
 
 all: foo.c main.c
        ${CC} -dynamiclib -prebind -seg1addr 400000 -o libfoo.dylib foo.c
        mkdir -p absent/
-       export MACOSX_DEPLOYMENT_TARGET=10.2 && ${CC} -prebind -I${TESTROOT}/include -L. -lfoo -DLIB_ABSENT  -o absent/main  main.c
+       ${CC} -prebind -I${TESTROOT}/include -L. -lfoo -DLIB_ABSENT  -o absent/main  main.c
        mkdir -p present/
-       export MACOSX_DEPLOYMENT_TARGET=10.2 && ${CC} -prebind -I${TESTROOT}/include -L. -lfoo -DLIB_PRESENT -o present/main main.c
+       ${CC} -prebind -I${TESTROOT}/include -L. -lfoo -DLIB_PRESENT -o present/main main.c
        mv libfoo.dylib present/
 
 clean:
diff --git a/unit-tests/test-cases/operator-new-dylib/Makefile b/unit-tests/test-cases/operator-new-dylib/Makefile
new file mode 100644 (file)
index 0000000..fbaac19
--- /dev/null
@@ -0,0 +1,33 @@
+
+
+
+
+#
+# test that if the main executable overrides operator new
+# that a dylib using operator new is redirected to it.
+#
+#
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+all-check: all check
+
+check:
+       ./main
+
+all: main
+
+
+main: main.cxx libfoo.dylib
+       ${CXX} ${CXXFLAGS} -I${TESTROOT}/include -o main main.cxx libfoo.dylib 
+
+libfoo.dylib: foo.cxx
+       ${CXX} ${CXXFLAGS} -dynamiclib foo.cxx -o libfoo.dylib
+
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main  libfoo.dylib
+
diff --git a/unit-tests/test-cases/operator-new-dylib/foo.cxx b/unit-tests/test-cases/operator-new-dylib/foo.cxx
new file mode 100644 (file)
index 0000000..f91f88c
--- /dev/null
@@ -0,0 +1,13 @@
+
+#include <stdlib.h>
+#include <new>
+
+
+
+
+
+char* foo()
+{
+       return new char[24];
+}
+
diff --git a/unit-tests/test-cases/operator-new-dylib/main.cxx b/unit-tests/test-cases/operator-new-dylib/main.cxx
new file mode 100644 (file)
index 0000000..25be30d
--- /dev/null
@@ -0,0 +1,31 @@
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+#include <stdlib.h>
+#include <new>
+
+
+extern char* foo();
+
+static char all[] = "hello";
+
+void* operator new[](std::size_t) throw (std::bad_alloc)
+{
+       return all;
+}
+
+
+int main()
+{
+       char* newArray = new char[24];
+       char* fromFoo = foo();
+       
+       if ( fromFoo == newArray )
+               PASS("operator-new-dylib");
+       else
+               FAIL("operator-new-dylib");
+       return EXIT_SUCCESS;
+}
+
index fb7fe849cd3e13b018f2b1ab1e3302986345ffb5..2fbed98f8c1875fc2cd0f61735bc48922f617f26 100644 (file)
@@ -24,7 +24,9 @@ TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main
index ead5c1e4197ee0d7dda61162de31c7c3e592dae8..a0c25ce26ff64681b594efa0bd648dbf3fee9dc0 100644 (file)
@@ -52,6 +52,3 @@ int main()
        return EXIT_SUCCESS;
 }
 
-
-// add this so WEAK_DEFINES is set, so dyld searchs this image
-int __attribute__((weak)) junk = 2;
index 37a84a45563d581a97944f53d4ff189f14360091..83ef9bd125d7a324ead26aa67b387a20ff79603f 100644 (file)
@@ -32,7 +32,9 @@ include ${TESTROOT}/include/common.makefile
 ###
 
 
-run: all
+all-check: all check
+
+check:
        export DYLD_IMAGE_SUFFIX="_missing" && ${TESTROOT}/bin/exit-zero-pass.pl "partial-library-load" "partial-library-load" ./main
 
 all: main test.bundle
diff --git a/unit-tests/test-cases/pie-DYLD_NO_PIE/Makefile b/unit-tests/test-cases/pie-DYLD_NO_PIE/Makefile
new file mode 100644 (file)
index 0000000..f3fd51e
--- /dev/null
@@ -0,0 +1,34 @@
+
+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
new file mode 100644 (file)
index 0000000..3a6571d
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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 2a2f68034310358417a08fd6b05fbd7cec8b2b36..0c6c45520819c8677de47255593bc71c8c37a631 100644 (file)
@@ -25,8 +25,9 @@ include ${TESTROOT}/include/common.makefile
 
 # run a PIE four times and verify its load address was different every time
 
+all-check: all check
 
-run: main
+check:
        ./main > main.out
        ./main >> main.out
        ./main >> main.out
@@ -38,6 +39,7 @@ run: main
                echo "FAIL pie-basic"; \
        fi; \
         
+all: main
 
 main : main.c
        ${CC} ${CCFLAGS} -I${TESTROOT}/include -Wl,-pie -o main main.c -mmacosx-version-min=10.5
index 6d4d95b10ff68952286f34ef1964b0335ffb79ad..b29599453ebe700fd4fbf0dd517fad3bb6b5d7e1 100644 (file)
@@ -25,8 +25,9 @@ include ${TESTROOT}/include/common.makefile
 
 # run a PIE four times and verify its load address was different every time
 
+all-check: all check
 
-run: main
+check:
        ./main > main.out
        ./main >> main.out
        ./main >> main.out
@@ -38,6 +39,7 @@ run: main
                echo "XFAIL pie-basic"; \
        fi; \
         
+all: main
 
 main : main.c
        ${CC} ${CCFLAGS} -I${TESTROOT}/include -Wl,-pie -o main main.c -mmacosx-version-min=10.5
index 48ff01eefe458e1d14db6ac48872438153e23f62..7c68dbce08bd9da0606a75c6e7d66b32909b32ae 100644 (file)
@@ -25,8 +25,9 @@ include ${TESTROOT}/include/common.makefile
 
 # run a PIE four times and verify its load address was different every time
 
+all-check: all check
 
-run: main
+check:
        ./main > main.out
        ./main >> main.out
        ./main >> main.out
@@ -38,6 +39,7 @@ run: main
                echo "FAIL pie-custom-stack"; \
        fi; \
         
+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
diff --git a/unit-tests/test-cases/pie-dylib/Makefile b/unit-tests/test-cases/pie-dylib/Makefile
new file mode 100644 (file)
index 0000000..3b709dd
--- /dev/null
@@ -0,0 +1,41 @@
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+#  <rdar://problem/6050482> If pie, ignore preferred load address
+#
+# run a PIE four times and verify libfoo.dylib load address was different every time
+#
+
+FOO_ADDRESS = 0x10000000
+
+ifeq "x86_64" "$(ARCH)"
+       FOO_ADDRESS = 0x300000000
+endif
+
+
+all-check: all check
+
+check:
+       ./main > main.out
+       ./main >> main.out
+       ./main >> main.out
+       ./main >> main.out
+       if [ `sort main.out -u | wc -l` == 4 ]; \
+       then \
+               echo "PASS pie-dylib"; \
+       else \
+               echo "FAIL pie-dylib"; \
+       fi; \
+        
+all: main
+
+main : main.c libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -Wl,-pie libfoo.dylib -o main main.c
+
+libfoo.dylib : foo.c
+       ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib -seg1addr ${FOO_ADDRESS}
+
+clean:
+       ${RM} ${RMFLAGS} *~ main main.out libfoo.dylib
+
diff --git a/unit-tests/test-cases/pie-dylib/foo.c b/unit-tests/test-cases/pie-dylib/foo.c
new file mode 100644 (file)
index 0000000..0c9d080
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include <stdbool.h>
+
+void foo()
+{
+       printf("&foo=%p\n", &foo);
+}
diff --git a/unit-tests/test-cases/pie-dylib/main.c b/unit-tests/test-cases/pie-dylib/main.c
new file mode 100644 (file)
index 0000000..d36c9b8
--- /dev/null
@@ -0,0 +1,10 @@
+#include <stdio.h>
+#include <stdbool.h>
+
+extern void foo();
+
+int main()
+{
+       foo();
+       return 0;
+}
diff --git a/unit-tests/test-cases/pie-text-reloc/Makefile b/unit-tests/test-cases/pie-text-reloc/Makefile
new file mode 100644 (file)
index 0000000..497174e
--- /dev/null
@@ -0,0 +1,57 @@
+##
+# Copyright (c) 2007-2008 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
+
+EXTRA_OPTIONS = -mdynamic-no-pic -read_only_relocs suppress
+
+ifeq "x86_64" "$(ARCH)"
+       EXTRA_OPTIONS = 
+endif
+
+
+# run a PIE four times and verify its load address was different every time
+
+all-check: all check
+
+check:
+       ./main > main.out
+       ./main >> main.out
+       ./main >> main.out
+       ./main >> main.out
+       if [ `sort main.out -u | wc -l` == 4 ]; \
+       then \
+               echo "PASS pie-basic"; \
+       else \
+               echo "FAIL pie-basic"; \
+       fi; \
+        
+all: main
+
+main : main.c
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -Wl,-pie  $(EXTRA_OPTIONS) -o main main.c -mmacosx-version-min=10.5
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main main.out
+
diff --git a/unit-tests/test-cases/pie-text-reloc/main.c b/unit-tests/test-cases/pie-text-reloc/main.c
new file mode 100644 (file)
index 0000000..f1c8b85
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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>
+
+
+static int data=0;
+
+int main()
+{
+       printf("&data=%p\n", &data);
+       return 0;
+}
index b469f9f87d545eaceb335d6dd2b68c07a8f67711..a3edccc26df4614af2fd2cbe6c8c624bb9c1a02d 100644 (file)
@@ -35,7 +35,9 @@ endif
 
 
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main 
index b0ee016fa5c95e8031d02efed404d9f40a98f53b..5caec0648726bfc013d0776763e26382f8b09eaa 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all:
index 4bb9ecb3da9de714895ebb41c710c49bb9b4be79..a6a32429aafe5edd8c22298e93bd6230ae69c2f7 100644 (file)
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: main
+all-check: all check
+
+check:
        ./main
 
+all: main
 
 main : main.c
        ${CC} -I${TESTROOT}/include main.c -o main
index cb281834f7991279f5825e52086eaa3c4107bc2a..da9f97a06f66fbffafeae5c094879f7ca2b9dfa1 100644 (file)
@@ -30,31 +30,33 @@ PWD = `pwd`
 # Test that the 10.4 and 10.5 ways to re-export a dylib work
 #
 
-run : all
+all-check: all check
+
+check:
        ./main4
        ./main5
 
-all : main4 main5
+all: main4 main5
 
 libbar4.dylib : bar.c
-       gcc bar.c -dynamiclib -o $(PWD)/libbar4.dylib -mmacosx-version-min=10.4
+       ${CC} bar.c -dynamiclib -o $(PWD)/libbar4.dylib -mmacosx-version-min=10.4
 
 libfoo4.dylib : foo.c libbar4.dylib
-       gcc foo.c -dynamiclib libbar4.dylib -sub_library libbar4 -o $(PWD)/libfoo4.dylib -mmacosx-version-min=10.4
+       ${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
-       gcc main.c -I${TESTROOT}/include -o main4 libfoo4.dylib -mmacosx-version-min=10.4
+       ${CC} main.c -I${TESTROOT}/include -o main4 libfoo4.dylib -mmacosx-version-min=10.4
 
 
 
 libbar5.dylib : bar.c
-       gcc bar.c -dynamiclib -o $(PWD)/libbar5.dylib -mmacosx-version-min=10.5
+       ${CC} bar.c -dynamiclib -o $(PWD)/libbar5.dylib -mmacosx-version-min=10.5
 
 libfoo5.dylib : foo.c libbar5.dylib
-       gcc foo.c -dynamiclib libbar5.dylib -sub_library libbar5 -o $(PWD)/libfoo5.dylib -mmacosx-version-min=10.5
+       ${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
-       gcc main.c -I${TESTROOT}/include -o main5 libfoo5.dylib -mmacosx-version-min=10.5
+       ${CC} main.c -I${TESTROOT}/include -o main5 libfoo5.dylib -mmacosx-version-min=10.5
 
        
 clean:
index b4740538ab201a8d0c221c93e13fcd89e886ec44..7082b05d6c1ccf7c9fab92f56da779c047773fb3 100644 (file)
@@ -30,35 +30,37 @@ PWD = `pwd`
 # Test that the 10.4 and 10.5 ways to re-export a framework work
 #
 
-run : all
+all-check: all check
+
+check:
        ./main4
        ./main5
 
-all : main4 main5
+all: main4 main5
 
 Bar4.framework/Bar4 : bar.c
        mkdir -p Bar4.framework
-       gcc bar.c -dynamiclib -o $(PWD)/Bar4.framework/Bar4 -mmacosx-version-min=10.4
+       ${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
-       gcc foo.c -dynamiclib Bar4.framework/Bar4 -sub_umbrella Bar4 -o $(PWD)/Foo4.framework/Foo4 -mmacosx-version-min=10.4
+       ${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
-       gcc main.c -I${TESTROOT}/include -o main4 -framework Foo4 -F. -mmacosx-version-min=10.4
+       ${CC} main.c -I${TESTROOT}/include -o main4 -framework Foo4 -F. -mmacosx-version-min=10.4
 
 
 
 Bar5.framework/Bar5 : bar.c
        mkdir -p Bar5.framework
-       gcc bar.c -dynamiclib -o $(PWD)/Bar5.framework/Bar5 -mmacosx-version-min=10.5
+       ${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
-       gcc foo.c -dynamiclib Bar5.framework/Bar5 -sub_umbrella Bar5 -o $(PWD)/Foo5.framework/Foo5 -mmacosx-version-min=10.5
+       ${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
-       gcc main.c -I${TESTROOT}/include -o main5 -framework Foo5 -F. -mmacosx-version-min=10.5
+       ${CC} main.c -I${TESTROOT}/include -o main5 -framework Foo5 -F. -mmacosx-version-min=10.5
 
 
 
index 1b761f5b927f1efe5fc74c07c4c1554c300ea7a8..c2f76e75cec147ca3bfe4e04f5a6b5c5a7dd3887 100644 (file)
@@ -30,34 +30,36 @@ PWD = `pwd`
 # Test that the 10.4 and 10.5 ways to re-export a sub framework work
 #
 
-run : all
+all-check: all check
+
+check:
        ./main4
        ./main5
 
-all : main4 main5
+all: main4 main5
 
 Bar4.framework/Bar4 : bar.c
        mkdir -p Bar4.framework
-       gcc bar.c -dynamiclib -o $(PWD)/Bar4.framework/Bar4 -umbrella Foo4 -mmacosx-version-min=10.4
+       ${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
-       gcc foo.c -dynamiclib Bar4.framework/Bar4 -o $(PWD)/Foo4.framework/Foo4 -mmacosx-version-min=10.4
+       ${CC} foo.c -dynamiclib Bar4.framework/Bar4 -install_name $(PWD)/Foo4.framework/Foo4 -o Foo4.framework/Foo4 -mmacosx-version-min=10.4
 
 main4 : main.c Foo4.framework/Foo4
-       gcc main.c -I${TESTROOT}/include -o main4 -framework Foo4 -F. -mmacosx-version-min=10.4
+       ${CC} main.c -I${TESTROOT}/include -o main4 -framework Foo4 -F. -mmacosx-version-min=10.4
 
 
 Bar5.framework/Bar5 : bar.c
        mkdir -p Bar5.framework
-       gcc bar.c -dynamiclib -o $(PWD)/Bar5.framework/Bar5 -umbrella Foo5 -mmacosx-version-min=10.5
+       ${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
-       gcc foo.c -dynamiclib Bar5.framework/Bar5 -o $(PWD)/Foo5.framework/Foo5 -mmacosx-version-min=10.5
+       ${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
-       gcc main.c -I${TESTROOT}/include -o main5 -framework Foo5 -F. -mmacosx-version-min=10.5
+       ${CC} main.c -I${TESTROOT}/include -o main5 -framework Foo5 -F. -mmacosx-version-min=10.5
 
 
        
index efd6319747d102f05aa8fc79a08031eea326637a..5364cbdeee6d52f9b6eac4363d02d06e3991d400 100644 (file)
@@ -24,7 +24,9 @@ TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main
index 26eb70602a6616a5dd540c905727eb878b1b0312..59cf69cbeb6a9b8c1912c949d4457529cb41ca64 100644 (file)
@@ -24,7 +24,9 @@ TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
 
-run: all
+all-check: all check
+
+check:
        export DYLD_INSERT_LIBRARIES="libmymalloc.dylib" && ./main
 
 all: main libmymalloc.dylib
index c8b934604f8ccc16a4f925c39bce392afbc32cfa..e0e6bcb33054be3a28d2fadd31a96e3c51d69fef 100644 (file)
@@ -24,19 +24,20 @@ TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
 
-run: all
+all-check: all check
+
+check:
+       cp /usr/lib/libSystem.B.dylib ./libSystem.B.dylib
        export DYLD_LIBRARY_PATH=`pwd` && ./main
 
-all: main libSystem.B.dylib
+all: main 
 
 main: main.c libfoo.dylib
-       ${CC} ${CCFLAGS}  -o main main.c
+       ${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 Cocoa
+       ${CC} ${CCFLAGS} -dynamiclib -I${TESTROOT}/include -o libfoo.dylib foo.c -framework CoreFoundation
 
-libSystem.B.dylib: /usr/lib/libSystem.B.dylib
-       cp /usr/lib/libSystem.B.dylib ./libSystem.B.dylib
 
 
 clean:
index 322485e545e2382857ae71a214a1a48d84d71ee5..a5b10db460d479fd36a3ebcdda8e17884ad1374d 100644 (file)
@@ -8,8 +8,9 @@ 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 )
-               PASS("read-only-import-shared-cache-override");
+               FAIL("read-only-import-shared-cache-override");
        else
                PASS("read-only-import-shared-cache-override");
 }      
index cc404ed6337345ec7abadd2dc00f57b63e727a06..9b3996cf8b2da653d5504443c1b845c8865e88dd 100644 (file)
@@ -1,10 +1,16 @@
 #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 d3a63ab6e72d8b5dd45261f7dd463ad0e7459a6a..7e700971d1521d581403d9088ff7fc9726f28a5d 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main
index 01fc9a809a42e26230ecd2bc8cb627a2c8313d5e..c5f12e7e4194ff704e0c0b801c2b3e7eb90da788 100644 (file)
@@ -73,6 +73,8 @@ static void* getStubAddr()
        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__
+       return getsectdatafromheader(&_mh_dylib_header, "__TEXT", "__picsymbolstub4", &size) + slide;
 #else
        #error unknown arch
 #endif
index 3c3dca97da4fb3d65e45e888963e3b427992e3fa..45f6d8ff898df811df983bf1d10cfa225cfbd67b 100644 (file)
@@ -70,6 +70,8 @@ static void* getStubAddr()
        return getsectdata("__TEXT", "__picsymbolstub1", &size);
 #elif __x86_64__
        return getsectdata("__TEXT", "__symbol_stub1", &size);
+#elif __arm__
+       return getsectdata("__TEXT", "__symbol_stub4", &size);
 #else
        #error unknown arch
 #endif
@@ -89,10 +91,15 @@ static void checkStubs(void* addr)
 int main()
 {
        void* stubAddr = getStubAddr(); 
+#if __i386__
+       if ( stubAddr != NULL )
+#endif
+       {
        checkStubs(stubAddr);
        fooData = 1;
        foo();
        checkStubs(stubAddr);
+       }
        PASS("read-only-stubs");
        return EXIT_SUCCESS;
 }
diff --git a/unit-tests/test-cases/restrict-environ/Makefile b/unit-tests/test-cases/restrict-environ/Makefile
new file mode 100644 (file)
index 0000000..a383d1a
--- /dev/null
@@ -0,0 +1,38 @@
+##
+# 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:
+       export DYLD_LIBRARY_PATH=/ && export DYLD_PRINT_LIBRARIES=/ &&  export DYLD_PREBIND_DEBUG=/ && ./main
+
+all: main
+
+main: main.c
+       ${CC} ${CCFLAGS} -w -I${TESTROOT}/include -o main main.c -sectcreate __RESTRICT __restrict /dev/null
+
+clean:
+       ${RM} ${RMFLAGS} *~ main
+
diff --git a/unit-tests/test-cases/restrict-environ/main.c b/unit-tests/test-cases/restrict-environ/main.c
new file mode 100644 (file)
index 0000000..c4c0da8
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2006-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>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <string.h> // strcmp(), strncmp()
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+//
+// binaries set to run as some other user id never see any DYLD_ environment variables
+//
+
+int main(int argc, const char* argv[], const char* envp[], const char* apple[])
+{
+       // verify no DYLD_ variables
+       const char** p;
+       for(p = envp; *p != NULL; p++) {
+               //fprintf(stderr, "%s\n", *p);
+               if ( strncmp(*p, "DYLD_", 5) == 0 ) {
+                       FAIL("restrict-environ: found %s", *p);
+                       return EXIT_SUCCESS;
+               }
+       }
+       // verify same as apple parameter
+       ++p;
+       if ( apple != p ) {
+               FAIL("restrict-environ: apple parameter not at end of envp");
+               return EXIT_SUCCESS;
+       }
+       
+       // verify apple parameter is not NULL and ends in main
+       if ( *apple == NULL ) {
+               FAIL("restrict-environ: apple parameter is empty");
+               return EXIT_SUCCESS;
+       }
+       if ( strstr(*apple, "/main") == NULL ) {
+               FAIL("restrict-environ: apple parameter is not path to main");
+               return EXIT_SUCCESS;
+       }
+       
+       PASS("restrict-environ");
+       return EXIT_SUCCESS;
+}
diff --git a/unit-tests/test-cases/restrict-executable_path/Makefile b/unit-tests/test-cases/restrict-executable_path/Makefile
new file mode 100644 (file)
index 0000000..b222951
--- /dev/null
@@ -0,0 +1,71 @@
+##
+# Copyright (c) 2006-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
+
+
+#
+# Use of @exectuable_path in restricted binaries is not allowed
+# Use of @loader_path in restricted binaries is not allowed
+# Use of relative paths in restricted binaries is not allowed
+#
+
+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"
+
+
+
+all: main_exe  main_loader main_rel 
+
+dir1/libfoo.dylib : foo.c
+       mkdir -p dir1
+       ${CC} ${CCFLAGS} foo.c -dynamiclib -o dir1/libfoo.dylib -install_name @executable_path/dir1/libfoo.dylib
+
+dir2/libbar.dylib : foo.c
+       mkdir -p dir2
+       ${CC} ${CCFLAGS} foo.c -dynamiclib -o dir2/libbar.dylib -install_name @loader_path/dir2/libbar.dylib
+
+dir3/libbaz.dylib : foo.c
+       mkdir -p dir3
+       ${CC} ${CCFLAGS} foo.c -dynamiclib -o ./dir3/libbaz.dylib
+
+main_exe: main.c dir1/libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main_exe main.c dir1/libfoo.dylib -sectcreate __RESTRICT __restrict /dev/null
+       
+main_loader: main.c dir2/libbar.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main_loader main.c dir2/libbar.dylib -sectcreate __RESTRICT __restrict /dev/null
+
+main_rel: main.c dir3/libbaz.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main_rel main.c dir3/libbaz.dylib -sectcreate __RESTRICT __restrict /dev/null
+
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main_exe  main_loader  main_rel  dir1 dir2 dir3
+
diff --git a/unit-tests/test-cases/restrict-executable_path/foo.c b/unit-tests/test-cases/restrict-executable_path/foo.c
new file mode 100644 (file)
index 0000000..d2b44c4
--- /dev/null
@@ -0,0 +1,5 @@
+
+
+int foo() { return 1; }
+
+
diff --git a/unit-tests/test-cases/restrict-executable_path/main.c b/unit-tests/test-cases/restrict-executable_path/main.c
new file mode 100644 (file)
index 0000000..de19bb6
--- /dev/null
@@ -0,0 +1,14 @@
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <string.h> // strcmp(), strncmp()
+#include <unistd.h> // issetugid
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+extern int foo();
+
+int main(int argc, const char* argv[])
+{
+       foo();
+       return EXIT_SUCCESS;
+}
index a01183407287ba79f65ab21d296db0c89ce1db2b..d85c89b166f637cdee0cfaa344c5bc6df20be1b2 100644 (file)
@@ -30,7 +30,9 @@ include ${TESTROOT}/include/common.makefile
 #
 
 
-run: all
+all-check: all check
+
+check:
        export DYLD_FALLBACK_LIBRARY_PATH=`pwd`/bad && ./main
        export DYLD_FALLBACK_LIBRARY_PATH=`pwd`/good && ./main2
 
index 153f7185f5fa622152b2d407431537152acdbe6c..6a7c1334a9f639e56d71d117959f6c7ece6e2b9b 100644 (file)
@@ -28,8 +28,9 @@ include ${TESTROOT}/include/common.makefile
 # a main executable run with DYLD_LIBRARY_PATH will override its rpath
 #
 
+all-check: all check
 
-run: all
+check:
        export DYLD_LIBRARY_PATH=`pwd`/hide1 && ./main
 
 all: main hide2/libfoo.dylib hide1/libfoo.dylib
diff --git a/unit-tests/test-cases/rpath-DYLD_ROOT_PATH/Makefile b/unit-tests/test-cases/rpath-DYLD_ROOT_PATH/Makefile
new file mode 100644 (file)
index 0000000..26692af
--- /dev/null
@@ -0,0 +1,28 @@
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# <rdar://problem/5869973> DYLD_ROOT_PATH should apply to LC_RPATH rpaths
+#
+
+all-check: all check
+
+check:
+       export DYLD_ROOT_PATH=`pwd` && ${PASS_IFF} ./main
+
+all: main
+
+       
+hide/libfoo.dylib : foo.c
+       mkdir -p hide
+       ${CC} foo.c -dynamiclib -o hide/libfoo.dylib -install_name @rpath/libfoo.dylib
+       
+
+main : main.c hide/libfoo.dylib 
+       ${CC} -I${TESTROOT}/include main.c -o main hide/libfoo.dylib -Wl,-rpath -Wl,/hide
+
+
+clean:
+       ${RM} ${RMFLAGS} *~  main hide
diff --git a/unit-tests/test-cases/rpath-DYLD_ROOT_PATH/foo.c b/unit-tests/test-cases/rpath-DYLD_ROOT_PATH/foo.c
new file mode 100644 (file)
index 0000000..c5563c5
--- /dev/null
@@ -0,0 +1,4 @@
+int foo()
+{
+       return 1;
+}
diff --git a/unit-tests/test-cases/rpath-DYLD_ROOT_PATH/main.c b/unit-tests/test-cases/rpath-DYLD_ROOT_PATH/main.c
new file mode 100644 (file)
index 0000000..b379c36
--- /dev/null
@@ -0,0 +1,16 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <mach-o/dyld.h>
+
+#include "test.h"
+
+extern int foo();
+
+int main()
+{
+       if ( foo() )
+               return EXIT_SUCCESS;
+       else
+               return EXIT_FAILURE;
+}
index ba5400db306a0d4d93ae60a40691883dda83ea8b..f235c0220e20a1e4e39d228e019635187085e217 100644 (file)
@@ -28,8 +28,9 @@ include ${TESTROOT}/include/common.makefile
 # a main executable run with LD_LIBRARY_PATH can locate a dylib it links against
 #
 
+all-check: all check
 
-run: all
+check:
        export LD_LIBRARY_PATH=`pwd`/hide/hole && ./main
 
 all: main
index 536d651dfdde5839465f6be46f3019e3ca4e7950..c559f75362ef64e67f3443d570401d72dd34d086 100644 (file)
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
+PWD = $(shell pwd)
 
 #
 # a main executable linked with -rpath used to locate a dylib it links against
 #
 
+all-check: all check
 
-run: all
+check:
        ./main
 
 all: main
@@ -43,7 +45,7 @@ hide/hole/libfoo.dylib : foo.c hide/hole/libbar.dylib
        ${CC} foo.c hide/hole/libbar.dylib -dynamiclib -o hide/hole/libfoo.dylib -install_name @rpath/libfoo.dylib 
 
 main : main.c hide/hole/libfoo.dylib
-       ${CC} -I${TESTROOT}/include main.c -o main hide/hole/libfoo.dylib -Wl,-rpath -Wl,`pwd`/hide/hole
+       ${CC} -I${TESTROOT}/include main.c -o main hide/hole/libfoo.dylib -Wl,-rpath -Wl,${PWD}/hide/hole
 
 clean:
        ${RM} -rf *~  main hide
index d94f47d85209b052a555f5ad02ba989cc31b4a57..f5ebbc7056afa9230b4ea07eac563d50eca02420 100644 (file)
@@ -23,6 +23,7 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
+PWD = $(shell pwd)
 
 #
 # a main executable linked with -rpath calls into a dylib which calls 
@@ -30,8 +31,9 @@ include ${TESTROOT}/include/common.makefile
 # find the dlopen path.
 #
 
+all-check: all check
 
-run: all
+check:
        ./main
 
 all: main
@@ -41,7 +43,7 @@ hide/hole/libfoo.dylib : foo.c
        ${CC} foo.c -dynamiclib -o hide/hole/libfoo.dylib -install_name @rpath/libfoo.dylib
        
 libbar.dylib : bar.c hide/hole/libfoo.dylib
-       ${CC} bar.c -dynamiclib -o libbar.dylib  -I${TESTROOT}/include  -Wl,-rpath -Wl,`pwd`/hide/hole
+       ${CC} bar.c -dynamiclib -o libbar.dylib  -I${TESTROOT}/include  -Wl,-rpath -Wl,${PWD}/hide/hole
 
 main : main.c libbar.dylib
        ${CC} -I${TESTROOT}/include main.c -o main libbar.dylib
index b679f7790f6e5b65f43c8b7a70ce07b052281632..5856ea7c32f7c3020e186c02df03abfef83c0413 100644 (file)
@@ -23,6 +23,7 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
+PWD = $(shell pwd)
 
 #
 # a main executable linked with -rpath calls into a dylib which calls 
@@ -30,8 +31,9 @@ include ${TESTROOT}/include/common.makefile
 # find the dlopen path.
 #
 
+all-check: all check
 
-run: all
+check:
        ./main
 
 all: main
@@ -44,7 +46,7 @@ libbar.dylib : bar.c hide/hole/libfoo.dylib
        ${CC} bar.c -dynamiclib -o libbar.dylib  -I${TESTROOT}/include
 
 main : main.c libbar.dylib
-       ${CC} -I${TESTROOT}/include main.c -o main libbar.dylib -Wl,-rpath -Wl,`pwd`/hide/hole
+       ${CC} -I${TESTROOT}/include main.c -o main libbar.dylib -Wl,-rpath -Wl,${PWD}/hide/hole
 
 clean:
        ${RM} ${RMFLAGS} *~  main hide/hole/libfoo.dylib hide libbar.dylib
index 22610287adbb2198c634fd724140910e49219f5b..0bea13aa94b83727601775aca24086cd8fb8f9ab 100644 (file)
@@ -37,8 +37,9 @@ ifeq "ppc" "$(ARCH)"
        endif
 endif
 
+all-check: all check
 
-run: all
+check:
        if [ ${EMULATED} == 0 ]; \
        then \
                ${TESTROOT}/bin/exit-zero-pass.pl "rpath-dlopen-leak" "rpath-dlopen-leak" "./main | grep '0 leaks for 0 total leaked bytes' > /dev/null"; \
index ce347460a8872780c03a465efbe804ad60cb3838..f08dfc95ab79783bfeb5e7a4338f8419ffe68951 100644 (file)
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
+PWD = $(shell pwd)
 
 #
 # a main executable linked with -rpath and uses dlopen can find a dylib
 #
 
+all-check: all check
 
-run: all
+check:
        ./main
 
 all: main
@@ -40,7 +42,7 @@ hide/hole/libfoo.dylib : foo.c
        
 
 main : main.c hide/hole/libfoo.dylib
-       ${CC} -I${TESTROOT}/include main.c -o main -Wl,-rpath -Wl,`pwd`/hide/hole
+       ${CC} -I${TESTROOT}/include main.c -o main -Wl,-rpath -Wl,${PWD}/hide/hole
 
 clean:
        ${RM} ${RMFLAGS} *~  main hide/hole/libfoo.dylib hide
index 76dde9f5ebb7dbd89b8b6c6b495f8b279c2c6af5..de9f6728db4707a50665515beb4a1210fc45163c 100644 (file)
@@ -30,8 +30,9 @@ include ${TESTROOT}/include/common.makefile
 # of the main executable.
 #
 
+all-check: all check
 
-run: all
+check:
        ./main
 
 all: main
index a1ec99eb33de21a04ff6795077bbb3c816fe73fd..fa534f2b4049f1dc87f8ea0fea59c8f39f087d18 100644 (file)
@@ -23,6 +23,7 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
+PWD = $(shell pwd)
 
 #
 # a setuid main executable linked with -rpath links against a dylib 
@@ -30,8 +31,9 @@ include ${TESTROOT}/include/common.makefile
 # LC_RPATH uses @loader_path or a relative path, but ok if it is an absolute path
 #
 
+all-check: all check
 
-run: all
+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
@@ -44,10 +46,10 @@ hide/hole/libbar.dylib : bar.c
        ${CC} bar.c -dynamiclib -o hide/hole/libbar.dylib -install_name @rpath/libbar.dylib
 
 libfoo.dylib : foo.c hide/hole/libbar.dylib
-       ${CC} foo.c -dynamiclib -o "`pwd`/libfoo.dylib" hide/hole/libbar.dylib 
+       ${CC} foo.c -dynamiclib -o "${PWD}/libfoo.dylib" hide/hole/libbar.dylib 
 
 main : main.c libfoo.dylib
-       ${CC} -I${TESTROOT}/include main.c -o main libfoo.dylib -Wl,-rpath -Wl,`pwd`/hide/hole
+       ${CC} -I${TESTROOT}/include main.c -o main libfoo.dylib -Wl,-rpath -Wl,${PWD}/hide/hole
        sudo chown root main
        sudo chmod 4755 main
 
index d83c5e821286b489ba432e68e52513328941364a..220b1ad9d0867540e4ff77746c643cc04998fd6a 100644 (file)
@@ -30,8 +30,9 @@ include ${TESTROOT}/include/common.makefile
 # of the main executable during calls to dlopen()
 #
 
+all-check: all check
 
-run: all
+check:
        ./main
 
 all: main
index 6bd18a9d6798081a55a9b0b690657f6ca1e8dc93..addee062c4ae239fc7498a997d24d58a47d109c5 100644 (file)
@@ -30,8 +30,9 @@ include ${TESTROOT}/include/common.makefile
 # of the binary.
 #
 
+all-check: all check
 
-run: all
+check:
        ./main
 
 all: main
index 0364549d216dd34f1e4072d920878a9debe53ab4..14e3a99ac178146c2e3ea1b050ccda4adad2d29b 100644 (file)
@@ -23,6 +23,7 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
+PWD = $(shell pwd)
 
 #
 # The main executable supplies an rpath.  libfoo.dylib supplies an 
@@ -31,8 +32,9 @@ include ${TESTROOT}/include/common.makefile
 # rpath. 
 #
 
+all-check: all check
 
-run: all
+check:
        ./main
 
 all: main
@@ -46,10 +48,10 @@ hide2/libbaz.dylib : baz.c
        ${CC} baz.c -dynamiclib -o hide2/libbaz.dylib  -install_name @rpath/libbaz.dylib
 
 libfoo.dylib : foo.c hide1/libbar.dylib hide2/libbaz.dylib
-       ${CC} foo.c -dynamiclib -o libfoo.dylib hide1/libbar.dylib hide2/libbaz.dylib -Wl,-rpath -Wl,`pwd`/hide2
+       ${CC} foo.c -dynamiclib -o libfoo.dylib hide1/libbar.dylib hide2/libbaz.dylib -Wl,-rpath -Wl,${PWD}/hide2
 
 main : main.c libfoo.dylib
-       ${CC} -I${TESTROOT}/include main.c -o main libfoo.dylib -Wl,-rpath -Wl,`pwd`/hide1
+       ${CC} -I${TESTROOT}/include main.c -o main libfoo.dylib -Wl,-rpath -Wl,${PWD}/hide1
 
 clean:
        ${RM} ${RMFLAGS} *~  main hide1 hide2 libfoo.dylib
index 92ea1b0675e42e2dc3113263e5d4fff29824d889..b8a5145e4bbb99610ce9047124127536387e734c 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        ./main
 
 all: main 
index 8ef3c6d5a6dc74859c6e944cee686fe0fafa5f40..85aa95465b4084891f08e0e30e1731e99b864837 100644 (file)
@@ -23,7 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        export DYLD_INSERT_LIBRARIES=/ && export DYLD_PRINT_LIBRARIES=/ &&  export DYLD_PREBIND_DEBUG=/ && ./main
 
 all: main
index 1dd7f1ebaf7d0ec664c26e665434983162c02778..87690821a9fffc635473ab4bdbcc55c881a2a797 100644 (file)
@@ -32,7 +32,9 @@ SHELL = bash # use bash shell so we can redirect just stderr
 # Use of relative paths in setuid binaries is not allowed
 #
 
-run: all
+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" 
index 00dd9acdae893afb7123404f047e4a94086551fa..a0feb3ab16915c1c3e686fa87fcc4da69440eb44 100644 (file)
@@ -36,11 +36,13 @@ include ${TESTROOT}/include/common.makefile
 ### 
 ### 
 
+PWD = $(shell pwd)
 
+all-check: all check
 
-run: all
+check:
        ./main
-       export DYLD_LIBRARY_PATH="`pwd`/fake" && ./main
+       export DYLD_LIBRARY_PATH="${PWD}/fake" && ./main
        
 
 all: main real/liblink.dylib  real/libtest.dylib fake/libtest.dylib
@@ -51,20 +53,20 @@ main: main.c stub/libtest.dylib stub/liblink.dylib real/libbase.dylib
 
 stub/libtest.dylib: test.c
        mkdir -p stub
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib test.c -DDO_NOTHING -o stub/libtest.dylib -install_name "`pwd`/real/libtest.dylib"
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib test.c -DDO_NOTHING -o stub/libtest.dylib -install_name "${PWD}/real/libtest.dylib"
        
 stub/liblink.dylib: link.c
        mkdir -p stub
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib link.c -o stub/liblink.dylib -install_name "`pwd`/real/liblink.dylib"
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib link.c -o stub/liblink.dylib -install_name "${PWD}/real/liblink.dylib"
        
 
 real/libbase.dylib: base.c
        mkdir -p real
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib base.c -o "`pwd`/real/libbase.dylib"
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib base.c -o "${PWD}/real/libbase.dylib"
        
 real/libtest.dylib: test.c real/libbase.dylib
        mkdir -p real
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib test.c real/libbase.dylib -o "`pwd`/real/libtest.dylib"
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib test.c real/libbase.dylib -o "${PWD}/real/libtest.dylib"
        
 real/liblink.dylib: link.c
        mkdir -p real
@@ -73,7 +75,7 @@ real/liblink.dylib: link.c
 
 fake/libtest.dylib: test.c real/libbase.dylib
        mkdir -p fake
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib test.c real/libbase.dylib -o "`pwd`/fake/libtest.dylib" -install_name "`pwd`/real/libtest.dylib"
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib test.c real/libbase.dylib -o "${PWD}/fake/libtest.dylib" -install_name "${PWD}/real/libtest.dylib"
        
        
 
index b0ee016fa5c95e8031d02efed404d9f40a98f53b..ec6d1cb87301ca493137f11e49821e5ba91e14a0 100644 (file)
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+
+all-check: all check
+
+check:
        ./main
 
 all:
index 92225e9f13485ecb5e72adba4692439f07dbdb23..cfadedaeb511881077a5d9c4132a919b59b81086 100644 (file)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2005-2007 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -24,13 +24,26 @@ TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
 ### 
-### This test case is to verify __TEXT reliocations work
+### This test case is to verify __TEXT reliocations work in dylibs
 ### 
 ### 
 
 
+TEXT_RELOC_FLAGS = -mdynamic-no-pic -read_only_relocs suppress -Wl,-w
 
-run: all
+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
+
+check:
        ./main
 
 all: main 
@@ -38,8 +51,8 @@ all: main
 main: main.c libbar.dylib
        ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libbar.dylib
 
-libbar.dylib: foo.s bar.c
-       ${CC} ${CCFLAGS} -dynamiclib -o libbar.dylib bar.c foo.s -read_only_relocs suppress -Os
+libbar.dylib: bar.c
+       ${CC} ${CCFLAGS} -dynamiclib -o libbar.dylib bar.c -Os ${TEXT_RELOC_FLAGS}
        
 clean:
        ${RM} ${RMFLAGS} *~ main libbar.dylib
index 9224e9290fc22d3b29717e0cfa2eaf50c0042962..acf643ca33131b2a39b42bf0a43cd38d630a01dc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2007 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <stdlib.h> // exit(), EXIT_SUCCESS
 #include <stdbool.h>
 
-extern int* foo;
+static int x = 0;
 
-bool testBar()
-{
-       return (*foo == 10);
-}
-
-int bar = 10;
+int getx() { return x; }
+void setx(int a) { x = a; }
 
diff --git a/unit-tests/test-cases/text-relocs/foo.s b/unit-tests/test-cases/text-relocs/foo.s
deleted file mode 100644 (file)
index 7f8821e..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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@
- */
-
-
-       .text
-       .globl _foo
-_foo:
-       .long   _bar
-       
-       
index a702c2e5230a0357585efb6972c4561d8c23760e..453b17bcaeec9a98f78906acad6990a12592cf4f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2007 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
-extern bool testBar();
+extern int getx();
+extern void setx(int a);
 
 int main(int argc, const char* argv[])
 {
-       if ( testBar() )
-               PASS("text-reloc");
-       else
+       setx(20);
+       if ( getx() != 20 )
                FAIL("text-reloc");
+       else {
+               setx(99);
+               if ( getx() == 99 )
+                       PASS("text-reloc");
+               else
+                       FAIL("text-reloc");
+       }
        return EXIT_SUCCESS;
 }
 
diff --git a/unit-tests/test-cases/threaded-lazy-bind/Makefile b/unit-tests/test-cases/threaded-lazy-bind/Makefile
new file mode 100644 (file)
index 0000000..7b38cee
--- /dev/null
@@ -0,0 +1,41 @@
+##
+# 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 libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libfoo.dylib
+
+libfoo.dylib : foo.c
+       ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libfoo.dylib
+
diff --git a/unit-tests/test-cases/threaded-lazy-bind/foo.c b/unit-tests/test-cases/threaded-lazy-bind/foo.c
new file mode 100644 (file)
index 0000000..d647bd5
--- /dev/null
@@ -0,0 +1,1001 @@
+
+int do_000() { return 0; }
+int do_001() { return 1; }
+int do_002() { return 2; }
+int do_003() { return 3; }
+int do_004() { return 4; }
+int do_005() { return 5; }
+int do_006() { return 6; }
+int do_007() { return 7; }
+int do_008() { return 8; }
+int do_009() { return 9; }
+int do_010() { return 10; }
+int do_011() { return 11; }
+int do_012() { return 12; }
+int do_013() { return 13; }
+int do_014() { return 14; }
+int do_015() { return 15; }
+int do_016() { return 16; }
+int do_017() { return 17; }
+int do_018() { return 18; }
+int do_019() { return 19; }
+int do_020() { return 20; }
+int do_021() { return 21; }
+int do_022() { return 22; }
+int do_023() { return 23; }
+int do_024() { return 24; }
+int do_025() { return 25; }
+int do_026() { return 26; }
+int do_027() { return 27; }
+int do_028() { return 28; }
+int do_029() { return 29; }
+int do_030() { return 30; }
+int do_031() { return 31; }
+int do_032() { return 32; }
+int do_033() { return 33; }
+int do_034() { return 34; }
+int do_035() { return 35; }
+int do_036() { return 36; }
+int do_037() { return 37; }
+int do_038() { return 38; }
+int do_039() { return 39; }
+int do_040() { return 40; }
+int do_041() { return 41; }
+int do_042() { return 42; }
+int do_043() { return 43; }
+int do_044() { return 44; }
+int do_045() { return 45; }
+int do_046() { return 46; }
+int do_047() { return 47; }
+int do_048() { return 48; }
+int do_049() { return 49; }
+int do_050() { return 50; }
+int do_051() { return 51; }
+int do_052() { return 52; }
+int do_053() { return 53; }
+int do_054() { return 54; }
+int do_055() { return 55; }
+int do_056() { return 56; }
+int do_057() { return 57; }
+int do_058() { return 58; }
+int do_059() { return 59; }
+int do_060() { return 60; }
+int do_061() { return 61; }
+int do_062() { return 62; }
+int do_063() { return 63; }
+int do_064() { return 64; }
+int do_065() { return 65; }
+int do_066() { return 66; }
+int do_067() { return 67; }
+int do_068() { return 68; }
+int do_069() { return 69; }
+int do_070() { return 70; }
+int do_071() { return 71; }
+int do_072() { return 72; }
+int do_073() { return 73; }
+int do_074() { return 74; }
+int do_075() { return 75; }
+int do_076() { return 76; }
+int do_077() { return 77; }
+int do_078() { return 78; }
+int do_079() { return 79; }
+int do_080() { return 80; }
+int do_081() { return 81; }
+int do_082() { return 82; }
+int do_083() { return 83; }
+int do_084() { return 84; }
+int do_085() { return 85; }
+int do_086() { return 86; }
+int do_087() { return 87; }
+int do_088() { return 88; }
+int do_089() { return 89; }
+int do_090() { return 90; }
+int do_091() { return 91; }
+int do_092() { return 92; }
+int do_093() { return 93; }
+int do_094() { return 94; }
+int do_095() { return 95; }
+int do_096() { return 96; }
+int do_097() { return 97; }
+int do_098() { return 98; }
+int do_099() { return 99; }
+int do_100() { return 100; }
+int do_101() { return 101; }
+int do_102() { return 102; }
+int do_103() { return 103; }
+int do_104() { return 104; }
+int do_105() { return 105; }
+int do_106() { return 106; }
+int do_107() { return 107; }
+int do_108() { return 108; }
+int do_109() { return 109; }
+int do_110() { return 110; }
+int do_111() { return 111; }
+int do_112() { return 112; }
+int do_113() { return 113; }
+int do_114() { return 114; }
+int do_115() { return 115; }
+int do_116() { return 116; }
+int do_117() { return 117; }
+int do_118() { return 118; }
+int do_119() { return 119; }
+int do_120() { return 120; }
+int do_121() { return 121; }
+int do_122() { return 122; }
+int do_123() { return 123; }
+int do_124() { return 124; }
+int do_125() { return 125; }
+int do_126() { return 126; }
+int do_127() { return 127; }
+int do_128() { return 128; }
+int do_129() { return 129; }
+int do_130() { return 130; }
+int do_131() { return 131; }
+int do_132() { return 132; }
+int do_133() { return 133; }
+int do_134() { return 134; }
+int do_135() { return 135; }
+int do_136() { return 136; }
+int do_137() { return 137; }
+int do_138() { return 138; }
+int do_139() { return 139; }
+int do_140() { return 140; }
+int do_141() { return 141; }
+int do_142() { return 142; }
+int do_143() { return 143; }
+int do_144() { return 144; }
+int do_145() { return 145; }
+int do_146() { return 146; }
+int do_147() { return 147; }
+int do_148() { return 148; }
+int do_149() { return 149; }
+int do_150() { return 150; }
+int do_151() { return 151; }
+int do_152() { return 152; }
+int do_153() { return 153; }
+int do_154() { return 154; }
+int do_155() { return 155; }
+int do_156() { return 156; }
+int do_157() { return 157; }
+int do_158() { return 158; }
+int do_159() { return 159; }
+int do_160() { return 160; }
+int do_161() { return 161; }
+int do_162() { return 162; }
+int do_163() { return 163; }
+int do_164() { return 164; }
+int do_165() { return 165; }
+int do_166() { return 166; }
+int do_167() { return 167; }
+int do_168() { return 168; }
+int do_169() { return 169; }
+int do_170() { return 170; }
+int do_171() { return 171; }
+int do_172() { return 172; }
+int do_173() { return 173; }
+int do_174() { return 174; }
+int do_175() { return 175; }
+int do_176() { return 176; }
+int do_177() { return 177; }
+int do_178() { return 178; }
+int do_179() { return 179; }
+int do_180() { return 180; }
+int do_181() { return 181; }
+int do_182() { return 182; }
+int do_183() { return 183; }
+int do_184() { return 184; }
+int do_185() { return 185; }
+int do_186() { return 186; }
+int do_187() { return 187; }
+int do_188() { return 188; }
+int do_189() { return 189; }
+int do_190() { return 190; }
+int do_191() { return 191; }
+int do_192() { return 192; }
+int do_193() { return 193; }
+int do_194() { return 194; }
+int do_195() { return 195; }
+int do_196() { return 196; }
+int do_197() { return 197; }
+int do_198() { return 198; }
+int do_199() { return 199; }
+int do_200() { return 200; }
+int do_201() { return 201; }
+int do_202() { return 202; }
+int do_203() { return 203; }
+int do_204() { return 204; }
+int do_205() { return 205; }
+int do_206() { return 206; }
+int do_207() { return 207; }
+int do_208() { return 208; }
+int do_209() { return 209; }
+int do_210() { return 210; }
+int do_211() { return 211; }
+int do_212() { return 212; }
+int do_213() { return 213; }
+int do_214() { return 214; }
+int do_215() { return 215; }
+int do_216() { return 216; }
+int do_217() { return 217; }
+int do_218() { return 218; }
+int do_219() { return 219; }
+int do_220() { return 220; }
+int do_221() { return 221; }
+int do_222() { return 222; }
+int do_223() { return 223; }
+int do_224() { return 224; }
+int do_225() { return 225; }
+int do_226() { return 226; }
+int do_227() { return 227; }
+int do_228() { return 228; }
+int do_229() { return 229; }
+int do_230() { return 230; }
+int do_231() { return 231; }
+int do_232() { return 232; }
+int do_233() { return 233; }
+int do_234() { return 234; }
+int do_235() { return 235; }
+int do_236() { return 236; }
+int do_237() { return 237; }
+int do_238() { return 238; }
+int do_239() { return 239; }
+int do_240() { return 240; }
+int do_241() { return 241; }
+int do_242() { return 242; }
+int do_243() { return 243; }
+int do_244() { return 244; }
+int do_245() { return 245; }
+int do_246() { return 246; }
+int do_247() { return 247; }
+int do_248() { return 248; }
+int do_249() { return 249; }
+int do_250() { return 250; }
+int do_251() { return 251; }
+int do_252() { return 252; }
+int do_253() { return 253; }
+int do_254() { return 254; }
+int do_255() { return 255; }
+int do_256() { return 256; }
+int do_257() { return 257; }
+int do_258() { return 258; }
+int do_259() { return 259; }
+int do_260() { return 260; }
+int do_261() { return 261; }
+int do_262() { return 262; }
+int do_263() { return 263; }
+int do_264() { return 264; }
+int do_265() { return 265; }
+int do_266() { return 266; }
+int do_267() { return 267; }
+int do_268() { return 268; }
+int do_269() { return 269; }
+int do_270() { return 270; }
+int do_271() { return 271; }
+int do_272() { return 272; }
+int do_273() { return 273; }
+int do_274() { return 274; }
+int do_275() { return 275; }
+int do_276() { return 276; }
+int do_277() { return 277; }
+int do_278() { return 278; }
+int do_279() { return 279; }
+int do_280() { return 280; }
+int do_281() { return 281; }
+int do_282() { return 282; }
+int do_283() { return 283; }
+int do_284() { return 284; }
+int do_285() { return 285; }
+int do_286() { return 286; }
+int do_287() { return 287; }
+int do_288() { return 288; }
+int do_289() { return 289; }
+int do_290() { return 290; }
+int do_291() { return 291; }
+int do_292() { return 292; }
+int do_293() { return 293; }
+int do_294() { return 294; }
+int do_295() { return 295; }
+int do_296() { return 296; }
+int do_297() { return 297; }
+int do_298() { return 298; }
+int do_299() { return 299; }
+int do_300() { return 300; }
+int do_301() { return 301; }
+int do_302() { return 302; }
+int do_303() { return 303; }
+int do_304() { return 304; }
+int do_305() { return 305; }
+int do_306() { return 306; }
+int do_307() { return 307; }
+int do_308() { return 308; }
+int do_309() { return 309; }
+int do_310() { return 310; }
+int do_311() { return 311; }
+int do_312() { return 312; }
+int do_313() { return 313; }
+int do_314() { return 314; }
+int do_315() { return 315; }
+int do_316() { return 316; }
+int do_317() { return 317; }
+int do_318() { return 318; }
+int do_319() { return 319; }
+int do_320() { return 320; }
+int do_321() { return 321; }
+int do_322() { return 322; }
+int do_323() { return 323; }
+int do_324() { return 324; }
+int do_325() { return 325; }
+int do_326() { return 326; }
+int do_327() { return 327; }
+int do_328() { return 328; }
+int do_329() { return 329; }
+int do_330() { return 330; }
+int do_331() { return 331; }
+int do_332() { return 332; }
+int do_333() { return 333; }
+int do_334() { return 334; }
+int do_335() { return 335; }
+int do_336() { return 336; }
+int do_337() { return 337; }
+int do_338() { return 338; }
+int do_339() { return 339; }
+int do_340() { return 340; }
+int do_341() { return 341; }
+int do_342() { return 342; }
+int do_343() { return 343; }
+int do_344() { return 344; }
+int do_345() { return 345; }
+int do_346() { return 346; }
+int do_347() { return 347; }
+int do_348() { return 348; }
+int do_349() { return 349; }
+int do_350() { return 350; }
+int do_351() { return 351; }
+int do_352() { return 352; }
+int do_353() { return 353; }
+int do_354() { return 354; }
+int do_355() { return 355; }
+int do_356() { return 356; }
+int do_357() { return 357; }
+int do_358() { return 358; }
+int do_359() { return 359; }
+int do_360() { return 360; }
+int do_361() { return 361; }
+int do_362() { return 362; }
+int do_363() { return 363; }
+int do_364() { return 364; }
+int do_365() { return 365; }
+int do_366() { return 366; }
+int do_367() { return 367; }
+int do_368() { return 368; }
+int do_369() { return 369; }
+int do_370() { return 370; }
+int do_371() { return 371; }
+int do_372() { return 372; }
+int do_373() { return 373; }
+int do_374() { return 374; }
+int do_375() { return 375; }
+int do_376() { return 376; }
+int do_377() { return 377; }
+int do_378() { return 378; }
+int do_379() { return 379; }
+int do_380() { return 380; }
+int do_381() { return 381; }
+int do_382() { return 382; }
+int do_383() { return 383; }
+int do_384() { return 384; }
+int do_385() { return 385; }
+int do_386() { return 386; }
+int do_387() { return 387; }
+int do_388() { return 388; }
+int do_389() { return 389; }
+int do_390() { return 390; }
+int do_391() { return 391; }
+int do_392() { return 392; }
+int do_393() { return 393; }
+int do_394() { return 394; }
+int do_395() { return 395; }
+int do_396() { return 396; }
+int do_397() { return 397; }
+int do_398() { return 398; }
+int do_399() { return 399; }
+int do_400() { return 400; }
+int do_401() { return 401; }
+int do_402() { return 402; }
+int do_403() { return 403; }
+int do_404() { return 404; }
+int do_405() { return 405; }
+int do_406() { return 406; }
+int do_407() { return 407; }
+int do_408() { return 408; }
+int do_409() { return 409; }
+int do_410() { return 410; }
+int do_411() { return 411; }
+int do_412() { return 412; }
+int do_413() { return 413; }
+int do_414() { return 414; }
+int do_415() { return 415; }
+int do_416() { return 416; }
+int do_417() { return 417; }
+int do_418() { return 418; }
+int do_419() { return 419; }
+int do_420() { return 420; }
+int do_421() { return 421; }
+int do_422() { return 422; }
+int do_423() { return 423; }
+int do_424() { return 424; }
+int do_425() { return 425; }
+int do_426() { return 426; }
+int do_427() { return 427; }
+int do_428() { return 428; }
+int do_429() { return 429; }
+int do_430() { return 430; }
+int do_431() { return 431; }
+int do_432() { return 432; }
+int do_433() { return 433; }
+int do_434() { return 434; }
+int do_435() { return 435; }
+int do_436() { return 436; }
+int do_437() { return 437; }
+int do_438() { return 438; }
+int do_439() { return 439; }
+int do_440() { return 440; }
+int do_441() { return 441; }
+int do_442() { return 442; }
+int do_443() { return 443; }
+int do_444() { return 444; }
+int do_445() { return 445; }
+int do_446() { return 446; }
+int do_447() { return 447; }
+int do_448() { return 448; }
+int do_449() { return 449; }
+int do_450() { return 450; }
+int do_451() { return 451; }
+int do_452() { return 452; }
+int do_453() { return 453; }
+int do_454() { return 454; }
+int do_455() { return 455; }
+int do_456() { return 456; }
+int do_457() { return 457; }
+int do_458() { return 458; }
+int do_459() { return 459; }
+int do_460() { return 460; }
+int do_461() { return 461; }
+int do_462() { return 462; }
+int do_463() { return 463; }
+int do_464() { return 464; }
+int do_465() { return 465; }
+int do_466() { return 466; }
+int do_467() { return 467; }
+int do_468() { return 468; }
+int do_469() { return 469; }
+int do_470() { return 470; }
+int do_471() { return 471; }
+int do_472() { return 472; }
+int do_473() { return 473; }
+int do_474() { return 474; }
+int do_475() { return 475; }
+int do_476() { return 476; }
+int do_477() { return 477; }
+int do_478() { return 478; }
+int do_479() { return 479; }
+int do_480() { return 480; }
+int do_481() { return 481; }
+int do_482() { return 482; }
+int do_483() { return 483; }
+int do_484() { return 484; }
+int do_485() { return 485; }
+int do_486() { return 486; }
+int do_487() { return 487; }
+int do_488() { return 488; }
+int do_489() { return 489; }
+int do_490() { return 490; }
+int do_491() { return 491; }
+int do_492() { return 492; }
+int do_493() { return 493; }
+int do_494() { return 494; }
+int do_495() { return 495; }
+int do_496() { return 496; }
+int do_497() { return 497; }
+int do_498() { return 498; }
+int do_499() { return 499; }
+int do_500() { return 500; }
+int do_501() { return 501; }
+int do_502() { return 502; }
+int do_503() { return 503; }
+int do_504() { return 504; }
+int do_505() { return 505; }
+int do_506() { return 506; }
+int do_507() { return 507; }
+int do_508() { return 508; }
+int do_509() { return 509; }
+int do_510() { return 510; }
+int do_511() { return 511; }
+int do_512() { return 512; }
+int do_513() { return 513; }
+int do_514() { return 514; }
+int do_515() { return 515; }
+int do_516() { return 516; }
+int do_517() { return 517; }
+int do_518() { return 518; }
+int do_519() { return 519; }
+int do_520() { return 520; }
+int do_521() { return 521; }
+int do_522() { return 522; }
+int do_523() { return 523; }
+int do_524() { return 524; }
+int do_525() { return 525; }
+int do_526() { return 526; }
+int do_527() { return 527; }
+int do_528() { return 528; }
+int do_529() { return 529; }
+int do_530() { return 530; }
+int do_531() { return 531; }
+int do_532() { return 532; }
+int do_533() { return 533; }
+int do_534() { return 534; }
+int do_535() { return 535; }
+int do_536() { return 536; }
+int do_537() { return 537; }
+int do_538() { return 538; }
+int do_539() { return 539; }
+int do_540() { return 540; }
+int do_541() { return 541; }
+int do_542() { return 542; }
+int do_543() { return 543; }
+int do_544() { return 544; }
+int do_545() { return 545; }
+int do_546() { return 546; }
+int do_547() { return 547; }
+int do_548() { return 548; }
+int do_549() { return 549; }
+int do_550() { return 550; }
+int do_551() { return 551; }
+int do_552() { return 552; }
+int do_553() { return 553; }
+int do_554() { return 554; }
+int do_555() { return 555; }
+int do_556() { return 556; }
+int do_557() { return 557; }
+int do_558() { return 558; }
+int do_559() { return 559; }
+int do_560() { return 560; }
+int do_561() { return 561; }
+int do_562() { return 562; }
+int do_563() { return 563; }
+int do_564() { return 564; }
+int do_565() { return 565; }
+int do_566() { return 566; }
+int do_567() { return 567; }
+int do_568() { return 568; }
+int do_569() { return 569; }
+int do_570() { return 570; }
+int do_571() { return 571; }
+int do_572() { return 572; }
+int do_573() { return 573; }
+int do_574() { return 574; }
+int do_575() { return 575; }
+int do_576() { return 576; }
+int do_577() { return 577; }
+int do_578() { return 578; }
+int do_579() { return 579; }
+int do_580() { return 580; }
+int do_581() { return 581; }
+int do_582() { return 582; }
+int do_583() { return 583; }
+int do_584() { return 584; }
+int do_585() { return 585; }
+int do_586() { return 586; }
+int do_587() { return 587; }
+int do_588() { return 588; }
+int do_589() { return 589; }
+int do_590() { return 590; }
+int do_591() { return 591; }
+int do_592() { return 592; }
+int do_593() { return 593; }
+int do_594() { return 594; }
+int do_595() { return 595; }
+int do_596() { return 596; }
+int do_597() { return 597; }
+int do_598() { return 598; }
+int do_599() { return 599; }
+int do_600() { return 600; }
+int do_601() { return 601; }
+int do_602() { return 602; }
+int do_603() { return 603; }
+int do_604() { return 604; }
+int do_605() { return 605; }
+int do_606() { return 606; }
+int do_607() { return 607; }
+int do_608() { return 608; }
+int do_609() { return 609; }
+int do_610() { return 610; }
+int do_611() { return 611; }
+int do_612() { return 612; }
+int do_613() { return 613; }
+int do_614() { return 614; }
+int do_615() { return 615; }
+int do_616() { return 616; }
+int do_617() { return 617; }
+int do_618() { return 618; }
+int do_619() { return 619; }
+int do_620() { return 620; }
+int do_621() { return 621; }
+int do_622() { return 622; }
+int do_623() { return 623; }
+int do_624() { return 624; }
+int do_625() { return 625; }
+int do_626() { return 626; }
+int do_627() { return 627; }
+int do_628() { return 628; }
+int do_629() { return 629; }
+int do_630() { return 630; }
+int do_631() { return 631; }
+int do_632() { return 632; }
+int do_633() { return 633; }
+int do_634() { return 634; }
+int do_635() { return 635; }
+int do_636() { return 636; }
+int do_637() { return 637; }
+int do_638() { return 638; }
+int do_639() { return 639; }
+int do_640() { return 640; }
+int do_641() { return 641; }
+int do_642() { return 642; }
+int do_643() { return 643; }
+int do_644() { return 644; }
+int do_645() { return 645; }
+int do_646() { return 646; }
+int do_647() { return 647; }
+int do_648() { return 648; }
+int do_649() { return 649; }
+int do_650() { return 650; }
+int do_651() { return 651; }
+int do_652() { return 652; }
+int do_653() { return 653; }
+int do_654() { return 654; }
+int do_655() { return 655; }
+int do_656() { return 656; }
+int do_657() { return 657; }
+int do_658() { return 658; }
+int do_659() { return 659; }
+int do_660() { return 660; }
+int do_661() { return 661; }
+int do_662() { return 662; }
+int do_663() { return 663; }
+int do_664() { return 664; }
+int do_665() { return 665; }
+int do_666() { return 666; }
+int do_667() { return 667; }
+int do_668() { return 668; }
+int do_669() { return 669; }
+int do_670() { return 670; }
+int do_671() { return 671; }
+int do_672() { return 672; }
+int do_673() { return 673; }
+int do_674() { return 674; }
+int do_675() { return 675; }
+int do_676() { return 676; }
+int do_677() { return 677; }
+int do_678() { return 678; }
+int do_679() { return 679; }
+int do_680() { return 680; }
+int do_681() { return 681; }
+int do_682() { return 682; }
+int do_683() { return 683; }
+int do_684() { return 684; }
+int do_685() { return 685; }
+int do_686() { return 686; }
+int do_687() { return 687; }
+int do_688() { return 688; }
+int do_689() { return 689; }
+int do_690() { return 690; }
+int do_691() { return 691; }
+int do_692() { return 692; }
+int do_693() { return 693; }
+int do_694() { return 694; }
+int do_695() { return 695; }
+int do_696() { return 696; }
+int do_697() { return 697; }
+int do_698() { return 698; }
+int do_699() { return 699; }
+int do_700() { return 700; }
+int do_701() { return 701; }
+int do_702() { return 702; }
+int do_703() { return 703; }
+int do_704() { return 704; }
+int do_705() { return 705; }
+int do_706() { return 706; }
+int do_707() { return 707; }
+int do_708() { return 708; }
+int do_709() { return 709; }
+int do_710() { return 710; }
+int do_711() { return 711; }
+int do_712() { return 712; }
+int do_713() { return 713; }
+int do_714() { return 714; }
+int do_715() { return 715; }
+int do_716() { return 716; }
+int do_717() { return 717; }
+int do_718() { return 718; }
+int do_719() { return 719; }
+int do_720() { return 720; }
+int do_721() { return 721; }
+int do_722() { return 722; }
+int do_723() { return 723; }
+int do_724() { return 724; }
+int do_725() { return 725; }
+int do_726() { return 726; }
+int do_727() { return 727; }
+int do_728() { return 728; }
+int do_729() { return 729; }
+int do_730() { return 730; }
+int do_731() { return 731; }
+int do_732() { return 732; }
+int do_733() { return 733; }
+int do_734() { return 734; }
+int do_735() { return 735; }
+int do_736() { return 736; }
+int do_737() { return 737; }
+int do_738() { return 738; }
+int do_739() { return 739; }
+int do_740() { return 740; }
+int do_741() { return 741; }
+int do_742() { return 742; }
+int do_743() { return 743; }
+int do_744() { return 744; }
+int do_745() { return 745; }
+int do_746() { return 746; }
+int do_747() { return 747; }
+int do_748() { return 748; }
+int do_749() { return 749; }
+int do_750() { return 750; }
+int do_751() { return 751; }
+int do_752() { return 752; }
+int do_753() { return 753; }
+int do_754() { return 754; }
+int do_755() { return 755; }
+int do_756() { return 756; }
+int do_757() { return 757; }
+int do_758() { return 758; }
+int do_759() { return 759; }
+int do_760() { return 760; }
+int do_761() { return 761; }
+int do_762() { return 762; }
+int do_763() { return 763; }
+int do_764() { return 764; }
+int do_765() { return 765; }
+int do_766() { return 766; }
+int do_767() { return 767; }
+int do_768() { return 768; }
+int do_769() { return 769; }
+int do_770() { return 770; }
+int do_771() { return 771; }
+int do_772() { return 772; }
+int do_773() { return 773; }
+int do_774() { return 774; }
+int do_775() { return 775; }
+int do_776() { return 776; }
+int do_777() { return 777; }
+int do_778() { return 778; }
+int do_779() { return 779; }
+int do_780() { return 780; }
+int do_781() { return 781; }
+int do_782() { return 782; }
+int do_783() { return 783; }
+int do_784() { return 784; }
+int do_785() { return 785; }
+int do_786() { return 786; }
+int do_787() { return 787; }
+int do_788() { return 788; }
+int do_789() { return 789; }
+int do_790() { return 790; }
+int do_791() { return 791; }
+int do_792() { return 792; }
+int do_793() { return 793; }
+int do_794() { return 794; }
+int do_795() { return 795; }
+int do_796() { return 796; }
+int do_797() { return 797; }
+int do_798() { return 798; }
+int do_799() { return 799; }
+int do_800() { return 800; }
+int do_801() { return 801; }
+int do_802() { return 802; }
+int do_803() { return 803; }
+int do_804() { return 804; }
+int do_805() { return 805; }
+int do_806() { return 806; }
+int do_807() { return 807; }
+int do_808() { return 808; }
+int do_809() { return 809; }
+int do_810() { return 810; }
+int do_811() { return 811; }
+int do_812() { return 812; }
+int do_813() { return 813; }
+int do_814() { return 814; }
+int do_815() { return 815; }
+int do_816() { return 816; }
+int do_817() { return 817; }
+int do_818() { return 818; }
+int do_819() { return 819; }
+int do_820() { return 820; }
+int do_821() { return 821; }
+int do_822() { return 822; }
+int do_823() { return 823; }
+int do_824() { return 824; }
+int do_825() { return 825; }
+int do_826() { return 826; }
+int do_827() { return 827; }
+int do_828() { return 828; }
+int do_829() { return 829; }
+int do_830() { return 830; }
+int do_831() { return 831; }
+int do_832() { return 832; }
+int do_833() { return 833; }
+int do_834() { return 834; }
+int do_835() { return 835; }
+int do_836() { return 836; }
+int do_837() { return 837; }
+int do_838() { return 838; }
+int do_839() { return 839; }
+int do_840() { return 840; }
+int do_841() { return 841; }
+int do_842() { return 842; }
+int do_843() { return 843; }
+int do_844() { return 844; }
+int do_845() { return 845; }
+int do_846() { return 846; }
+int do_847() { return 847; }
+int do_848() { return 848; }
+int do_849() { return 849; }
+int do_850() { return 850; }
+int do_851() { return 851; }
+int do_852() { return 852; }
+int do_853() { return 853; }
+int do_854() { return 854; }
+int do_855() { return 855; }
+int do_856() { return 856; }
+int do_857() { return 857; }
+int do_858() { return 858; }
+int do_859() { return 859; }
+int do_860() { return 860; }
+int do_861() { return 861; }
+int do_862() { return 862; }
+int do_863() { return 863; }
+int do_864() { return 864; }
+int do_865() { return 865; }
+int do_866() { return 866; }
+int do_867() { return 867; }
+int do_868() { return 868; }
+int do_869() { return 869; }
+int do_870() { return 870; }
+int do_871() { return 871; }
+int do_872() { return 872; }
+int do_873() { return 873; }
+int do_874() { return 874; }
+int do_875() { return 875; }
+int do_876() { return 876; }
+int do_877() { return 877; }
+int do_878() { return 878; }
+int do_879() { return 879; }
+int do_880() { return 880; }
+int do_881() { return 881; }
+int do_882() { return 882; }
+int do_883() { return 883; }
+int do_884() { return 884; }
+int do_885() { return 885; }
+int do_886() { return 886; }
+int do_887() { return 887; }
+int do_888() { return 888; }
+int do_889() { return 889; }
+int do_890() { return 890; }
+int do_891() { return 891; }
+int do_892() { return 892; }
+int do_893() { return 893; }
+int do_894() { return 894; }
+int do_895() { return 895; }
+int do_896() { return 896; }
+int do_897() { return 897; }
+int do_898() { return 898; }
+int do_899() { return 899; }
+int do_900() { return 900; }
+int do_901() { return 901; }
+int do_902() { return 902; }
+int do_903() { return 903; }
+int do_904() { return 904; }
+int do_905() { return 905; }
+int do_906() { return 906; }
+int do_907() { return 907; }
+int do_908() { return 908; }
+int do_909() { return 909; }
+int do_910() { return 910; }
+int do_911() { return 911; }
+int do_912() { return 912; }
+int do_913() { return 913; }
+int do_914() { return 914; }
+int do_915() { return 915; }
+int do_916() { return 916; }
+int do_917() { return 917; }
+int do_918() { return 918; }
+int do_919() { return 919; }
+int do_920() { return 920; }
+int do_921() { return 921; }
+int do_922() { return 922; }
+int do_923() { return 923; }
+int do_924() { return 924; }
+int do_925() { return 925; }
+int do_926() { return 926; }
+int do_927() { return 927; }
+int do_928() { return 928; }
+int do_929() { return 929; }
+int do_930() { return 930; }
+int do_931() { return 931; }
+int do_932() { return 932; }
+int do_933() { return 933; }
+int do_934() { return 934; }
+int do_935() { return 935; }
+int do_936() { return 936; }
+int do_937() { return 937; }
+int do_938() { return 938; }
+int do_939() { return 939; }
+int do_940() { return 940; }
+int do_941() { return 941; }
+int do_942() { return 942; }
+int do_943() { return 943; }
+int do_944() { return 944; }
+int do_945() { return 945; }
+int do_946() { return 946; }
+int do_947() { return 947; }
+int do_948() { return 948; }
+int do_949() { return 949; }
+int do_950() { return 950; }
+int do_951() { return 951; }
+int do_952() { return 952; }
+int do_953() { return 953; }
+int do_954() { return 954; }
+int do_955() { return 955; }
+int do_956() { return 956; }
+int do_957() { return 957; }
+int do_958() { return 958; }
+int do_959() { return 959; }
+int do_960() { return 960; }
+int do_961() { return 961; }
+int do_962() { return 962; }
+int do_963() { return 963; }
+int do_964() { return 964; }
+int do_965() { return 965; }
+int do_966() { return 966; }
+int do_967() { return 967; }
+int do_968() { return 968; }
+int do_969() { return 969; }
+int do_970() { return 970; }
+int do_971() { return 971; }
+int do_972() { return 972; }
+int do_973() { return 973; }
+int do_974() { return 974; }
+int do_975() { return 975; }
+int do_976() { return 976; }
+int do_977() { return 977; }
+int do_978() { return 978; }
+int do_979() { return 979; }
+int do_980() { return 980; }
+int do_981() { return 981; }
+int do_982() { return 982; }
+int do_983() { return 983; }
+int do_984() { return 984; }
+int do_985() { return 985; }
+int do_986() { return 986; }
+int do_987() { return 987; }
+int do_988() { return 988; }
+int do_989() { return 989; }
+int do_990() { return 990; }
+int do_991() { return 991; }
+int do_992() { return 992; }
+int do_993() { return 993; }
+int do_994() { return 994; }
+int do_995() { return 995; }
+int do_996() { return 996; }
+int do_997() { return 997; }
+int do_998() { return 998; }
+int do_999() { return 999; }
diff --git a/unit-tests/test-cases/threaded-lazy-bind/gen.c b/unit-tests/test-cases/threaded-lazy-bind/gen.c
new file mode 100644 (file)
index 0000000..03bd744
--- /dev/null
@@ -0,0 +1,19 @@
+
+#include <stdio.h>
+
+int main()
+{
+       int i;
+       for (i = 0; i < 1000; ++i) {
+               printf("int do_%03d() { return %d; }\n", i, i);
+       }
+
+       for (i = 0; i < 1000; ++i) {
+               printf("extern int do_%03d();\n", i);
+       }
+       for (i = 0; i < 1000; ++i) {
+               printf("if ( do_%03d() != %d ) { FAIL(\"iteration %d\"); exit(0); }\n", i, i, i);
+       }
+
+       return 0;
+}
\ No newline at end of file
diff --git a/unit-tests/test-cases/threaded-lazy-bind/main.c b/unit-tests/test-cases/threaded-lazy-bind/main.c
new file mode 100644 (file)
index 0000000..ebb0e0d
--- /dev/null
@@ -0,0 +1,2060 @@
+/*
+ * 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>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <string.h>
+#include <dlfcn.h>
+#include <pthread.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+///
+/// Test that lazy binding is thread safe
+///
+
+extern int do_000();
+extern int do_001();
+extern int do_002();
+extern int do_003();
+extern int do_004();
+extern int do_005();
+extern int do_006();
+extern int do_007();
+extern int do_008();
+extern int do_009();
+extern int do_010();
+extern int do_011();
+extern int do_012();
+extern int do_013();
+extern int do_014();
+extern int do_015();
+extern int do_016();
+extern int do_017();
+extern int do_018();
+extern int do_019();
+extern int do_020();
+extern int do_021();
+extern int do_022();
+extern int do_023();
+extern int do_024();
+extern int do_025();
+extern int do_026();
+extern int do_027();
+extern int do_028();
+extern int do_029();
+extern int do_030();
+extern int do_031();
+extern int do_032();
+extern int do_033();
+extern int do_034();
+extern int do_035();
+extern int do_036();
+extern int do_037();
+extern int do_038();
+extern int do_039();
+extern int do_040();
+extern int do_041();
+extern int do_042();
+extern int do_043();
+extern int do_044();
+extern int do_045();
+extern int do_046();
+extern int do_047();
+extern int do_048();
+extern int do_049();
+extern int do_050();
+extern int do_051();
+extern int do_052();
+extern int do_053();
+extern int do_054();
+extern int do_055();
+extern int do_056();
+extern int do_057();
+extern int do_058();
+extern int do_059();
+extern int do_060();
+extern int do_061();
+extern int do_062();
+extern int do_063();
+extern int do_064();
+extern int do_065();
+extern int do_066();
+extern int do_067();
+extern int do_068();
+extern int do_069();
+extern int do_070();
+extern int do_071();
+extern int do_072();
+extern int do_073();
+extern int do_074();
+extern int do_075();
+extern int do_076();
+extern int do_077();
+extern int do_078();
+extern int do_079();
+extern int do_080();
+extern int do_081();
+extern int do_082();
+extern int do_083();
+extern int do_084();
+extern int do_085();
+extern int do_086();
+extern int do_087();
+extern int do_088();
+extern int do_089();
+extern int do_090();
+extern int do_091();
+extern int do_092();
+extern int do_093();
+extern int do_094();
+extern int do_095();
+extern int do_096();
+extern int do_097();
+extern int do_098();
+extern int do_099();
+extern int do_100();
+extern int do_101();
+extern int do_102();
+extern int do_103();
+extern int do_104();
+extern int do_105();
+extern int do_106();
+extern int do_107();
+extern int do_108();
+extern int do_109();
+extern int do_110();
+extern int do_111();
+extern int do_112();
+extern int do_113();
+extern int do_114();
+extern int do_115();
+extern int do_116();
+extern int do_117();
+extern int do_118();
+extern int do_119();
+extern int do_120();
+extern int do_121();
+extern int do_122();
+extern int do_123();
+extern int do_124();
+extern int do_125();
+extern int do_126();
+extern int do_127();
+extern int do_128();
+extern int do_129();
+extern int do_130();
+extern int do_131();
+extern int do_132();
+extern int do_133();
+extern int do_134();
+extern int do_135();
+extern int do_136();
+extern int do_137();
+extern int do_138();
+extern int do_139();
+extern int do_140();
+extern int do_141();
+extern int do_142();
+extern int do_143();
+extern int do_144();
+extern int do_145();
+extern int do_146();
+extern int do_147();
+extern int do_148();
+extern int do_149();
+extern int do_150();
+extern int do_151();
+extern int do_152();
+extern int do_153();
+extern int do_154();
+extern int do_155();
+extern int do_156();
+extern int do_157();
+extern int do_158();
+extern int do_159();
+extern int do_160();
+extern int do_161();
+extern int do_162();
+extern int do_163();
+extern int do_164();
+extern int do_165();
+extern int do_166();
+extern int do_167();
+extern int do_168();
+extern int do_169();
+extern int do_170();
+extern int do_171();
+extern int do_172();
+extern int do_173();
+extern int do_174();
+extern int do_175();
+extern int do_176();
+extern int do_177();
+extern int do_178();
+extern int do_179();
+extern int do_180();
+extern int do_181();
+extern int do_182();
+extern int do_183();
+extern int do_184();
+extern int do_185();
+extern int do_186();
+extern int do_187();
+extern int do_188();
+extern int do_189();
+extern int do_190();
+extern int do_191();
+extern int do_192();
+extern int do_193();
+extern int do_194();
+extern int do_195();
+extern int do_196();
+extern int do_197();
+extern int do_198();
+extern int do_199();
+extern int do_200();
+extern int do_201();
+extern int do_202();
+extern int do_203();
+extern int do_204();
+extern int do_205();
+extern int do_206();
+extern int do_207();
+extern int do_208();
+extern int do_209();
+extern int do_210();
+extern int do_211();
+extern int do_212();
+extern int do_213();
+extern int do_214();
+extern int do_215();
+extern int do_216();
+extern int do_217();
+extern int do_218();
+extern int do_219();
+extern int do_220();
+extern int do_221();
+extern int do_222();
+extern int do_223();
+extern int do_224();
+extern int do_225();
+extern int do_226();
+extern int do_227();
+extern int do_228();
+extern int do_229();
+extern int do_230();
+extern int do_231();
+extern int do_232();
+extern int do_233();
+extern int do_234();
+extern int do_235();
+extern int do_236();
+extern int do_237();
+extern int do_238();
+extern int do_239();
+extern int do_240();
+extern int do_241();
+extern int do_242();
+extern int do_243();
+extern int do_244();
+extern int do_245();
+extern int do_246();
+extern int do_247();
+extern int do_248();
+extern int do_249();
+extern int do_250();
+extern int do_251();
+extern int do_252();
+extern int do_253();
+extern int do_254();
+extern int do_255();
+extern int do_256();
+extern int do_257();
+extern int do_258();
+extern int do_259();
+extern int do_260();
+extern int do_261();
+extern int do_262();
+extern int do_263();
+extern int do_264();
+extern int do_265();
+extern int do_266();
+extern int do_267();
+extern int do_268();
+extern int do_269();
+extern int do_270();
+extern int do_271();
+extern int do_272();
+extern int do_273();
+extern int do_274();
+extern int do_275();
+extern int do_276();
+extern int do_277();
+extern int do_278();
+extern int do_279();
+extern int do_280();
+extern int do_281();
+extern int do_282();
+extern int do_283();
+extern int do_284();
+extern int do_285();
+extern int do_286();
+extern int do_287();
+extern int do_288();
+extern int do_289();
+extern int do_290();
+extern int do_291();
+extern int do_292();
+extern int do_293();
+extern int do_294();
+extern int do_295();
+extern int do_296();
+extern int do_297();
+extern int do_298();
+extern int do_299();
+extern int do_300();
+extern int do_301();
+extern int do_302();
+extern int do_303();
+extern int do_304();
+extern int do_305();
+extern int do_306();
+extern int do_307();
+extern int do_308();
+extern int do_309();
+extern int do_310();
+extern int do_311();
+extern int do_312();
+extern int do_313();
+extern int do_314();
+extern int do_315();
+extern int do_316();
+extern int do_317();
+extern int do_318();
+extern int do_319();
+extern int do_320();
+extern int do_321();
+extern int do_322();
+extern int do_323();
+extern int do_324();
+extern int do_325();
+extern int do_326();
+extern int do_327();
+extern int do_328();
+extern int do_329();
+extern int do_330();
+extern int do_331();
+extern int do_332();
+extern int do_333();
+extern int do_334();
+extern int do_335();
+extern int do_336();
+extern int do_337();
+extern int do_338();
+extern int do_339();
+extern int do_340();
+extern int do_341();
+extern int do_342();
+extern int do_343();
+extern int do_344();
+extern int do_345();
+extern int do_346();
+extern int do_347();
+extern int do_348();
+extern int do_349();
+extern int do_350();
+extern int do_351();
+extern int do_352();
+extern int do_353();
+extern int do_354();
+extern int do_355();
+extern int do_356();
+extern int do_357();
+extern int do_358();
+extern int do_359();
+extern int do_360();
+extern int do_361();
+extern int do_362();
+extern int do_363();
+extern int do_364();
+extern int do_365();
+extern int do_366();
+extern int do_367();
+extern int do_368();
+extern int do_369();
+extern int do_370();
+extern int do_371();
+extern int do_372();
+extern int do_373();
+extern int do_374();
+extern int do_375();
+extern int do_376();
+extern int do_377();
+extern int do_378();
+extern int do_379();
+extern int do_380();
+extern int do_381();
+extern int do_382();
+extern int do_383();
+extern int do_384();
+extern int do_385();
+extern int do_386();
+extern int do_387();
+extern int do_388();
+extern int do_389();
+extern int do_390();
+extern int do_391();
+extern int do_392();
+extern int do_393();
+extern int do_394();
+extern int do_395();
+extern int do_396();
+extern int do_397();
+extern int do_398();
+extern int do_399();
+extern int do_400();
+extern int do_401();
+extern int do_402();
+extern int do_403();
+extern int do_404();
+extern int do_405();
+extern int do_406();
+extern int do_407();
+extern int do_408();
+extern int do_409();
+extern int do_410();
+extern int do_411();
+extern int do_412();
+extern int do_413();
+extern int do_414();
+extern int do_415();
+extern int do_416();
+extern int do_417();
+extern int do_418();
+extern int do_419();
+extern int do_420();
+extern int do_421();
+extern int do_422();
+extern int do_423();
+extern int do_424();
+extern int do_425();
+extern int do_426();
+extern int do_427();
+extern int do_428();
+extern int do_429();
+extern int do_430();
+extern int do_431();
+extern int do_432();
+extern int do_433();
+extern int do_434();
+extern int do_435();
+extern int do_436();
+extern int do_437();
+extern int do_438();
+extern int do_439();
+extern int do_440();
+extern int do_441();
+extern int do_442();
+extern int do_443();
+extern int do_444();
+extern int do_445();
+extern int do_446();
+extern int do_447();
+extern int do_448();
+extern int do_449();
+extern int do_450();
+extern int do_451();
+extern int do_452();
+extern int do_453();
+extern int do_454();
+extern int do_455();
+extern int do_456();
+extern int do_457();
+extern int do_458();
+extern int do_459();
+extern int do_460();
+extern int do_461();
+extern int do_462();
+extern int do_463();
+extern int do_464();
+extern int do_465();
+extern int do_466();
+extern int do_467();
+extern int do_468();
+extern int do_469();
+extern int do_470();
+extern int do_471();
+extern int do_472();
+extern int do_473();
+extern int do_474();
+extern int do_475();
+extern int do_476();
+extern int do_477();
+extern int do_478();
+extern int do_479();
+extern int do_480();
+extern int do_481();
+extern int do_482();
+extern int do_483();
+extern int do_484();
+extern int do_485();
+extern int do_486();
+extern int do_487();
+extern int do_488();
+extern int do_489();
+extern int do_490();
+extern int do_491();
+extern int do_492();
+extern int do_493();
+extern int do_494();
+extern int do_495();
+extern int do_496();
+extern int do_497();
+extern int do_498();
+extern int do_499();
+extern int do_500();
+extern int do_501();
+extern int do_502();
+extern int do_503();
+extern int do_504();
+extern int do_505();
+extern int do_506();
+extern int do_507();
+extern int do_508();
+extern int do_509();
+extern int do_510();
+extern int do_511();
+extern int do_512();
+extern int do_513();
+extern int do_514();
+extern int do_515();
+extern int do_516();
+extern int do_517();
+extern int do_518();
+extern int do_519();
+extern int do_520();
+extern int do_521();
+extern int do_522();
+extern int do_523();
+extern int do_524();
+extern int do_525();
+extern int do_526();
+extern int do_527();
+extern int do_528();
+extern int do_529();
+extern int do_530();
+extern int do_531();
+extern int do_532();
+extern int do_533();
+extern int do_534();
+extern int do_535();
+extern int do_536();
+extern int do_537();
+extern int do_538();
+extern int do_539();
+extern int do_540();
+extern int do_541();
+extern int do_542();
+extern int do_543();
+extern int do_544();
+extern int do_545();
+extern int do_546();
+extern int do_547();
+extern int do_548();
+extern int do_549();
+extern int do_550();
+extern int do_551();
+extern int do_552();
+extern int do_553();
+extern int do_554();
+extern int do_555();
+extern int do_556();
+extern int do_557();
+extern int do_558();
+extern int do_559();
+extern int do_560();
+extern int do_561();
+extern int do_562();
+extern int do_563();
+extern int do_564();
+extern int do_565();
+extern int do_566();
+extern int do_567();
+extern int do_568();
+extern int do_569();
+extern int do_570();
+extern int do_571();
+extern int do_572();
+extern int do_573();
+extern int do_574();
+extern int do_575();
+extern int do_576();
+extern int do_577();
+extern int do_578();
+extern int do_579();
+extern int do_580();
+extern int do_581();
+extern int do_582();
+extern int do_583();
+extern int do_584();
+extern int do_585();
+extern int do_586();
+extern int do_587();
+extern int do_588();
+extern int do_589();
+extern int do_590();
+extern int do_591();
+extern int do_592();
+extern int do_593();
+extern int do_594();
+extern int do_595();
+extern int do_596();
+extern int do_597();
+extern int do_598();
+extern int do_599();
+extern int do_600();
+extern int do_601();
+extern int do_602();
+extern int do_603();
+extern int do_604();
+extern int do_605();
+extern int do_606();
+extern int do_607();
+extern int do_608();
+extern int do_609();
+extern int do_610();
+extern int do_611();
+extern int do_612();
+extern int do_613();
+extern int do_614();
+extern int do_615();
+extern int do_616();
+extern int do_617();
+extern int do_618();
+extern int do_619();
+extern int do_620();
+extern int do_621();
+extern int do_622();
+extern int do_623();
+extern int do_624();
+extern int do_625();
+extern int do_626();
+extern int do_627();
+extern int do_628();
+extern int do_629();
+extern int do_630();
+extern int do_631();
+extern int do_632();
+extern int do_633();
+extern int do_634();
+extern int do_635();
+extern int do_636();
+extern int do_637();
+extern int do_638();
+extern int do_639();
+extern int do_640();
+extern int do_641();
+extern int do_642();
+extern int do_643();
+extern int do_644();
+extern int do_645();
+extern int do_646();
+extern int do_647();
+extern int do_648();
+extern int do_649();
+extern int do_650();
+extern int do_651();
+extern int do_652();
+extern int do_653();
+extern int do_654();
+extern int do_655();
+extern int do_656();
+extern int do_657();
+extern int do_658();
+extern int do_659();
+extern int do_660();
+extern int do_661();
+extern int do_662();
+extern int do_663();
+extern int do_664();
+extern int do_665();
+extern int do_666();
+extern int do_667();
+extern int do_668();
+extern int do_669();
+extern int do_670();
+extern int do_671();
+extern int do_672();
+extern int do_673();
+extern int do_674();
+extern int do_675();
+extern int do_676();
+extern int do_677();
+extern int do_678();
+extern int do_679();
+extern int do_680();
+extern int do_681();
+extern int do_682();
+extern int do_683();
+extern int do_684();
+extern int do_685();
+extern int do_686();
+extern int do_687();
+extern int do_688();
+extern int do_689();
+extern int do_690();
+extern int do_691();
+extern int do_692();
+extern int do_693();
+extern int do_694();
+extern int do_695();
+extern int do_696();
+extern int do_697();
+extern int do_698();
+extern int do_699();
+extern int do_700();
+extern int do_701();
+extern int do_702();
+extern int do_703();
+extern int do_704();
+extern int do_705();
+extern int do_706();
+extern int do_707();
+extern int do_708();
+extern int do_709();
+extern int do_710();
+extern int do_711();
+extern int do_712();
+extern int do_713();
+extern int do_714();
+extern int do_715();
+extern int do_716();
+extern int do_717();
+extern int do_718();
+extern int do_719();
+extern int do_720();
+extern int do_721();
+extern int do_722();
+extern int do_723();
+extern int do_724();
+extern int do_725();
+extern int do_726();
+extern int do_727();
+extern int do_728();
+extern int do_729();
+extern int do_730();
+extern int do_731();
+extern int do_732();
+extern int do_733();
+extern int do_734();
+extern int do_735();
+extern int do_736();
+extern int do_737();
+extern int do_738();
+extern int do_739();
+extern int do_740();
+extern int do_741();
+extern int do_742();
+extern int do_743();
+extern int do_744();
+extern int do_745();
+extern int do_746();
+extern int do_747();
+extern int do_748();
+extern int do_749();
+extern int do_750();
+extern int do_751();
+extern int do_752();
+extern int do_753();
+extern int do_754();
+extern int do_755();
+extern int do_756();
+extern int do_757();
+extern int do_758();
+extern int do_759();
+extern int do_760();
+extern int do_761();
+extern int do_762();
+extern int do_763();
+extern int do_764();
+extern int do_765();
+extern int do_766();
+extern int do_767();
+extern int do_768();
+extern int do_769();
+extern int do_770();
+extern int do_771();
+extern int do_772();
+extern int do_773();
+extern int do_774();
+extern int do_775();
+extern int do_776();
+extern int do_777();
+extern int do_778();
+extern int do_779();
+extern int do_780();
+extern int do_781();
+extern int do_782();
+extern int do_783();
+extern int do_784();
+extern int do_785();
+extern int do_786();
+extern int do_787();
+extern int do_788();
+extern int do_789();
+extern int do_790();
+extern int do_791();
+extern int do_792();
+extern int do_793();
+extern int do_794();
+extern int do_795();
+extern int do_796();
+extern int do_797();
+extern int do_798();
+extern int do_799();
+extern int do_800();
+extern int do_801();
+extern int do_802();
+extern int do_803();
+extern int do_804();
+extern int do_805();
+extern int do_806();
+extern int do_807();
+extern int do_808();
+extern int do_809();
+extern int do_810();
+extern int do_811();
+extern int do_812();
+extern int do_813();
+extern int do_814();
+extern int do_815();
+extern int do_816();
+extern int do_817();
+extern int do_818();
+extern int do_819();
+extern int do_820();
+extern int do_821();
+extern int do_822();
+extern int do_823();
+extern int do_824();
+extern int do_825();
+extern int do_826();
+extern int do_827();
+extern int do_828();
+extern int do_829();
+extern int do_830();
+extern int do_831();
+extern int do_832();
+extern int do_833();
+extern int do_834();
+extern int do_835();
+extern int do_836();
+extern int do_837();
+extern int do_838();
+extern int do_839();
+extern int do_840();
+extern int do_841();
+extern int do_842();
+extern int do_843();
+extern int do_844();
+extern int do_845();
+extern int do_846();
+extern int do_847();
+extern int do_848();
+extern int do_849();
+extern int do_850();
+extern int do_851();
+extern int do_852();
+extern int do_853();
+extern int do_854();
+extern int do_855();
+extern int do_856();
+extern int do_857();
+extern int do_858();
+extern int do_859();
+extern int do_860();
+extern int do_861();
+extern int do_862();
+extern int do_863();
+extern int do_864();
+extern int do_865();
+extern int do_866();
+extern int do_867();
+extern int do_868();
+extern int do_869();
+extern int do_870();
+extern int do_871();
+extern int do_872();
+extern int do_873();
+extern int do_874();
+extern int do_875();
+extern int do_876();
+extern int do_877();
+extern int do_878();
+extern int do_879();
+extern int do_880();
+extern int do_881();
+extern int do_882();
+extern int do_883();
+extern int do_884();
+extern int do_885();
+extern int do_886();
+extern int do_887();
+extern int do_888();
+extern int do_889();
+extern int do_890();
+extern int do_891();
+extern int do_892();
+extern int do_893();
+extern int do_894();
+extern int do_895();
+extern int do_896();
+extern int do_897();
+extern int do_898();
+extern int do_899();
+extern int do_900();
+extern int do_901();
+extern int do_902();
+extern int do_903();
+extern int do_904();
+extern int do_905();
+extern int do_906();
+extern int do_907();
+extern int do_908();
+extern int do_909();
+extern int do_910();
+extern int do_911();
+extern int do_912();
+extern int do_913();
+extern int do_914();
+extern int do_915();
+extern int do_916();
+extern int do_917();
+extern int do_918();
+extern int do_919();
+extern int do_920();
+extern int do_921();
+extern int do_922();
+extern int do_923();
+extern int do_924();
+extern int do_925();
+extern int do_926();
+extern int do_927();
+extern int do_928();
+extern int do_929();
+extern int do_930();
+extern int do_931();
+extern int do_932();
+extern int do_933();
+extern int do_934();
+extern int do_935();
+extern int do_936();
+extern int do_937();
+extern int do_938();
+extern int do_939();
+extern int do_940();
+extern int do_941();
+extern int do_942();
+extern int do_943();
+extern int do_944();
+extern int do_945();
+extern int do_946();
+extern int do_947();
+extern int do_948();
+extern int do_949();
+extern int do_950();
+extern int do_951();
+extern int do_952();
+extern int do_953();
+extern int do_954();
+extern int do_955();
+extern int do_956();
+extern int do_957();
+extern int do_958();
+extern int do_959();
+extern int do_960();
+extern int do_961();
+extern int do_962();
+extern int do_963();
+extern int do_964();
+extern int do_965();
+extern int do_966();
+extern int do_967();
+extern int do_968();
+extern int do_969();
+extern int do_970();
+extern int do_971();
+extern int do_972();
+extern int do_973();
+extern int do_974();
+extern int do_975();
+extern int do_976();
+extern int do_977();
+extern int do_978();
+extern int do_979();
+extern int do_980();
+extern int do_981();
+extern int do_982();
+extern int do_983();
+extern int do_984();
+extern int do_985();
+extern int do_986();
+extern int do_987();
+extern int do_988();
+extern int do_989();
+extern int do_990();
+extern int do_991();
+extern int do_992();
+extern int do_993();
+extern int do_994();
+extern int do_995();
+extern int do_996();
+extern int do_997();
+extern int do_998();
+extern int do_999();
+
+
+static void* work(void* ignore)
+{
+       if ( do_000() != 0 ) { FAIL("iteration 0"); exit(0); }
+       if ( do_001() != 1 ) { FAIL("iteration 1"); exit(0); }
+       if ( do_002() != 2 ) { FAIL("iteration 2"); exit(0); }
+       if ( do_003() != 3 ) { FAIL("iteration 3"); exit(0); }
+       if ( do_004() != 4 ) { FAIL("iteration 4"); exit(0); }
+       if ( do_005() != 5 ) { FAIL("iteration 5"); exit(0); }
+       if ( do_006() != 6 ) { FAIL("iteration 6"); exit(0); }
+       if ( do_007() != 7 ) { FAIL("iteration 7"); exit(0); }
+       if ( do_008() != 8 ) { FAIL("iteration 8"); exit(0); }
+       if ( do_009() != 9 ) { FAIL("iteration 9"); exit(0); }
+       if ( do_010() != 10 ) { FAIL("iteration 10"); exit(0); }
+       if ( do_011() != 11 ) { FAIL("iteration 11"); exit(0); }
+       if ( do_012() != 12 ) { FAIL("iteration 12"); exit(0); }
+       if ( do_013() != 13 ) { FAIL("iteration 13"); exit(0); }
+       if ( do_014() != 14 ) { FAIL("iteration 14"); exit(0); }
+       if ( do_015() != 15 ) { FAIL("iteration 15"); exit(0); }
+       if ( do_016() != 16 ) { FAIL("iteration 16"); exit(0); }
+       if ( do_017() != 17 ) { FAIL("iteration 17"); exit(0); }
+       if ( do_018() != 18 ) { FAIL("iteration 18"); exit(0); }
+       if ( do_019() != 19 ) { FAIL("iteration 19"); exit(0); }
+       if ( do_020() != 20 ) { FAIL("iteration 20"); exit(0); }
+       if ( do_021() != 21 ) { FAIL("iteration 21"); exit(0); }
+       if ( do_022() != 22 ) { FAIL("iteration 22"); exit(0); }
+       if ( do_023() != 23 ) { FAIL("iteration 23"); exit(0); }
+       if ( do_024() != 24 ) { FAIL("iteration 24"); exit(0); }
+       if ( do_025() != 25 ) { FAIL("iteration 25"); exit(0); }
+       if ( do_026() != 26 ) { FAIL("iteration 26"); exit(0); }
+       if ( do_027() != 27 ) { FAIL("iteration 27"); exit(0); }
+       if ( do_028() != 28 ) { FAIL("iteration 28"); exit(0); }
+       if ( do_029() != 29 ) { FAIL("iteration 29"); exit(0); }
+       if ( do_030() != 30 ) { FAIL("iteration 30"); exit(0); }
+       if ( do_031() != 31 ) { FAIL("iteration 31"); exit(0); }
+       if ( do_032() != 32 ) { FAIL("iteration 32"); exit(0); }
+       if ( do_033() != 33 ) { FAIL("iteration 33"); exit(0); }
+       if ( do_034() != 34 ) { FAIL("iteration 34"); exit(0); }
+       if ( do_035() != 35 ) { FAIL("iteration 35"); exit(0); }
+       if ( do_036() != 36 ) { FAIL("iteration 36"); exit(0); }
+       if ( do_037() != 37 ) { FAIL("iteration 37"); exit(0); }
+       if ( do_038() != 38 ) { FAIL("iteration 38"); exit(0); }
+       if ( do_039() != 39 ) { FAIL("iteration 39"); exit(0); }
+       if ( do_040() != 40 ) { FAIL("iteration 40"); exit(0); }
+       if ( do_041() != 41 ) { FAIL("iteration 41"); exit(0); }
+       if ( do_042() != 42 ) { FAIL("iteration 42"); exit(0); }
+       if ( do_043() != 43 ) { FAIL("iteration 43"); exit(0); }
+       if ( do_044() != 44 ) { FAIL("iteration 44"); exit(0); }
+       if ( do_045() != 45 ) { FAIL("iteration 45"); exit(0); }
+       if ( do_046() != 46 ) { FAIL("iteration 46"); exit(0); }
+       if ( do_047() != 47 ) { FAIL("iteration 47"); exit(0); }
+       if ( do_048() != 48 ) { FAIL("iteration 48"); exit(0); }
+       if ( do_049() != 49 ) { FAIL("iteration 49"); exit(0); }
+       if ( do_050() != 50 ) { FAIL("iteration 50"); exit(0); }
+       if ( do_051() != 51 ) { FAIL("iteration 51"); exit(0); }
+       if ( do_052() != 52 ) { FAIL("iteration 52"); exit(0); }
+       if ( do_053() != 53 ) { FAIL("iteration 53"); exit(0); }
+       if ( do_054() != 54 ) { FAIL("iteration 54"); exit(0); }
+       if ( do_055() != 55 ) { FAIL("iteration 55"); exit(0); }
+       if ( do_056() != 56 ) { FAIL("iteration 56"); exit(0); }
+       if ( do_057() != 57 ) { FAIL("iteration 57"); exit(0); }
+       if ( do_058() != 58 ) { FAIL("iteration 58"); exit(0); }
+       if ( do_059() != 59 ) { FAIL("iteration 59"); exit(0); }
+       if ( do_060() != 60 ) { FAIL("iteration 60"); exit(0); }
+       if ( do_061() != 61 ) { FAIL("iteration 61"); exit(0); }
+       if ( do_062() != 62 ) { FAIL("iteration 62"); exit(0); }
+       if ( do_063() != 63 ) { FAIL("iteration 63"); exit(0); }
+       if ( do_064() != 64 ) { FAIL("iteration 64"); exit(0); }
+       if ( do_065() != 65 ) { FAIL("iteration 65"); exit(0); }
+       if ( do_066() != 66 ) { FAIL("iteration 66"); exit(0); }
+       if ( do_067() != 67 ) { FAIL("iteration 67"); exit(0); }
+       if ( do_068() != 68 ) { FAIL("iteration 68"); exit(0); }
+       if ( do_069() != 69 ) { FAIL("iteration 69"); exit(0); }
+       if ( do_070() != 70 ) { FAIL("iteration 70"); exit(0); }
+       if ( do_071() != 71 ) { FAIL("iteration 71"); exit(0); }
+       if ( do_072() != 72 ) { FAIL("iteration 72"); exit(0); }
+       if ( do_073() != 73 ) { FAIL("iteration 73"); exit(0); }
+       if ( do_074() != 74 ) { FAIL("iteration 74"); exit(0); }
+       if ( do_075() != 75 ) { FAIL("iteration 75"); exit(0); }
+       if ( do_076() != 76 ) { FAIL("iteration 76"); exit(0); }
+       if ( do_077() != 77 ) { FAIL("iteration 77"); exit(0); }
+       if ( do_078() != 78 ) { FAIL("iteration 78"); exit(0); }
+       if ( do_079() != 79 ) { FAIL("iteration 79"); exit(0); }
+       if ( do_080() != 80 ) { FAIL("iteration 80"); exit(0); }
+       if ( do_081() != 81 ) { FAIL("iteration 81"); exit(0); }
+       if ( do_082() != 82 ) { FAIL("iteration 82"); exit(0); }
+       if ( do_083() != 83 ) { FAIL("iteration 83"); exit(0); }
+       if ( do_084() != 84 ) { FAIL("iteration 84"); exit(0); }
+       if ( do_085() != 85 ) { FAIL("iteration 85"); exit(0); }
+       if ( do_086() != 86 ) { FAIL("iteration 86"); exit(0); }
+       if ( do_087() != 87 ) { FAIL("iteration 87"); exit(0); }
+       if ( do_088() != 88 ) { FAIL("iteration 88"); exit(0); }
+       if ( do_089() != 89 ) { FAIL("iteration 89"); exit(0); }
+       if ( do_090() != 90 ) { FAIL("iteration 90"); exit(0); }
+       if ( do_091() != 91 ) { FAIL("iteration 91"); exit(0); }
+       if ( do_092() != 92 ) { FAIL("iteration 92"); exit(0); }
+       if ( do_093() != 93 ) { FAIL("iteration 93"); exit(0); }
+       if ( do_094() != 94 ) { FAIL("iteration 94"); exit(0); }
+       if ( do_095() != 95 ) { FAIL("iteration 95"); exit(0); }
+       if ( do_096() != 96 ) { FAIL("iteration 96"); exit(0); }
+       if ( do_097() != 97 ) { FAIL("iteration 97"); exit(0); }
+       if ( do_098() != 98 ) { FAIL("iteration 98"); exit(0); }
+       if ( do_099() != 99 ) { FAIL("iteration 99"); exit(0); }
+       if ( do_100() != 100 ) { FAIL("iteration 100"); exit(0); }
+       if ( do_101() != 101 ) { FAIL("iteration 101"); exit(0); }
+       if ( do_102() != 102 ) { FAIL("iteration 102"); exit(0); }
+       if ( do_103() != 103 ) { FAIL("iteration 103"); exit(0); }
+       if ( do_104() != 104 ) { FAIL("iteration 104"); exit(0); }
+       if ( do_105() != 105 ) { FAIL("iteration 105"); exit(0); }
+       if ( do_106() != 106 ) { FAIL("iteration 106"); exit(0); }
+       if ( do_107() != 107 ) { FAIL("iteration 107"); exit(0); }
+       if ( do_108() != 108 ) { FAIL("iteration 108"); exit(0); }
+       if ( do_109() != 109 ) { FAIL("iteration 109"); exit(0); }
+       if ( do_110() != 110 ) { FAIL("iteration 110"); exit(0); }
+       if ( do_111() != 111 ) { FAIL("iteration 111"); exit(0); }
+       if ( do_112() != 112 ) { FAIL("iteration 112"); exit(0); }
+       if ( do_113() != 113 ) { FAIL("iteration 113"); exit(0); }
+       if ( do_114() != 114 ) { FAIL("iteration 114"); exit(0); }
+       if ( do_115() != 115 ) { FAIL("iteration 115"); exit(0); }
+       if ( do_116() != 116 ) { FAIL("iteration 116"); exit(0); }
+       if ( do_117() != 117 ) { FAIL("iteration 117"); exit(0); }
+       if ( do_118() != 118 ) { FAIL("iteration 118"); exit(0); }
+       if ( do_119() != 119 ) { FAIL("iteration 119"); exit(0); }
+       if ( do_120() != 120 ) { FAIL("iteration 120"); exit(0); }
+       if ( do_121() != 121 ) { FAIL("iteration 121"); exit(0); }
+       if ( do_122() != 122 ) { FAIL("iteration 122"); exit(0); }
+       if ( do_123() != 123 ) { FAIL("iteration 123"); exit(0); }
+       if ( do_124() != 124 ) { FAIL("iteration 124"); exit(0); }
+       if ( do_125() != 125 ) { FAIL("iteration 125"); exit(0); }
+       if ( do_126() != 126 ) { FAIL("iteration 126"); exit(0); }
+       if ( do_127() != 127 ) { FAIL("iteration 127"); exit(0); }
+       if ( do_128() != 128 ) { FAIL("iteration 128"); exit(0); }
+       if ( do_129() != 129 ) { FAIL("iteration 129"); exit(0); }
+       if ( do_130() != 130 ) { FAIL("iteration 130"); exit(0); }
+       if ( do_131() != 131 ) { FAIL("iteration 131"); exit(0); }
+       if ( do_132() != 132 ) { FAIL("iteration 132"); exit(0); }
+       if ( do_133() != 133 ) { FAIL("iteration 133"); exit(0); }
+       if ( do_134() != 134 ) { FAIL("iteration 134"); exit(0); }
+       if ( do_135() != 135 ) { FAIL("iteration 135"); exit(0); }
+       if ( do_136() != 136 ) { FAIL("iteration 136"); exit(0); }
+       if ( do_137() != 137 ) { FAIL("iteration 137"); exit(0); }
+       if ( do_138() != 138 ) { FAIL("iteration 138"); exit(0); }
+       if ( do_139() != 139 ) { FAIL("iteration 139"); exit(0); }
+       if ( do_140() != 140 ) { FAIL("iteration 140"); exit(0); }
+       if ( do_141() != 141 ) { FAIL("iteration 141"); exit(0); }
+       if ( do_142() != 142 ) { FAIL("iteration 142"); exit(0); }
+       if ( do_143() != 143 ) { FAIL("iteration 143"); exit(0); }
+       if ( do_144() != 144 ) { FAIL("iteration 144"); exit(0); }
+       if ( do_145() != 145 ) { FAIL("iteration 145"); exit(0); }
+       if ( do_146() != 146 ) { FAIL("iteration 146"); exit(0); }
+       if ( do_147() != 147 ) { FAIL("iteration 147"); exit(0); }
+       if ( do_148() != 148 ) { FAIL("iteration 148"); exit(0); }
+       if ( do_149() != 149 ) { FAIL("iteration 149"); exit(0); }
+       if ( do_150() != 150 ) { FAIL("iteration 150"); exit(0); }
+       if ( do_151() != 151 ) { FAIL("iteration 151"); exit(0); }
+       if ( do_152() != 152 ) { FAIL("iteration 152"); exit(0); }
+       if ( do_153() != 153 ) { FAIL("iteration 153"); exit(0); }
+       if ( do_154() != 154 ) { FAIL("iteration 154"); exit(0); }
+       if ( do_155() != 155 ) { FAIL("iteration 155"); exit(0); }
+       if ( do_156() != 156 ) { FAIL("iteration 156"); exit(0); }
+       if ( do_157() != 157 ) { FAIL("iteration 157"); exit(0); }
+       if ( do_158() != 158 ) { FAIL("iteration 158"); exit(0); }
+       if ( do_159() != 159 ) { FAIL("iteration 159"); exit(0); }
+       if ( do_160() != 160 ) { FAIL("iteration 160"); exit(0); }
+       if ( do_161() != 161 ) { FAIL("iteration 161"); exit(0); }
+       if ( do_162() != 162 ) { FAIL("iteration 162"); exit(0); }
+       if ( do_163() != 163 ) { FAIL("iteration 163"); exit(0); }
+       if ( do_164() != 164 ) { FAIL("iteration 164"); exit(0); }
+       if ( do_165() != 165 ) { FAIL("iteration 165"); exit(0); }
+       if ( do_166() != 166 ) { FAIL("iteration 166"); exit(0); }
+       if ( do_167() != 167 ) { FAIL("iteration 167"); exit(0); }
+       if ( do_168() != 168 ) { FAIL("iteration 168"); exit(0); }
+       if ( do_169() != 169 ) { FAIL("iteration 169"); exit(0); }
+       if ( do_170() != 170 ) { FAIL("iteration 170"); exit(0); }
+       if ( do_171() != 171 ) { FAIL("iteration 171"); exit(0); }
+       if ( do_172() != 172 ) { FAIL("iteration 172"); exit(0); }
+       if ( do_173() != 173 ) { FAIL("iteration 173"); exit(0); }
+       if ( do_174() != 174 ) { FAIL("iteration 174"); exit(0); }
+       if ( do_175() != 175 ) { FAIL("iteration 175"); exit(0); }
+       if ( do_176() != 176 ) { FAIL("iteration 176"); exit(0); }
+       if ( do_177() != 177 ) { FAIL("iteration 177"); exit(0); }
+       if ( do_178() != 178 ) { FAIL("iteration 178"); exit(0); }
+       if ( do_179() != 179 ) { FAIL("iteration 179"); exit(0); }
+       if ( do_180() != 180 ) { FAIL("iteration 180"); exit(0); }
+       if ( do_181() != 181 ) { FAIL("iteration 181"); exit(0); }
+       if ( do_182() != 182 ) { FAIL("iteration 182"); exit(0); }
+       if ( do_183() != 183 ) { FAIL("iteration 183"); exit(0); }
+       if ( do_184() != 184 ) { FAIL("iteration 184"); exit(0); }
+       if ( do_185() != 185 ) { FAIL("iteration 185"); exit(0); }
+       if ( do_186() != 186 ) { FAIL("iteration 186"); exit(0); }
+       if ( do_187() != 187 ) { FAIL("iteration 187"); exit(0); }
+       if ( do_188() != 188 ) { FAIL("iteration 188"); exit(0); }
+       if ( do_189() != 189 ) { FAIL("iteration 189"); exit(0); }
+       if ( do_190() != 190 ) { FAIL("iteration 190"); exit(0); }
+       if ( do_191() != 191 ) { FAIL("iteration 191"); exit(0); }
+       if ( do_192() != 192 ) { FAIL("iteration 192"); exit(0); }
+       if ( do_193() != 193 ) { FAIL("iteration 193"); exit(0); }
+       if ( do_194() != 194 ) { FAIL("iteration 194"); exit(0); }
+       if ( do_195() != 195 ) { FAIL("iteration 195"); exit(0); }
+       if ( do_196() != 196 ) { FAIL("iteration 196"); exit(0); }
+       if ( do_197() != 197 ) { FAIL("iteration 197"); exit(0); }
+       if ( do_198() != 198 ) { FAIL("iteration 198"); exit(0); }
+       if ( do_199() != 199 ) { FAIL("iteration 199"); exit(0); }
+       if ( do_200() != 200 ) { FAIL("iteration 200"); exit(0); }
+       if ( do_201() != 201 ) { FAIL("iteration 201"); exit(0); }
+       if ( do_202() != 202 ) { FAIL("iteration 202"); exit(0); }
+       if ( do_203() != 203 ) { FAIL("iteration 203"); exit(0); }
+       if ( do_204() != 204 ) { FAIL("iteration 204"); exit(0); }
+       if ( do_205() != 205 ) { FAIL("iteration 205"); exit(0); }
+       if ( do_206() != 206 ) { FAIL("iteration 206"); exit(0); }
+       if ( do_207() != 207 ) { FAIL("iteration 207"); exit(0); }
+       if ( do_208() != 208 ) { FAIL("iteration 208"); exit(0); }
+       if ( do_209() != 209 ) { FAIL("iteration 209"); exit(0); }
+       if ( do_210() != 210 ) { FAIL("iteration 210"); exit(0); }
+       if ( do_211() != 211 ) { FAIL("iteration 211"); exit(0); }
+       if ( do_212() != 212 ) { FAIL("iteration 212"); exit(0); }
+       if ( do_213() != 213 ) { FAIL("iteration 213"); exit(0); }
+       if ( do_214() != 214 ) { FAIL("iteration 214"); exit(0); }
+       if ( do_215() != 215 ) { FAIL("iteration 215"); exit(0); }
+       if ( do_216() != 216 ) { FAIL("iteration 216"); exit(0); }
+       if ( do_217() != 217 ) { FAIL("iteration 217"); exit(0); }
+       if ( do_218() != 218 ) { FAIL("iteration 218"); exit(0); }
+       if ( do_219() != 219 ) { FAIL("iteration 219"); exit(0); }
+       if ( do_220() != 220 ) { FAIL("iteration 220"); exit(0); }
+       if ( do_221() != 221 ) { FAIL("iteration 221"); exit(0); }
+       if ( do_222() != 222 ) { FAIL("iteration 222"); exit(0); }
+       if ( do_223() != 223 ) { FAIL("iteration 223"); exit(0); }
+       if ( do_224() != 224 ) { FAIL("iteration 224"); exit(0); }
+       if ( do_225() != 225 ) { FAIL("iteration 225"); exit(0); }
+       if ( do_226() != 226 ) { FAIL("iteration 226"); exit(0); }
+       if ( do_227() != 227 ) { FAIL("iteration 227"); exit(0); }
+       if ( do_228() != 228 ) { FAIL("iteration 228"); exit(0); }
+       if ( do_229() != 229 ) { FAIL("iteration 229"); exit(0); }
+       if ( do_230() != 230 ) { FAIL("iteration 230"); exit(0); }
+       if ( do_231() != 231 ) { FAIL("iteration 231"); exit(0); }
+       if ( do_232() != 232 ) { FAIL("iteration 232"); exit(0); }
+       if ( do_233() != 233 ) { FAIL("iteration 233"); exit(0); }
+       if ( do_234() != 234 ) { FAIL("iteration 234"); exit(0); }
+       if ( do_235() != 235 ) { FAIL("iteration 235"); exit(0); }
+       if ( do_236() != 236 ) { FAIL("iteration 236"); exit(0); }
+       if ( do_237() != 237 ) { FAIL("iteration 237"); exit(0); }
+       if ( do_238() != 238 ) { FAIL("iteration 238"); exit(0); }
+       if ( do_239() != 239 ) { FAIL("iteration 239"); exit(0); }
+       if ( do_240() != 240 ) { FAIL("iteration 240"); exit(0); }
+       if ( do_241() != 241 ) { FAIL("iteration 241"); exit(0); }
+       if ( do_242() != 242 ) { FAIL("iteration 242"); exit(0); }
+       if ( do_243() != 243 ) { FAIL("iteration 243"); exit(0); }
+       if ( do_244() != 244 ) { FAIL("iteration 244"); exit(0); }
+       if ( do_245() != 245 ) { FAIL("iteration 245"); exit(0); }
+       if ( do_246() != 246 ) { FAIL("iteration 246"); exit(0); }
+       if ( do_247() != 247 ) { FAIL("iteration 247"); exit(0); }
+       if ( do_248() != 248 ) { FAIL("iteration 248"); exit(0); }
+       if ( do_249() != 249 ) { FAIL("iteration 249"); exit(0); }
+       if ( do_250() != 250 ) { FAIL("iteration 250"); exit(0); }
+       if ( do_251() != 251 ) { FAIL("iteration 251"); exit(0); }
+       if ( do_252() != 252 ) { FAIL("iteration 252"); exit(0); }
+       if ( do_253() != 253 ) { FAIL("iteration 253"); exit(0); }
+       if ( do_254() != 254 ) { FAIL("iteration 254"); exit(0); }
+       if ( do_255() != 255 ) { FAIL("iteration 255"); exit(0); }
+       if ( do_256() != 256 ) { FAIL("iteration 256"); exit(0); }
+       if ( do_257() != 257 ) { FAIL("iteration 257"); exit(0); }
+       if ( do_258() != 258 ) { FAIL("iteration 258"); exit(0); }
+       if ( do_259() != 259 ) { FAIL("iteration 259"); exit(0); }
+       if ( do_260() != 260 ) { FAIL("iteration 260"); exit(0); }
+       if ( do_261() != 261 ) { FAIL("iteration 261"); exit(0); }
+       if ( do_262() != 262 ) { FAIL("iteration 262"); exit(0); }
+       if ( do_263() != 263 ) { FAIL("iteration 263"); exit(0); }
+       if ( do_264() != 264 ) { FAIL("iteration 264"); exit(0); }
+       if ( do_265() != 265 ) { FAIL("iteration 265"); exit(0); }
+       if ( do_266() != 266 ) { FAIL("iteration 266"); exit(0); }
+       if ( do_267() != 267 ) { FAIL("iteration 267"); exit(0); }
+       if ( do_268() != 268 ) { FAIL("iteration 268"); exit(0); }
+       if ( do_269() != 269 ) { FAIL("iteration 269"); exit(0); }
+       if ( do_270() != 270 ) { FAIL("iteration 270"); exit(0); }
+       if ( do_271() != 271 ) { FAIL("iteration 271"); exit(0); }
+       if ( do_272() != 272 ) { FAIL("iteration 272"); exit(0); }
+       if ( do_273() != 273 ) { FAIL("iteration 273"); exit(0); }
+       if ( do_274() != 274 ) { FAIL("iteration 274"); exit(0); }
+       if ( do_275() != 275 ) { FAIL("iteration 275"); exit(0); }
+       if ( do_276() != 276 ) { FAIL("iteration 276"); exit(0); }
+       if ( do_277() != 277 ) { FAIL("iteration 277"); exit(0); }
+       if ( do_278() != 278 ) { FAIL("iteration 278"); exit(0); }
+       if ( do_279() != 279 ) { FAIL("iteration 279"); exit(0); }
+       if ( do_280() != 280 ) { FAIL("iteration 280"); exit(0); }
+       if ( do_281() != 281 ) { FAIL("iteration 281"); exit(0); }
+       if ( do_282() != 282 ) { FAIL("iteration 282"); exit(0); }
+       if ( do_283() != 283 ) { FAIL("iteration 283"); exit(0); }
+       if ( do_284() != 284 ) { FAIL("iteration 284"); exit(0); }
+       if ( do_285() != 285 ) { FAIL("iteration 285"); exit(0); }
+       if ( do_286() != 286 ) { FAIL("iteration 286"); exit(0); }
+       if ( do_287() != 287 ) { FAIL("iteration 287"); exit(0); }
+       if ( do_288() != 288 ) { FAIL("iteration 288"); exit(0); }
+       if ( do_289() != 289 ) { FAIL("iteration 289"); exit(0); }
+       if ( do_290() != 290 ) { FAIL("iteration 290"); exit(0); }
+       if ( do_291() != 291 ) { FAIL("iteration 291"); exit(0); }
+       if ( do_292() != 292 ) { FAIL("iteration 292"); exit(0); }
+       if ( do_293() != 293 ) { FAIL("iteration 293"); exit(0); }
+       if ( do_294() != 294 ) { FAIL("iteration 294"); exit(0); }
+       if ( do_295() != 295 ) { FAIL("iteration 295"); exit(0); }
+       if ( do_296() != 296 ) { FAIL("iteration 296"); exit(0); }
+       if ( do_297() != 297 ) { FAIL("iteration 297"); exit(0); }
+       if ( do_298() != 298 ) { FAIL("iteration 298"); exit(0); }
+       if ( do_299() != 299 ) { FAIL("iteration 299"); exit(0); }
+       if ( do_300() != 300 ) { FAIL("iteration 300"); exit(0); }
+       if ( do_301() != 301 ) { FAIL("iteration 301"); exit(0); }
+       if ( do_302() != 302 ) { FAIL("iteration 302"); exit(0); }
+       if ( do_303() != 303 ) { FAIL("iteration 303"); exit(0); }
+       if ( do_304() != 304 ) { FAIL("iteration 304"); exit(0); }
+       if ( do_305() != 305 ) { FAIL("iteration 305"); exit(0); }
+       if ( do_306() != 306 ) { FAIL("iteration 306"); exit(0); }
+       if ( do_307() != 307 ) { FAIL("iteration 307"); exit(0); }
+       if ( do_308() != 308 ) { FAIL("iteration 308"); exit(0); }
+       if ( do_309() != 309 ) { FAIL("iteration 309"); exit(0); }
+       if ( do_310() != 310 ) { FAIL("iteration 310"); exit(0); }
+       if ( do_311() != 311 ) { FAIL("iteration 311"); exit(0); }
+       if ( do_312() != 312 ) { FAIL("iteration 312"); exit(0); }
+       if ( do_313() != 313 ) { FAIL("iteration 313"); exit(0); }
+       if ( do_314() != 314 ) { FAIL("iteration 314"); exit(0); }
+       if ( do_315() != 315 ) { FAIL("iteration 315"); exit(0); }
+       if ( do_316() != 316 ) { FAIL("iteration 316"); exit(0); }
+       if ( do_317() != 317 ) { FAIL("iteration 317"); exit(0); }
+       if ( do_318() != 318 ) { FAIL("iteration 318"); exit(0); }
+       if ( do_319() != 319 ) { FAIL("iteration 319"); exit(0); }
+       if ( do_320() != 320 ) { FAIL("iteration 320"); exit(0); }
+       if ( do_321() != 321 ) { FAIL("iteration 321"); exit(0); }
+       if ( do_322() != 322 ) { FAIL("iteration 322"); exit(0); }
+       if ( do_323() != 323 ) { FAIL("iteration 323"); exit(0); }
+       if ( do_324() != 324 ) { FAIL("iteration 324"); exit(0); }
+       if ( do_325() != 325 ) { FAIL("iteration 325"); exit(0); }
+       if ( do_326() != 326 ) { FAIL("iteration 326"); exit(0); }
+       if ( do_327() != 327 ) { FAIL("iteration 327"); exit(0); }
+       if ( do_328() != 328 ) { FAIL("iteration 328"); exit(0); }
+       if ( do_329() != 329 ) { FAIL("iteration 329"); exit(0); }
+       if ( do_330() != 330 ) { FAIL("iteration 330"); exit(0); }
+       if ( do_331() != 331 ) { FAIL("iteration 331"); exit(0); }
+       if ( do_332() != 332 ) { FAIL("iteration 332"); exit(0); }
+       if ( do_333() != 333 ) { FAIL("iteration 333"); exit(0); }
+       if ( do_334() != 334 ) { FAIL("iteration 334"); exit(0); }
+       if ( do_335() != 335 ) { FAIL("iteration 335"); exit(0); }
+       if ( do_336() != 336 ) { FAIL("iteration 336"); exit(0); }
+       if ( do_337() != 337 ) { FAIL("iteration 337"); exit(0); }
+       if ( do_338() != 338 ) { FAIL("iteration 338"); exit(0); }
+       if ( do_339() != 339 ) { FAIL("iteration 339"); exit(0); }
+       if ( do_340() != 340 ) { FAIL("iteration 340"); exit(0); }
+       if ( do_341() != 341 ) { FAIL("iteration 341"); exit(0); }
+       if ( do_342() != 342 ) { FAIL("iteration 342"); exit(0); }
+       if ( do_343() != 343 ) { FAIL("iteration 343"); exit(0); }
+       if ( do_344() != 344 ) { FAIL("iteration 344"); exit(0); }
+       if ( do_345() != 345 ) { FAIL("iteration 345"); exit(0); }
+       if ( do_346() != 346 ) { FAIL("iteration 346"); exit(0); }
+       if ( do_347() != 347 ) { FAIL("iteration 347"); exit(0); }
+       if ( do_348() != 348 ) { FAIL("iteration 348"); exit(0); }
+       if ( do_349() != 349 ) { FAIL("iteration 349"); exit(0); }
+       if ( do_350() != 350 ) { FAIL("iteration 350"); exit(0); }
+       if ( do_351() != 351 ) { FAIL("iteration 351"); exit(0); }
+       if ( do_352() != 352 ) { FAIL("iteration 352"); exit(0); }
+       if ( do_353() != 353 ) { FAIL("iteration 353"); exit(0); }
+       if ( do_354() != 354 ) { FAIL("iteration 354"); exit(0); }
+       if ( do_355() != 355 ) { FAIL("iteration 355"); exit(0); }
+       if ( do_356() != 356 ) { FAIL("iteration 356"); exit(0); }
+       if ( do_357() != 357 ) { FAIL("iteration 357"); exit(0); }
+       if ( do_358() != 358 ) { FAIL("iteration 358"); exit(0); }
+       if ( do_359() != 359 ) { FAIL("iteration 359"); exit(0); }
+       if ( do_360() != 360 ) { FAIL("iteration 360"); exit(0); }
+       if ( do_361() != 361 ) { FAIL("iteration 361"); exit(0); }
+       if ( do_362() != 362 ) { FAIL("iteration 362"); exit(0); }
+       if ( do_363() != 363 ) { FAIL("iteration 363"); exit(0); }
+       if ( do_364() != 364 ) { FAIL("iteration 364"); exit(0); }
+       if ( do_365() != 365 ) { FAIL("iteration 365"); exit(0); }
+       if ( do_366() != 366 ) { FAIL("iteration 366"); exit(0); }
+       if ( do_367() != 367 ) { FAIL("iteration 367"); exit(0); }
+       if ( do_368() != 368 ) { FAIL("iteration 368"); exit(0); }
+       if ( do_369() != 369 ) { FAIL("iteration 369"); exit(0); }
+       if ( do_370() != 370 ) { FAIL("iteration 370"); exit(0); }
+       if ( do_371() != 371 ) { FAIL("iteration 371"); exit(0); }
+       if ( do_372() != 372 ) { FAIL("iteration 372"); exit(0); }
+       if ( do_373() != 373 ) { FAIL("iteration 373"); exit(0); }
+       if ( do_374() != 374 ) { FAIL("iteration 374"); exit(0); }
+       if ( do_375() != 375 ) { FAIL("iteration 375"); exit(0); }
+       if ( do_376() != 376 ) { FAIL("iteration 376"); exit(0); }
+       if ( do_377() != 377 ) { FAIL("iteration 377"); exit(0); }
+       if ( do_378() != 378 ) { FAIL("iteration 378"); exit(0); }
+       if ( do_379() != 379 ) { FAIL("iteration 379"); exit(0); }
+       if ( do_380() != 380 ) { FAIL("iteration 380"); exit(0); }
+       if ( do_381() != 381 ) { FAIL("iteration 381"); exit(0); }
+       if ( do_382() != 382 ) { FAIL("iteration 382"); exit(0); }
+       if ( do_383() != 383 ) { FAIL("iteration 383"); exit(0); }
+       if ( do_384() != 384 ) { FAIL("iteration 384"); exit(0); }
+       if ( do_385() != 385 ) { FAIL("iteration 385"); exit(0); }
+       if ( do_386() != 386 ) { FAIL("iteration 386"); exit(0); }
+       if ( do_387() != 387 ) { FAIL("iteration 387"); exit(0); }
+       if ( do_388() != 388 ) { FAIL("iteration 388"); exit(0); }
+       if ( do_389() != 389 ) { FAIL("iteration 389"); exit(0); }
+       if ( do_390() != 390 ) { FAIL("iteration 390"); exit(0); }
+       if ( do_391() != 391 ) { FAIL("iteration 391"); exit(0); }
+       if ( do_392() != 392 ) { FAIL("iteration 392"); exit(0); }
+       if ( do_393() != 393 ) { FAIL("iteration 393"); exit(0); }
+       if ( do_394() != 394 ) { FAIL("iteration 394"); exit(0); }
+       if ( do_395() != 395 ) { FAIL("iteration 395"); exit(0); }
+       if ( do_396() != 396 ) { FAIL("iteration 396"); exit(0); }
+       if ( do_397() != 397 ) { FAIL("iteration 397"); exit(0); }
+       if ( do_398() != 398 ) { FAIL("iteration 398"); exit(0); }
+       if ( do_399() != 399 ) { FAIL("iteration 399"); exit(0); }
+       if ( do_400() != 400 ) { FAIL("iteration 400"); exit(0); }
+       if ( do_401() != 401 ) { FAIL("iteration 401"); exit(0); }
+       if ( do_402() != 402 ) { FAIL("iteration 402"); exit(0); }
+       if ( do_403() != 403 ) { FAIL("iteration 403"); exit(0); }
+       if ( do_404() != 404 ) { FAIL("iteration 404"); exit(0); }
+       if ( do_405() != 405 ) { FAIL("iteration 405"); exit(0); }
+       if ( do_406() != 406 ) { FAIL("iteration 406"); exit(0); }
+       if ( do_407() != 407 ) { FAIL("iteration 407"); exit(0); }
+       if ( do_408() != 408 ) { FAIL("iteration 408"); exit(0); }
+       if ( do_409() != 409 ) { FAIL("iteration 409"); exit(0); }
+       if ( do_410() != 410 ) { FAIL("iteration 410"); exit(0); }
+       if ( do_411() != 411 ) { FAIL("iteration 411"); exit(0); }
+       if ( do_412() != 412 ) { FAIL("iteration 412"); exit(0); }
+       if ( do_413() != 413 ) { FAIL("iteration 413"); exit(0); }
+       if ( do_414() != 414 ) { FAIL("iteration 414"); exit(0); }
+       if ( do_415() != 415 ) { FAIL("iteration 415"); exit(0); }
+       if ( do_416() != 416 ) { FAIL("iteration 416"); exit(0); }
+       if ( do_417() != 417 ) { FAIL("iteration 417"); exit(0); }
+       if ( do_418() != 418 ) { FAIL("iteration 418"); exit(0); }
+       if ( do_419() != 419 ) { FAIL("iteration 419"); exit(0); }
+       if ( do_420() != 420 ) { FAIL("iteration 420"); exit(0); }
+       if ( do_421() != 421 ) { FAIL("iteration 421"); exit(0); }
+       if ( do_422() != 422 ) { FAIL("iteration 422"); exit(0); }
+       if ( do_423() != 423 ) { FAIL("iteration 423"); exit(0); }
+       if ( do_424() != 424 ) { FAIL("iteration 424"); exit(0); }
+       if ( do_425() != 425 ) { FAIL("iteration 425"); exit(0); }
+       if ( do_426() != 426 ) { FAIL("iteration 426"); exit(0); }
+       if ( do_427() != 427 ) { FAIL("iteration 427"); exit(0); }
+       if ( do_428() != 428 ) { FAIL("iteration 428"); exit(0); }
+       if ( do_429() != 429 ) { FAIL("iteration 429"); exit(0); }
+       if ( do_430() != 430 ) { FAIL("iteration 430"); exit(0); }
+       if ( do_431() != 431 ) { FAIL("iteration 431"); exit(0); }
+       if ( do_432() != 432 ) { FAIL("iteration 432"); exit(0); }
+       if ( do_433() != 433 ) { FAIL("iteration 433"); exit(0); }
+       if ( do_434() != 434 ) { FAIL("iteration 434"); exit(0); }
+       if ( do_435() != 435 ) { FAIL("iteration 435"); exit(0); }
+       if ( do_436() != 436 ) { FAIL("iteration 436"); exit(0); }
+       if ( do_437() != 437 ) { FAIL("iteration 437"); exit(0); }
+       if ( do_438() != 438 ) { FAIL("iteration 438"); exit(0); }
+       if ( do_439() != 439 ) { FAIL("iteration 439"); exit(0); }
+       if ( do_440() != 440 ) { FAIL("iteration 440"); exit(0); }
+       if ( do_441() != 441 ) { FAIL("iteration 441"); exit(0); }
+       if ( do_442() != 442 ) { FAIL("iteration 442"); exit(0); }
+       if ( do_443() != 443 ) { FAIL("iteration 443"); exit(0); }
+       if ( do_444() != 444 ) { FAIL("iteration 444"); exit(0); }
+       if ( do_445() != 445 ) { FAIL("iteration 445"); exit(0); }
+       if ( do_446() != 446 ) { FAIL("iteration 446"); exit(0); }
+       if ( do_447() != 447 ) { FAIL("iteration 447"); exit(0); }
+       if ( do_448() != 448 ) { FAIL("iteration 448"); exit(0); }
+       if ( do_449() != 449 ) { FAIL("iteration 449"); exit(0); }
+       if ( do_450() != 450 ) { FAIL("iteration 450"); exit(0); }
+       if ( do_451() != 451 ) { FAIL("iteration 451"); exit(0); }
+       if ( do_452() != 452 ) { FAIL("iteration 452"); exit(0); }
+       if ( do_453() != 453 ) { FAIL("iteration 453"); exit(0); }
+       if ( do_454() != 454 ) { FAIL("iteration 454"); exit(0); }
+       if ( do_455() != 455 ) { FAIL("iteration 455"); exit(0); }
+       if ( do_456() != 456 ) { FAIL("iteration 456"); exit(0); }
+       if ( do_457() != 457 ) { FAIL("iteration 457"); exit(0); }
+       if ( do_458() != 458 ) { FAIL("iteration 458"); exit(0); }
+       if ( do_459() != 459 ) { FAIL("iteration 459"); exit(0); }
+       if ( do_460() != 460 ) { FAIL("iteration 460"); exit(0); }
+       if ( do_461() != 461 ) { FAIL("iteration 461"); exit(0); }
+       if ( do_462() != 462 ) { FAIL("iteration 462"); exit(0); }
+       if ( do_463() != 463 ) { FAIL("iteration 463"); exit(0); }
+       if ( do_464() != 464 ) { FAIL("iteration 464"); exit(0); }
+       if ( do_465() != 465 ) { FAIL("iteration 465"); exit(0); }
+       if ( do_466() != 466 ) { FAIL("iteration 466"); exit(0); }
+       if ( do_467() != 467 ) { FAIL("iteration 467"); exit(0); }
+       if ( do_468() != 468 ) { FAIL("iteration 468"); exit(0); }
+       if ( do_469() != 469 ) { FAIL("iteration 469"); exit(0); }
+       if ( do_470() != 470 ) { FAIL("iteration 470"); exit(0); }
+       if ( do_471() != 471 ) { FAIL("iteration 471"); exit(0); }
+       if ( do_472() != 472 ) { FAIL("iteration 472"); exit(0); }
+       if ( do_473() != 473 ) { FAIL("iteration 473"); exit(0); }
+       if ( do_474() != 474 ) { FAIL("iteration 474"); exit(0); }
+       if ( do_475() != 475 ) { FAIL("iteration 475"); exit(0); }
+       if ( do_476() != 476 ) { FAIL("iteration 476"); exit(0); }
+       if ( do_477() != 477 ) { FAIL("iteration 477"); exit(0); }
+       if ( do_478() != 478 ) { FAIL("iteration 478"); exit(0); }
+       if ( do_479() != 479 ) { FAIL("iteration 479"); exit(0); }
+       if ( do_480() != 480 ) { FAIL("iteration 480"); exit(0); }
+       if ( do_481() != 481 ) { FAIL("iteration 481"); exit(0); }
+       if ( do_482() != 482 ) { FAIL("iteration 482"); exit(0); }
+       if ( do_483() != 483 ) { FAIL("iteration 483"); exit(0); }
+       if ( do_484() != 484 ) { FAIL("iteration 484"); exit(0); }
+       if ( do_485() != 485 ) { FAIL("iteration 485"); exit(0); }
+       if ( do_486() != 486 ) { FAIL("iteration 486"); exit(0); }
+       if ( do_487() != 487 ) { FAIL("iteration 487"); exit(0); }
+       if ( do_488() != 488 ) { FAIL("iteration 488"); exit(0); }
+       if ( do_489() != 489 ) { FAIL("iteration 489"); exit(0); }
+       if ( do_490() != 490 ) { FAIL("iteration 490"); exit(0); }
+       if ( do_491() != 491 ) { FAIL("iteration 491"); exit(0); }
+       if ( do_492() != 492 ) { FAIL("iteration 492"); exit(0); }
+       if ( do_493() != 493 ) { FAIL("iteration 493"); exit(0); }
+       if ( do_494() != 494 ) { FAIL("iteration 494"); exit(0); }
+       if ( do_495() != 495 ) { FAIL("iteration 495"); exit(0); }
+       if ( do_496() != 496 ) { FAIL("iteration 496"); exit(0); }
+       if ( do_497() != 497 ) { FAIL("iteration 497"); exit(0); }
+       if ( do_498() != 498 ) { FAIL("iteration 498"); exit(0); }
+       if ( do_499() != 499 ) { FAIL("iteration 499"); exit(0); }
+       if ( do_500() != 500 ) { FAIL("iteration 500"); exit(0); }
+       if ( do_501() != 501 ) { FAIL("iteration 501"); exit(0); }
+       if ( do_502() != 502 ) { FAIL("iteration 502"); exit(0); }
+       if ( do_503() != 503 ) { FAIL("iteration 503"); exit(0); }
+       if ( do_504() != 504 ) { FAIL("iteration 504"); exit(0); }
+       if ( do_505() != 505 ) { FAIL("iteration 505"); exit(0); }
+       if ( do_506() != 506 ) { FAIL("iteration 506"); exit(0); }
+       if ( do_507() != 507 ) { FAIL("iteration 507"); exit(0); }
+       if ( do_508() != 508 ) { FAIL("iteration 508"); exit(0); }
+       if ( do_509() != 509 ) { FAIL("iteration 509"); exit(0); }
+       if ( do_510() != 510 ) { FAIL("iteration 510"); exit(0); }
+       if ( do_511() != 511 ) { FAIL("iteration 511"); exit(0); }
+       if ( do_512() != 512 ) { FAIL("iteration 512"); exit(0); }
+       if ( do_513() != 513 ) { FAIL("iteration 513"); exit(0); }
+       if ( do_514() != 514 ) { FAIL("iteration 514"); exit(0); }
+       if ( do_515() != 515 ) { FAIL("iteration 515"); exit(0); }
+       if ( do_516() != 516 ) { FAIL("iteration 516"); exit(0); }
+       if ( do_517() != 517 ) { FAIL("iteration 517"); exit(0); }
+       if ( do_518() != 518 ) { FAIL("iteration 518"); exit(0); }
+       if ( do_519() != 519 ) { FAIL("iteration 519"); exit(0); }
+       if ( do_520() != 520 ) { FAIL("iteration 520"); exit(0); }
+       if ( do_521() != 521 ) { FAIL("iteration 521"); exit(0); }
+       if ( do_522() != 522 ) { FAIL("iteration 522"); exit(0); }
+       if ( do_523() != 523 ) { FAIL("iteration 523"); exit(0); }
+       if ( do_524() != 524 ) { FAIL("iteration 524"); exit(0); }
+       if ( do_525() != 525 ) { FAIL("iteration 525"); exit(0); }
+       if ( do_526() != 526 ) { FAIL("iteration 526"); exit(0); }
+       if ( do_527() != 527 ) { FAIL("iteration 527"); exit(0); }
+       if ( do_528() != 528 ) { FAIL("iteration 528"); exit(0); }
+       if ( do_529() != 529 ) { FAIL("iteration 529"); exit(0); }
+       if ( do_530() != 530 ) { FAIL("iteration 530"); exit(0); }
+       if ( do_531() != 531 ) { FAIL("iteration 531"); exit(0); }
+       if ( do_532() != 532 ) { FAIL("iteration 532"); exit(0); }
+       if ( do_533() != 533 ) { FAIL("iteration 533"); exit(0); }
+       if ( do_534() != 534 ) { FAIL("iteration 534"); exit(0); }
+       if ( do_535() != 535 ) { FAIL("iteration 535"); exit(0); }
+       if ( do_536() != 536 ) { FAIL("iteration 536"); exit(0); }
+       if ( do_537() != 537 ) { FAIL("iteration 537"); exit(0); }
+       if ( do_538() != 538 ) { FAIL("iteration 538"); exit(0); }
+       if ( do_539() != 539 ) { FAIL("iteration 539"); exit(0); }
+       if ( do_540() != 540 ) { FAIL("iteration 540"); exit(0); }
+       if ( do_541() != 541 ) { FAIL("iteration 541"); exit(0); }
+       if ( do_542() != 542 ) { FAIL("iteration 542"); exit(0); }
+       if ( do_543() != 543 ) { FAIL("iteration 543"); exit(0); }
+       if ( do_544() != 544 ) { FAIL("iteration 544"); exit(0); }
+       if ( do_545() != 545 ) { FAIL("iteration 545"); exit(0); }
+       if ( do_546() != 546 ) { FAIL("iteration 546"); exit(0); }
+       if ( do_547() != 547 ) { FAIL("iteration 547"); exit(0); }
+       if ( do_548() != 548 ) { FAIL("iteration 548"); exit(0); }
+       if ( do_549() != 549 ) { FAIL("iteration 549"); exit(0); }
+       if ( do_550() != 550 ) { FAIL("iteration 550"); exit(0); }
+       if ( do_551() != 551 ) { FAIL("iteration 551"); exit(0); }
+       if ( do_552() != 552 ) { FAIL("iteration 552"); exit(0); }
+       if ( do_553() != 553 ) { FAIL("iteration 553"); exit(0); }
+       if ( do_554() != 554 ) { FAIL("iteration 554"); exit(0); }
+       if ( do_555() != 555 ) { FAIL("iteration 555"); exit(0); }
+       if ( do_556() != 556 ) { FAIL("iteration 556"); exit(0); }
+       if ( do_557() != 557 ) { FAIL("iteration 557"); exit(0); }
+       if ( do_558() != 558 ) { FAIL("iteration 558"); exit(0); }
+       if ( do_559() != 559 ) { FAIL("iteration 559"); exit(0); }
+       if ( do_560() != 560 ) { FAIL("iteration 560"); exit(0); }
+       if ( do_561() != 561 ) { FAIL("iteration 561"); exit(0); }
+       if ( do_562() != 562 ) { FAIL("iteration 562"); exit(0); }
+       if ( do_563() != 563 ) { FAIL("iteration 563"); exit(0); }
+       if ( do_564() != 564 ) { FAIL("iteration 564"); exit(0); }
+       if ( do_565() != 565 ) { FAIL("iteration 565"); exit(0); }
+       if ( do_566() != 566 ) { FAIL("iteration 566"); exit(0); }
+       if ( do_567() != 567 ) { FAIL("iteration 567"); exit(0); }
+       if ( do_568() != 568 ) { FAIL("iteration 568"); exit(0); }
+       if ( do_569() != 569 ) { FAIL("iteration 569"); exit(0); }
+       if ( do_570() != 570 ) { FAIL("iteration 570"); exit(0); }
+       if ( do_571() != 571 ) { FAIL("iteration 571"); exit(0); }
+       if ( do_572() != 572 ) { FAIL("iteration 572"); exit(0); }
+       if ( do_573() != 573 ) { FAIL("iteration 573"); exit(0); }
+       if ( do_574() != 574 ) { FAIL("iteration 574"); exit(0); }
+       if ( do_575() != 575 ) { FAIL("iteration 575"); exit(0); }
+       if ( do_576() != 576 ) { FAIL("iteration 576"); exit(0); }
+       if ( do_577() != 577 ) { FAIL("iteration 577"); exit(0); }
+       if ( do_578() != 578 ) { FAIL("iteration 578"); exit(0); }
+       if ( do_579() != 579 ) { FAIL("iteration 579"); exit(0); }
+       if ( do_580() != 580 ) { FAIL("iteration 580"); exit(0); }
+       if ( do_581() != 581 ) { FAIL("iteration 581"); exit(0); }
+       if ( do_582() != 582 ) { FAIL("iteration 582"); exit(0); }
+       if ( do_583() != 583 ) { FAIL("iteration 583"); exit(0); }
+       if ( do_584() != 584 ) { FAIL("iteration 584"); exit(0); }
+       if ( do_585() != 585 ) { FAIL("iteration 585"); exit(0); }
+       if ( do_586() != 586 ) { FAIL("iteration 586"); exit(0); }
+       if ( do_587() != 587 ) { FAIL("iteration 587"); exit(0); }
+       if ( do_588() != 588 ) { FAIL("iteration 588"); exit(0); }
+       if ( do_589() != 589 ) { FAIL("iteration 589"); exit(0); }
+       if ( do_590() != 590 ) { FAIL("iteration 590"); exit(0); }
+       if ( do_591() != 591 ) { FAIL("iteration 591"); exit(0); }
+       if ( do_592() != 592 ) { FAIL("iteration 592"); exit(0); }
+       if ( do_593() != 593 ) { FAIL("iteration 593"); exit(0); }
+       if ( do_594() != 594 ) { FAIL("iteration 594"); exit(0); }
+       if ( do_595() != 595 ) { FAIL("iteration 595"); exit(0); }
+       if ( do_596() != 596 ) { FAIL("iteration 596"); exit(0); }
+       if ( do_597() != 597 ) { FAIL("iteration 597"); exit(0); }
+       if ( do_598() != 598 ) { FAIL("iteration 598"); exit(0); }
+       if ( do_599() != 599 ) { FAIL("iteration 599"); exit(0); }
+       if ( do_600() != 600 ) { FAIL("iteration 600"); exit(0); }
+       if ( do_601() != 601 ) { FAIL("iteration 601"); exit(0); }
+       if ( do_602() != 602 ) { FAIL("iteration 602"); exit(0); }
+       if ( do_603() != 603 ) { FAIL("iteration 603"); exit(0); }
+       if ( do_604() != 604 ) { FAIL("iteration 604"); exit(0); }
+       if ( do_605() != 605 ) { FAIL("iteration 605"); exit(0); }
+       if ( do_606() != 606 ) { FAIL("iteration 606"); exit(0); }
+       if ( do_607() != 607 ) { FAIL("iteration 607"); exit(0); }
+       if ( do_608() != 608 ) { FAIL("iteration 608"); exit(0); }
+       if ( do_609() != 609 ) { FAIL("iteration 609"); exit(0); }
+       if ( do_610() != 610 ) { FAIL("iteration 610"); exit(0); }
+       if ( do_611() != 611 ) { FAIL("iteration 611"); exit(0); }
+       if ( do_612() != 612 ) { FAIL("iteration 612"); exit(0); }
+       if ( do_613() != 613 ) { FAIL("iteration 613"); exit(0); }
+       if ( do_614() != 614 ) { FAIL("iteration 614"); exit(0); }
+       if ( do_615() != 615 ) { FAIL("iteration 615"); exit(0); }
+       if ( do_616() != 616 ) { FAIL("iteration 616"); exit(0); }
+       if ( do_617() != 617 ) { FAIL("iteration 617"); exit(0); }
+       if ( do_618() != 618 ) { FAIL("iteration 618"); exit(0); }
+       if ( do_619() != 619 ) { FAIL("iteration 619"); exit(0); }
+       if ( do_620() != 620 ) { FAIL("iteration 620"); exit(0); }
+       if ( do_621() != 621 ) { FAIL("iteration 621"); exit(0); }
+       if ( do_622() != 622 ) { FAIL("iteration 622"); exit(0); }
+       if ( do_623() != 623 ) { FAIL("iteration 623"); exit(0); }
+       if ( do_624() != 624 ) { FAIL("iteration 624"); exit(0); }
+       if ( do_625() != 625 ) { FAIL("iteration 625"); exit(0); }
+       if ( do_626() != 626 ) { FAIL("iteration 626"); exit(0); }
+       if ( do_627() != 627 ) { FAIL("iteration 627"); exit(0); }
+       if ( do_628() != 628 ) { FAIL("iteration 628"); exit(0); }
+       if ( do_629() != 629 ) { FAIL("iteration 629"); exit(0); }
+       if ( do_630() != 630 ) { FAIL("iteration 630"); exit(0); }
+       if ( do_631() != 631 ) { FAIL("iteration 631"); exit(0); }
+       if ( do_632() != 632 ) { FAIL("iteration 632"); exit(0); }
+       if ( do_633() != 633 ) { FAIL("iteration 633"); exit(0); }
+       if ( do_634() != 634 ) { FAIL("iteration 634"); exit(0); }
+       if ( do_635() != 635 ) { FAIL("iteration 635"); exit(0); }
+       if ( do_636() != 636 ) { FAIL("iteration 636"); exit(0); }
+       if ( do_637() != 637 ) { FAIL("iteration 637"); exit(0); }
+       if ( do_638() != 638 ) { FAIL("iteration 638"); exit(0); }
+       if ( do_639() != 639 ) { FAIL("iteration 639"); exit(0); }
+       if ( do_640() != 640 ) { FAIL("iteration 640"); exit(0); }
+       if ( do_641() != 641 ) { FAIL("iteration 641"); exit(0); }
+       if ( do_642() != 642 ) { FAIL("iteration 642"); exit(0); }
+       if ( do_643() != 643 ) { FAIL("iteration 643"); exit(0); }
+       if ( do_644() != 644 ) { FAIL("iteration 644"); exit(0); }
+       if ( do_645() != 645 ) { FAIL("iteration 645"); exit(0); }
+       if ( do_646() != 646 ) { FAIL("iteration 646"); exit(0); }
+       if ( do_647() != 647 ) { FAIL("iteration 647"); exit(0); }
+       if ( do_648() != 648 ) { FAIL("iteration 648"); exit(0); }
+       if ( do_649() != 649 ) { FAIL("iteration 649"); exit(0); }
+       if ( do_650() != 650 ) { FAIL("iteration 650"); exit(0); }
+       if ( do_651() != 651 ) { FAIL("iteration 651"); exit(0); }
+       if ( do_652() != 652 ) { FAIL("iteration 652"); exit(0); }
+       if ( do_653() != 653 ) { FAIL("iteration 653"); exit(0); }
+       if ( do_654() != 654 ) { FAIL("iteration 654"); exit(0); }
+       if ( do_655() != 655 ) { FAIL("iteration 655"); exit(0); }
+       if ( do_656() != 656 ) { FAIL("iteration 656"); exit(0); }
+       if ( do_657() != 657 ) { FAIL("iteration 657"); exit(0); }
+       if ( do_658() != 658 ) { FAIL("iteration 658"); exit(0); }
+       if ( do_659() != 659 ) { FAIL("iteration 659"); exit(0); }
+       if ( do_660() != 660 ) { FAIL("iteration 660"); exit(0); }
+       if ( do_661() != 661 ) { FAIL("iteration 661"); exit(0); }
+       if ( do_662() != 662 ) { FAIL("iteration 662"); exit(0); }
+       if ( do_663() != 663 ) { FAIL("iteration 663"); exit(0); }
+       if ( do_664() != 664 ) { FAIL("iteration 664"); exit(0); }
+       if ( do_665() != 665 ) { FAIL("iteration 665"); exit(0); }
+       if ( do_666() != 666 ) { FAIL("iteration 666"); exit(0); }
+       if ( do_667() != 667 ) { FAIL("iteration 667"); exit(0); }
+       if ( do_668() != 668 ) { FAIL("iteration 668"); exit(0); }
+       if ( do_669() != 669 ) { FAIL("iteration 669"); exit(0); }
+       if ( do_670() != 670 ) { FAIL("iteration 670"); exit(0); }
+       if ( do_671() != 671 ) { FAIL("iteration 671"); exit(0); }
+       if ( do_672() != 672 ) { FAIL("iteration 672"); exit(0); }
+       if ( do_673() != 673 ) { FAIL("iteration 673"); exit(0); }
+       if ( do_674() != 674 ) { FAIL("iteration 674"); exit(0); }
+       if ( do_675() != 675 ) { FAIL("iteration 675"); exit(0); }
+       if ( do_676() != 676 ) { FAIL("iteration 676"); exit(0); }
+       if ( do_677() != 677 ) { FAIL("iteration 677"); exit(0); }
+       if ( do_678() != 678 ) { FAIL("iteration 678"); exit(0); }
+       if ( do_679() != 679 ) { FAIL("iteration 679"); exit(0); }
+       if ( do_680() != 680 ) { FAIL("iteration 680"); exit(0); }
+       if ( do_681() != 681 ) { FAIL("iteration 681"); exit(0); }
+       if ( do_682() != 682 ) { FAIL("iteration 682"); exit(0); }
+       if ( do_683() != 683 ) { FAIL("iteration 683"); exit(0); }
+       if ( do_684() != 684 ) { FAIL("iteration 684"); exit(0); }
+       if ( do_685() != 685 ) { FAIL("iteration 685"); exit(0); }
+       if ( do_686() != 686 ) { FAIL("iteration 686"); exit(0); }
+       if ( do_687() != 687 ) { FAIL("iteration 687"); exit(0); }
+       if ( do_688() != 688 ) { FAIL("iteration 688"); exit(0); }
+       if ( do_689() != 689 ) { FAIL("iteration 689"); exit(0); }
+       if ( do_690() != 690 ) { FAIL("iteration 690"); exit(0); }
+       if ( do_691() != 691 ) { FAIL("iteration 691"); exit(0); }
+       if ( do_692() != 692 ) { FAIL("iteration 692"); exit(0); }
+       if ( do_693() != 693 ) { FAIL("iteration 693"); exit(0); }
+       if ( do_694() != 694 ) { FAIL("iteration 694"); exit(0); }
+       if ( do_695() != 695 ) { FAIL("iteration 695"); exit(0); }
+       if ( do_696() != 696 ) { FAIL("iteration 696"); exit(0); }
+       if ( do_697() != 697 ) { FAIL("iteration 697"); exit(0); }
+       if ( do_698() != 698 ) { FAIL("iteration 698"); exit(0); }
+       if ( do_699() != 699 ) { FAIL("iteration 699"); exit(0); }
+       if ( do_700() != 700 ) { FAIL("iteration 700"); exit(0); }
+       if ( do_701() != 701 ) { FAIL("iteration 701"); exit(0); }
+       if ( do_702() != 702 ) { FAIL("iteration 702"); exit(0); }
+       if ( do_703() != 703 ) { FAIL("iteration 703"); exit(0); }
+       if ( do_704() != 704 ) { FAIL("iteration 704"); exit(0); }
+       if ( do_705() != 705 ) { FAIL("iteration 705"); exit(0); }
+       if ( do_706() != 706 ) { FAIL("iteration 706"); exit(0); }
+       if ( do_707() != 707 ) { FAIL("iteration 707"); exit(0); }
+       if ( do_708() != 708 ) { FAIL("iteration 708"); exit(0); }
+       if ( do_709() != 709 ) { FAIL("iteration 709"); exit(0); }
+       if ( do_710() != 710 ) { FAIL("iteration 710"); exit(0); }
+       if ( do_711() != 711 ) { FAIL("iteration 711"); exit(0); }
+       if ( do_712() != 712 ) { FAIL("iteration 712"); exit(0); }
+       if ( do_713() != 713 ) { FAIL("iteration 713"); exit(0); }
+       if ( do_714() != 714 ) { FAIL("iteration 714"); exit(0); }
+       if ( do_715() != 715 ) { FAIL("iteration 715"); exit(0); }
+       if ( do_716() != 716 ) { FAIL("iteration 716"); exit(0); }
+       if ( do_717() != 717 ) { FAIL("iteration 717"); exit(0); }
+       if ( do_718() != 718 ) { FAIL("iteration 718"); exit(0); }
+       if ( do_719() != 719 ) { FAIL("iteration 719"); exit(0); }
+       if ( do_720() != 720 ) { FAIL("iteration 720"); exit(0); }
+       if ( do_721() != 721 ) { FAIL("iteration 721"); exit(0); }
+       if ( do_722() != 722 ) { FAIL("iteration 722"); exit(0); }
+       if ( do_723() != 723 ) { FAIL("iteration 723"); exit(0); }
+       if ( do_724() != 724 ) { FAIL("iteration 724"); exit(0); }
+       if ( do_725() != 725 ) { FAIL("iteration 725"); exit(0); }
+       if ( do_726() != 726 ) { FAIL("iteration 726"); exit(0); }
+       if ( do_727() != 727 ) { FAIL("iteration 727"); exit(0); }
+       if ( do_728() != 728 ) { FAIL("iteration 728"); exit(0); }
+       if ( do_729() != 729 ) { FAIL("iteration 729"); exit(0); }
+       if ( do_730() != 730 ) { FAIL("iteration 730"); exit(0); }
+       if ( do_731() != 731 ) { FAIL("iteration 731"); exit(0); }
+       if ( do_732() != 732 ) { FAIL("iteration 732"); exit(0); }
+       if ( do_733() != 733 ) { FAIL("iteration 733"); exit(0); }
+       if ( do_734() != 734 ) { FAIL("iteration 734"); exit(0); }
+       if ( do_735() != 735 ) { FAIL("iteration 735"); exit(0); }
+       if ( do_736() != 736 ) { FAIL("iteration 736"); exit(0); }
+       if ( do_737() != 737 ) { FAIL("iteration 737"); exit(0); }
+       if ( do_738() != 738 ) { FAIL("iteration 738"); exit(0); }
+       if ( do_739() != 739 ) { FAIL("iteration 739"); exit(0); }
+       if ( do_740() != 740 ) { FAIL("iteration 740"); exit(0); }
+       if ( do_741() != 741 ) { FAIL("iteration 741"); exit(0); }
+       if ( do_742() != 742 ) { FAIL("iteration 742"); exit(0); }
+       if ( do_743() != 743 ) { FAIL("iteration 743"); exit(0); }
+       if ( do_744() != 744 ) { FAIL("iteration 744"); exit(0); }
+       if ( do_745() != 745 ) { FAIL("iteration 745"); exit(0); }
+       if ( do_746() != 746 ) { FAIL("iteration 746"); exit(0); }
+       if ( do_747() != 747 ) { FAIL("iteration 747"); exit(0); }
+       if ( do_748() != 748 ) { FAIL("iteration 748"); exit(0); }
+       if ( do_749() != 749 ) { FAIL("iteration 749"); exit(0); }
+       if ( do_750() != 750 ) { FAIL("iteration 750"); exit(0); }
+       if ( do_751() != 751 ) { FAIL("iteration 751"); exit(0); }
+       if ( do_752() != 752 ) { FAIL("iteration 752"); exit(0); }
+       if ( do_753() != 753 ) { FAIL("iteration 753"); exit(0); }
+       if ( do_754() != 754 ) { FAIL("iteration 754"); exit(0); }
+       if ( do_755() != 755 ) { FAIL("iteration 755"); exit(0); }
+       if ( do_756() != 756 ) { FAIL("iteration 756"); exit(0); }
+       if ( do_757() != 757 ) { FAIL("iteration 757"); exit(0); }
+       if ( do_758() != 758 ) { FAIL("iteration 758"); exit(0); }
+       if ( do_759() != 759 ) { FAIL("iteration 759"); exit(0); }
+       if ( do_760() != 760 ) { FAIL("iteration 760"); exit(0); }
+       if ( do_761() != 761 ) { FAIL("iteration 761"); exit(0); }
+       if ( do_762() != 762 ) { FAIL("iteration 762"); exit(0); }
+       if ( do_763() != 763 ) { FAIL("iteration 763"); exit(0); }
+       if ( do_764() != 764 ) { FAIL("iteration 764"); exit(0); }
+       if ( do_765() != 765 ) { FAIL("iteration 765"); exit(0); }
+       if ( do_766() != 766 ) { FAIL("iteration 766"); exit(0); }
+       if ( do_767() != 767 ) { FAIL("iteration 767"); exit(0); }
+       if ( do_768() != 768 ) { FAIL("iteration 768"); exit(0); }
+       if ( do_769() != 769 ) { FAIL("iteration 769"); exit(0); }
+       if ( do_770() != 770 ) { FAIL("iteration 770"); exit(0); }
+       if ( do_771() != 771 ) { FAIL("iteration 771"); exit(0); }
+       if ( do_772() != 772 ) { FAIL("iteration 772"); exit(0); }
+       if ( do_773() != 773 ) { FAIL("iteration 773"); exit(0); }
+       if ( do_774() != 774 ) { FAIL("iteration 774"); exit(0); }
+       if ( do_775() != 775 ) { FAIL("iteration 775"); exit(0); }
+       if ( do_776() != 776 ) { FAIL("iteration 776"); exit(0); }
+       if ( do_777() != 777 ) { FAIL("iteration 777"); exit(0); }
+       if ( do_778() != 778 ) { FAIL("iteration 778"); exit(0); }
+       if ( do_779() != 779 ) { FAIL("iteration 779"); exit(0); }
+       if ( do_780() != 780 ) { FAIL("iteration 780"); exit(0); }
+       if ( do_781() != 781 ) { FAIL("iteration 781"); exit(0); }
+       if ( do_782() != 782 ) { FAIL("iteration 782"); exit(0); }
+       if ( do_783() != 783 ) { FAIL("iteration 783"); exit(0); }
+       if ( do_784() != 784 ) { FAIL("iteration 784"); exit(0); }
+       if ( do_785() != 785 ) { FAIL("iteration 785"); exit(0); }
+       if ( do_786() != 786 ) { FAIL("iteration 786"); exit(0); }
+       if ( do_787() != 787 ) { FAIL("iteration 787"); exit(0); }
+       if ( do_788() != 788 ) { FAIL("iteration 788"); exit(0); }
+       if ( do_789() != 789 ) { FAIL("iteration 789"); exit(0); }
+       if ( do_790() != 790 ) { FAIL("iteration 790"); exit(0); }
+       if ( do_791() != 791 ) { FAIL("iteration 791"); exit(0); }
+       if ( do_792() != 792 ) { FAIL("iteration 792"); exit(0); }
+       if ( do_793() != 793 ) { FAIL("iteration 793"); exit(0); }
+       if ( do_794() != 794 ) { FAIL("iteration 794"); exit(0); }
+       if ( do_795() != 795 ) { FAIL("iteration 795"); exit(0); }
+       if ( do_796() != 796 ) { FAIL("iteration 796"); exit(0); }
+       if ( do_797() != 797 ) { FAIL("iteration 797"); exit(0); }
+       if ( do_798() != 798 ) { FAIL("iteration 798"); exit(0); }
+       if ( do_799() != 799 ) { FAIL("iteration 799"); exit(0); }
+       if ( do_800() != 800 ) { FAIL("iteration 800"); exit(0); }
+       if ( do_801() != 801 ) { FAIL("iteration 801"); exit(0); }
+       if ( do_802() != 802 ) { FAIL("iteration 802"); exit(0); }
+       if ( do_803() != 803 ) { FAIL("iteration 803"); exit(0); }
+       if ( do_804() != 804 ) { FAIL("iteration 804"); exit(0); }
+       if ( do_805() != 805 ) { FAIL("iteration 805"); exit(0); }
+       if ( do_806() != 806 ) { FAIL("iteration 806"); exit(0); }
+       if ( do_807() != 807 ) { FAIL("iteration 807"); exit(0); }
+       if ( do_808() != 808 ) { FAIL("iteration 808"); exit(0); }
+       if ( do_809() != 809 ) { FAIL("iteration 809"); exit(0); }
+       if ( do_810() != 810 ) { FAIL("iteration 810"); exit(0); }
+       if ( do_811() != 811 ) { FAIL("iteration 811"); exit(0); }
+       if ( do_812() != 812 ) { FAIL("iteration 812"); exit(0); }
+       if ( do_813() != 813 ) { FAIL("iteration 813"); exit(0); }
+       if ( do_814() != 814 ) { FAIL("iteration 814"); exit(0); }
+       if ( do_815() != 815 ) { FAIL("iteration 815"); exit(0); }
+       if ( do_816() != 816 ) { FAIL("iteration 816"); exit(0); }
+       if ( do_817() != 817 ) { FAIL("iteration 817"); exit(0); }
+       if ( do_818() != 818 ) { FAIL("iteration 818"); exit(0); }
+       if ( do_819() != 819 ) { FAIL("iteration 819"); exit(0); }
+       if ( do_820() != 820 ) { FAIL("iteration 820"); exit(0); }
+       if ( do_821() != 821 ) { FAIL("iteration 821"); exit(0); }
+       if ( do_822() != 822 ) { FAIL("iteration 822"); exit(0); }
+       if ( do_823() != 823 ) { FAIL("iteration 823"); exit(0); }
+       if ( do_824() != 824 ) { FAIL("iteration 824"); exit(0); }
+       if ( do_825() != 825 ) { FAIL("iteration 825"); exit(0); }
+       if ( do_826() != 826 ) { FAIL("iteration 826"); exit(0); }
+       if ( do_827() != 827 ) { FAIL("iteration 827"); exit(0); }
+       if ( do_828() != 828 ) { FAIL("iteration 828"); exit(0); }
+       if ( do_829() != 829 ) { FAIL("iteration 829"); exit(0); }
+       if ( do_830() != 830 ) { FAIL("iteration 830"); exit(0); }
+       if ( do_831() != 831 ) { FAIL("iteration 831"); exit(0); }
+       if ( do_832() != 832 ) { FAIL("iteration 832"); exit(0); }
+       if ( do_833() != 833 ) { FAIL("iteration 833"); exit(0); }
+       if ( do_834() != 834 ) { FAIL("iteration 834"); exit(0); }
+       if ( do_835() != 835 ) { FAIL("iteration 835"); exit(0); }
+       if ( do_836() != 836 ) { FAIL("iteration 836"); exit(0); }
+       if ( do_837() != 837 ) { FAIL("iteration 837"); exit(0); }
+       if ( do_838() != 838 ) { FAIL("iteration 838"); exit(0); }
+       if ( do_839() != 839 ) { FAIL("iteration 839"); exit(0); }
+       if ( do_840() != 840 ) { FAIL("iteration 840"); exit(0); }
+       if ( do_841() != 841 ) { FAIL("iteration 841"); exit(0); }
+       if ( do_842() != 842 ) { FAIL("iteration 842"); exit(0); }
+       if ( do_843() != 843 ) { FAIL("iteration 843"); exit(0); }
+       if ( do_844() != 844 ) { FAIL("iteration 844"); exit(0); }
+       if ( do_845() != 845 ) { FAIL("iteration 845"); exit(0); }
+       if ( do_846() != 846 ) { FAIL("iteration 846"); exit(0); }
+       if ( do_847() != 847 ) { FAIL("iteration 847"); exit(0); }
+       if ( do_848() != 848 ) { FAIL("iteration 848"); exit(0); }
+       if ( do_849() != 849 ) { FAIL("iteration 849"); exit(0); }
+       if ( do_850() != 850 ) { FAIL("iteration 850"); exit(0); }
+       if ( do_851() != 851 ) { FAIL("iteration 851"); exit(0); }
+       if ( do_852() != 852 ) { FAIL("iteration 852"); exit(0); }
+       if ( do_853() != 853 ) { FAIL("iteration 853"); exit(0); }
+       if ( do_854() != 854 ) { FAIL("iteration 854"); exit(0); }
+       if ( do_855() != 855 ) { FAIL("iteration 855"); exit(0); }
+       if ( do_856() != 856 ) { FAIL("iteration 856"); exit(0); }
+       if ( do_857() != 857 ) { FAIL("iteration 857"); exit(0); }
+       if ( do_858() != 858 ) { FAIL("iteration 858"); exit(0); }
+       if ( do_859() != 859 ) { FAIL("iteration 859"); exit(0); }
+       if ( do_860() != 860 ) { FAIL("iteration 860"); exit(0); }
+       if ( do_861() != 861 ) { FAIL("iteration 861"); exit(0); }
+       if ( do_862() != 862 ) { FAIL("iteration 862"); exit(0); }
+       if ( do_863() != 863 ) { FAIL("iteration 863"); exit(0); }
+       if ( do_864() != 864 ) { FAIL("iteration 864"); exit(0); }
+       if ( do_865() != 865 ) { FAIL("iteration 865"); exit(0); }
+       if ( do_866() != 866 ) { FAIL("iteration 866"); exit(0); }
+       if ( do_867() != 867 ) { FAIL("iteration 867"); exit(0); }
+       if ( do_868() != 868 ) { FAIL("iteration 868"); exit(0); }
+       if ( do_869() != 869 ) { FAIL("iteration 869"); exit(0); }
+       if ( do_870() != 870 ) { FAIL("iteration 870"); exit(0); }
+       if ( do_871() != 871 ) { FAIL("iteration 871"); exit(0); }
+       if ( do_872() != 872 ) { FAIL("iteration 872"); exit(0); }
+       if ( do_873() != 873 ) { FAIL("iteration 873"); exit(0); }
+       if ( do_874() != 874 ) { FAIL("iteration 874"); exit(0); }
+       if ( do_875() != 875 ) { FAIL("iteration 875"); exit(0); }
+       if ( do_876() != 876 ) { FAIL("iteration 876"); exit(0); }
+       if ( do_877() != 877 ) { FAIL("iteration 877"); exit(0); }
+       if ( do_878() != 878 ) { FAIL("iteration 878"); exit(0); }
+       if ( do_879() != 879 ) { FAIL("iteration 879"); exit(0); }
+       if ( do_880() != 880 ) { FAIL("iteration 880"); exit(0); }
+       if ( do_881() != 881 ) { FAIL("iteration 881"); exit(0); }
+       if ( do_882() != 882 ) { FAIL("iteration 882"); exit(0); }
+       if ( do_883() != 883 ) { FAIL("iteration 883"); exit(0); }
+       if ( do_884() != 884 ) { FAIL("iteration 884"); exit(0); }
+       if ( do_885() != 885 ) { FAIL("iteration 885"); exit(0); }
+       if ( do_886() != 886 ) { FAIL("iteration 886"); exit(0); }
+       if ( do_887() != 887 ) { FAIL("iteration 887"); exit(0); }
+       if ( do_888() != 888 ) { FAIL("iteration 888"); exit(0); }
+       if ( do_889() != 889 ) { FAIL("iteration 889"); exit(0); }
+       if ( do_890() != 890 ) { FAIL("iteration 890"); exit(0); }
+       if ( do_891() != 891 ) { FAIL("iteration 891"); exit(0); }
+       if ( do_892() != 892 ) { FAIL("iteration 892"); exit(0); }
+       if ( do_893() != 893 ) { FAIL("iteration 893"); exit(0); }
+       if ( do_894() != 894 ) { FAIL("iteration 894"); exit(0); }
+       if ( do_895() != 895 ) { FAIL("iteration 895"); exit(0); }
+       if ( do_896() != 896 ) { FAIL("iteration 896"); exit(0); }
+       if ( do_897() != 897 ) { FAIL("iteration 897"); exit(0); }
+       if ( do_898() != 898 ) { FAIL("iteration 898"); exit(0); }
+       if ( do_899() != 899 ) { FAIL("iteration 899"); exit(0); }
+       if ( do_900() != 900 ) { FAIL("iteration 900"); exit(0); }
+       if ( do_901() != 901 ) { FAIL("iteration 901"); exit(0); }
+       if ( do_902() != 902 ) { FAIL("iteration 902"); exit(0); }
+       if ( do_903() != 903 ) { FAIL("iteration 903"); exit(0); }
+       if ( do_904() != 904 ) { FAIL("iteration 904"); exit(0); }
+       if ( do_905() != 905 ) { FAIL("iteration 905"); exit(0); }
+       if ( do_906() != 906 ) { FAIL("iteration 906"); exit(0); }
+       if ( do_907() != 907 ) { FAIL("iteration 907"); exit(0); }
+       if ( do_908() != 908 ) { FAIL("iteration 908"); exit(0); }
+       if ( do_909() != 909 ) { FAIL("iteration 909"); exit(0); }
+       if ( do_910() != 910 ) { FAIL("iteration 910"); exit(0); }
+       if ( do_911() != 911 ) { FAIL("iteration 911"); exit(0); }
+       if ( do_912() != 912 ) { FAIL("iteration 912"); exit(0); }
+       if ( do_913() != 913 ) { FAIL("iteration 913"); exit(0); }
+       if ( do_914() != 914 ) { FAIL("iteration 914"); exit(0); }
+       if ( do_915() != 915 ) { FAIL("iteration 915"); exit(0); }
+       if ( do_916() != 916 ) { FAIL("iteration 916"); exit(0); }
+       if ( do_917() != 917 ) { FAIL("iteration 917"); exit(0); }
+       if ( do_918() != 918 ) { FAIL("iteration 918"); exit(0); }
+       if ( do_919() != 919 ) { FAIL("iteration 919"); exit(0); }
+       if ( do_920() != 920 ) { FAIL("iteration 920"); exit(0); }
+       if ( do_921() != 921 ) { FAIL("iteration 921"); exit(0); }
+       if ( do_922() != 922 ) { FAIL("iteration 922"); exit(0); }
+       if ( do_923() != 923 ) { FAIL("iteration 923"); exit(0); }
+       if ( do_924() != 924 ) { FAIL("iteration 924"); exit(0); }
+       if ( do_925() != 925 ) { FAIL("iteration 925"); exit(0); }
+       if ( do_926() != 926 ) { FAIL("iteration 926"); exit(0); }
+       if ( do_927() != 927 ) { FAIL("iteration 927"); exit(0); }
+       if ( do_928() != 928 ) { FAIL("iteration 928"); exit(0); }
+       if ( do_929() != 929 ) { FAIL("iteration 929"); exit(0); }
+       if ( do_930() != 930 ) { FAIL("iteration 930"); exit(0); }
+       if ( do_931() != 931 ) { FAIL("iteration 931"); exit(0); }
+       if ( do_932() != 932 ) { FAIL("iteration 932"); exit(0); }
+       if ( do_933() != 933 ) { FAIL("iteration 933"); exit(0); }
+       if ( do_934() != 934 ) { FAIL("iteration 934"); exit(0); }
+       if ( do_935() != 935 ) { FAIL("iteration 935"); exit(0); }
+       if ( do_936() != 936 ) { FAIL("iteration 936"); exit(0); }
+       if ( do_937() != 937 ) { FAIL("iteration 937"); exit(0); }
+       if ( do_938() != 938 ) { FAIL("iteration 938"); exit(0); }
+       if ( do_939() != 939 ) { FAIL("iteration 939"); exit(0); }
+       if ( do_940() != 940 ) { FAIL("iteration 940"); exit(0); }
+       if ( do_941() != 941 ) { FAIL("iteration 941"); exit(0); }
+       if ( do_942() != 942 ) { FAIL("iteration 942"); exit(0); }
+       if ( do_943() != 943 ) { FAIL("iteration 943"); exit(0); }
+       if ( do_944() != 944 ) { FAIL("iteration 944"); exit(0); }
+       if ( do_945() != 945 ) { FAIL("iteration 945"); exit(0); }
+       if ( do_946() != 946 ) { FAIL("iteration 946"); exit(0); }
+       if ( do_947() != 947 ) { FAIL("iteration 947"); exit(0); }
+       if ( do_948() != 948 ) { FAIL("iteration 948"); exit(0); }
+       if ( do_949() != 949 ) { FAIL("iteration 949"); exit(0); }
+       if ( do_950() != 950 ) { FAIL("iteration 950"); exit(0); }
+       if ( do_951() != 951 ) { FAIL("iteration 951"); exit(0); }
+       if ( do_952() != 952 ) { FAIL("iteration 952"); exit(0); }
+       if ( do_953() != 953 ) { FAIL("iteration 953"); exit(0); }
+       if ( do_954() != 954 ) { FAIL("iteration 954"); exit(0); }
+       if ( do_955() != 955 ) { FAIL("iteration 955"); exit(0); }
+       if ( do_956() != 956 ) { FAIL("iteration 956"); exit(0); }
+       if ( do_957() != 957 ) { FAIL("iteration 957"); exit(0); }
+       if ( do_958() != 958 ) { FAIL("iteration 958"); exit(0); }
+       if ( do_959() != 959 ) { FAIL("iteration 959"); exit(0); }
+       if ( do_960() != 960 ) { FAIL("iteration 960"); exit(0); }
+       if ( do_961() != 961 ) { FAIL("iteration 961"); exit(0); }
+       if ( do_962() != 962 ) { FAIL("iteration 962"); exit(0); }
+       if ( do_963() != 963 ) { FAIL("iteration 963"); exit(0); }
+       if ( do_964() != 964 ) { FAIL("iteration 964"); exit(0); }
+       if ( do_965() != 965 ) { FAIL("iteration 965"); exit(0); }
+       if ( do_966() != 966 ) { FAIL("iteration 966"); exit(0); }
+       if ( do_967() != 967 ) { FAIL("iteration 967"); exit(0); }
+       if ( do_968() != 968 ) { FAIL("iteration 968"); exit(0); }
+       if ( do_969() != 969 ) { FAIL("iteration 969"); exit(0); }
+       if ( do_970() != 970 ) { FAIL("iteration 970"); exit(0); }
+       if ( do_971() != 971 ) { FAIL("iteration 971"); exit(0); }
+       if ( do_972() != 972 ) { FAIL("iteration 972"); exit(0); }
+       if ( do_973() != 973 ) { FAIL("iteration 973"); exit(0); }
+       if ( do_974() != 974 ) { FAIL("iteration 974"); exit(0); }
+       if ( do_975() != 975 ) { FAIL("iteration 975"); exit(0); }
+       if ( do_976() != 976 ) { FAIL("iteration 976"); exit(0); }
+       if ( do_977() != 977 ) { FAIL("iteration 977"); exit(0); }
+       if ( do_978() != 978 ) { FAIL("iteration 978"); exit(0); }
+       if ( do_979() != 979 ) { FAIL("iteration 979"); exit(0); }
+       if ( do_980() != 980 ) { FAIL("iteration 980"); exit(0); }
+       if ( do_981() != 981 ) { FAIL("iteration 981"); exit(0); }
+       if ( do_982() != 982 ) { FAIL("iteration 982"); exit(0); }
+       if ( do_983() != 983 ) { FAIL("iteration 983"); exit(0); }
+       if ( do_984() != 984 ) { FAIL("iteration 984"); exit(0); }
+       if ( do_985() != 985 ) { FAIL("iteration 985"); exit(0); }
+       if ( do_986() != 986 ) { FAIL("iteration 986"); exit(0); }
+       if ( do_987() != 987 ) { FAIL("iteration 987"); exit(0); }
+       if ( do_988() != 988 ) { FAIL("iteration 988"); exit(0); }
+       if ( do_989() != 989 ) { FAIL("iteration 989"); exit(0); }
+       if ( do_990() != 990 ) { FAIL("iteration 990"); exit(0); }
+       if ( do_991() != 991 ) { FAIL("iteration 991"); exit(0); }
+       if ( do_992() != 992 ) { FAIL("iteration 992"); exit(0); }
+       if ( do_993() != 993 ) { FAIL("iteration 993"); exit(0); }
+       if ( do_994() != 994 ) { FAIL("iteration 994"); exit(0); }
+       if ( do_995() != 995 ) { FAIL("iteration 995"); exit(0); }
+       if ( do_996() != 996 ) { FAIL("iteration 996"); exit(0); }
+       if ( do_997() != 997 ) { FAIL("iteration 997"); exit(0); }
+       if ( do_998() != 998 ) { FAIL("iteration 998"); exit(0); }
+       if ( do_999() != 999 ) { FAIL("iteration 999"); exit(0); }
+       return NULL;
+}
+
+
+int main()
+{
+       pthread_t worker[10];
+       for (int i=0; i < 10; ++i) {
+               if ( pthread_create(&worker[i], NULL, work, NULL) != 0 ) {
+                       FAIL("pthread_create failed");
+                       exit(0);
+               }
+       }
+               
+       void* result;
+       for (int i=0; i < 10; ++i) {
+               pthread_join(worker[i], &result);
+       }
+       
+       PASS("thread-lazy-bind");
+       return 0;
+}
diff --git a/unit-tests/test-cases/trie-symbol-overrun/Makefile b/unit-tests/test-cases/trie-symbol-overrun/Makefile
new file mode 100644 (file)
index 0000000..41fe1c1
--- /dev/null
@@ -0,0 +1,43 @@
+##
+# 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 foo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c foo.dylib -Wno-deprecated-declarations
+
+
+foo.dylib : foo.c
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o foo.dylib
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main foo.dylib
+
diff --git a/unit-tests/test-cases/trie-symbol-overrun/foo.c b/unit-tests/test-cases/trie-symbol-overrun/foo.c
new file mode 100644 (file)
index 0000000..62d5f38
--- /dev/null
@@ -0,0 +1,12 @@
+
+void abc()
+{
+}
+
+void abcdefghi()
+{
+}
+
+void abcdee()
+{
+}
diff --git a/unit-tests/test-cases/trie-symbol-overrun/main.c b/unit-tests/test-cases/trie-symbol-overrun/main.c
new file mode 100644 (file)
index 0000000..34d1a63
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <mach-o/dyld.h>
+#include <mach/mach.h>
+#include <sys/mman.h>
+
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+
+int main()
+{
+       // allocate two pages
+       vm_address_t addr = 0;
+       kern_return_t r = vm_allocate(mach_task_self(), &addr, 8192, VM_FLAGS_ANYWHERE);
+       if ( r != KERN_SUCCESS )  {
+               FAIL("vm_allocate returned %d", r);
+               exit(0);
+       }
+       // mark the second page unreadable
+       mprotect((char*)(addr+4096), 4096, 0);
+       // copy a string to the end of the first page
+       char* sym = (char*)(addr+4096-5);
+       strcpy(sym, "_abd");
+
+       // 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
+       _dyld_lookup_and_bind(sym, NULL, NULL);
+  
+       PASS("trie-symbol-overrun");
+       return EXIT_SUCCESS;
+}
index fd4ad9bdf7ab085a022aeadc6759c87fd5633af3..42459e6f17408aadefeedfea26a9ea34634161f4 100644 (file)
@@ -31,8 +31,9 @@ include ${TESTROOT}/include/common.makefile
 ### so the next use of libfoo seemed to succeed, when it should have failed.
 ###
 
+all-check: all check
 
-run: all
+check:
        export DYLD_IMAGE_SUFFIX="_missing" && ./main
 
 all: main libfoo.dylib
index 4f38eebd663d5957533045a0b392814278fe86c6..253ea75fc764e5b347866633a53945a50f8f3ad5 100644 (file)
@@ -24,12 +24,13 @@ TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
 
-run: all
+all-check: all check
+
+check:
        ./dynamic-test
 
 all: dynamic-test  static-test
 
-
 static-test: a1.o a2.o main.o
        $(CXX) -I${TESTROOT}/include a1.o a2.o main.o -o static-test
 
index 13bdf3720e3edbe5280e314033b7afa7913b646c..543a5be4a15f43395278a48c0cab1b7f167648b1 100644 (file)
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
+all-check: all check
 
-run: all
+check:
        ./main
 
 all: main
 
-
 main: main.c libfoo1.dylib libbase.dylib
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libfoo1.dylib libbase.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libfoo1.dylib libbase.dylib 
 
 libfoo1.dylib: foo1.c libfoo2.dylib libbase.dylib
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -single_module -o libfoo1.dylib foo1.c libfoo2.dylib libbase.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -single_module -o libfoo1.dylib foo1.c libfoo2.dylib libbase.dylib 
 
 libfoo2.dylib: foo2.c libfoo3.dylib libbase.dylib
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -single_module -o libfoo2.dylib foo2.c libfoo3.dylib libbase.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -single_module -o libfoo2.dylib foo2.c libfoo3.dylib libbase.dylib 
 
 libfoo3.dylib: foo3.c libbase.dylib
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -single_module -o libfoo3.dylib foo3.c libbase.dylib -prebind -seg1addr 20000
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -single_module -o libfoo3.dylib foo3.c libbase.dylib -prebind -seg1addr 20000 
 
 libbase.dylib: base.c
-       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -single_module -o libbase.dylib base.c -prebind -seg1addr 10000
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -single_module -o libbase.dylib base.c -prebind -seg1addr 10000 
 
 
 
diff --git a/unit-tests/test-cases/weak-external-reloc-flat/Makefile b/unit-tests/test-cases/weak-external-reloc-flat/Makefile
new file mode 100644 (file)
index 0000000..b1e95b2
--- /dev/null
@@ -0,0 +1,34 @@
+
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# <rdar://problem/6369189> flat_namespace and weak binding conflict
+#
+# Note that libfoo.dylib is built flat-namespace
+#
+
+all-check: all check
+
+check:
+       ./main
+
+all: main
+
+main: main.c libfoo.dylib 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libfoo.dylib 
+
+libfoo.dylib: foo.c  libbar.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o libfoo.dylib foo.c  libbar.dylib -flat_namespace
+
+libbar.dylib: bar.c  libbaz.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o libbar.dylib bar.c  libbaz.dylib
+
+libbaz.dylib: baz.c 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o libbaz.dylib baz.c 
+
+clean:
+       ${RM} ${RMFLAGS} *~ main  libfoo.dylib libbar.dylib libbaz.dylib
+
diff --git a/unit-tests/test-cases/weak-external-reloc-flat/bar.c b/unit-tests/test-cases/weak-external-reloc-flat/bar.c
new file mode 100644 (file)
index 0000000..4787d5b
--- /dev/null
@@ -0,0 +1,8 @@
+
+
+int bar[] = { 20, 21, 22, 23 };
+
+
+int __attribute__((weak)) frob[] = { 30, 31, 32, 33 };
+
+int bar_getfrob(int x) { return frob[x]; }
diff --git a/unit-tests/test-cases/weak-external-reloc-flat/baz.c b/unit-tests/test-cases/weak-external-reloc-flat/baz.c
new file mode 100644 (file)
index 0000000..f35d05c
--- /dev/null
@@ -0,0 +1,8 @@
+
+
+
+
+
+int __attribute__((weak)) bar[] = { 30, 31, 32, 33 };
+
+
diff --git a/unit-tests/test-cases/weak-external-reloc-flat/foo.c b/unit-tests/test-cases/weak-external-reloc-flat/foo.c
new file mode 100644 (file)
index 0000000..d2d73ef
--- /dev/null
@@ -0,0 +1,14 @@
+
+
+extern int bar_getfrob(int x);
+
+
+int __attribute__((weak)) foo[] = { 1, 2, 3, 4 };
+int __attribute__((weak)) bar[] = { 10, 11, 12, 13 };
+int __attribute__((weak)) frob[] = { 20, 21, 22, 23 };
+
+int* pfoo = &foo[2];
+
+int getfrob() {
+       return bar_getfrob(2);
+}
\ No newline at end of file
diff --git a/unit-tests/test-cases/weak-external-reloc-flat/main.c b/unit-tests/test-cases/weak-external-reloc-flat/main.c
new file mode 100644 (file)
index 0000000..e74b44d
--- /dev/null
@@ -0,0 +1,41 @@
+
+
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+// pfoo is in libfoo.dylib
+// libfoo.dylib also has weak foo[]
+// pfoo should be rebound to point into the foo[] in main
+int foo[] = { 5, 6, 7, 8 };
+extern int* pfoo;
+
+// libfoo.dylib has a weak bar[]
+// libbar.dylib has a strong bar[]
+// at build  time linker  only sees weak bar in libfoo.dylib
+// at runtime, dyld uses strong bar in libbar.dylib
+extern int bar[];
+int* pbar = &bar[1];
+
+
+// libfoo.dylib has a weak frob[]
+// libbar.dylib has a weak frob[] and a funtion that refrences frob[]
+// the function should use libfoo's frob[] even if libfoo is flat
+extern int getfrob();
+
+int main()
+{
+       if ( *pfoo != 7 )
+               FAIL("weak-external-reloc-flat, pfoo=%d", *pfoo);
+       else if ( *pbar != 21 ) 
+               FAIL("weak-external-reloc-flat, pbar=%d", *pbar);
+       else if ( getfrob() != 22 ) 
+               FAIL("weak-external-reloc-flat, frob()=%d", getfrob());
+       else
+               PASS("weak-external-reloc-flat");
+       
+       return EXIT_SUCCESS;
+}
+
+
diff --git a/unit-tests/test-cases/weak-external-reloc/Makefile b/unit-tests/test-cases/weak-external-reloc/Makefile
new file mode 100644 (file)
index 0000000..b01a66b
--- /dev/null
@@ -0,0 +1,30 @@
+
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+all-check: all check
+
+check:
+       ./main
+
+all: main
+
+main: main.c librealmain.dylib 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c librealmain.dylib 
+
+librealmain.dylib: realmain.c  libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o librealmain.dylib realmain.c libfoo.dylib
+
+libfoo.dylib: foo.c  libbar.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o libfoo.dylib foo.c  libbar.dylib
+
+libbar.dylib: bar.c  libbaz.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o libbar.dylib bar.c  libbaz.dylib
+
+libbaz.dylib: baz.c 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o libbaz.dylib baz.c 
+
+clean:
+       ${RM} ${RMFLAGS} *~ main  libfoo.dylib libbar.dylib libbaz.dylib librealmain.dylib
+
diff --git a/unit-tests/test-cases/weak-external-reloc/bar.c b/unit-tests/test-cases/weak-external-reloc/bar.c
new file mode 100644 (file)
index 0000000..615196e
--- /dev/null
@@ -0,0 +1,6 @@
+
+
+int bar[] = { 20, 21, 22, 23 };
+
+// needs something weak to join coalescing
+int __attribute__((weak)) junk = 5;
diff --git a/unit-tests/test-cases/weak-external-reloc/baz.c b/unit-tests/test-cases/weak-external-reloc/baz.c
new file mode 100644 (file)
index 0000000..f35d05c
--- /dev/null
@@ -0,0 +1,8 @@
+
+
+
+
+
+int __attribute__((weak)) bar[] = { 30, 31, 32, 33 };
+
+
diff --git a/unit-tests/test-cases/weak-external-reloc/foo.c b/unit-tests/test-cases/weak-external-reloc/foo.c
new file mode 100644 (file)
index 0000000..9e4873a
--- /dev/null
@@ -0,0 +1,10 @@
+
+
+
+
+
+int __attribute__((weak)) foo[] = { 1, 2, 3, 4 };
+int __attribute__((weak)) bar[] = { 10, 11, 12, 13 };
+
+int* pfoo = &foo[2];
+
diff --git a/unit-tests/test-cases/weak-external-reloc/main.c b/unit-tests/test-cases/weak-external-reloc/main.c
new file mode 100644 (file)
index 0000000..a25c448
--- /dev/null
@@ -0,0 +1,10 @@
+
+extern void realmain();
+
+int main()
+{
+       realmain();
+       return 0;
+}
+
+
diff --git a/unit-tests/test-cases/weak-external-reloc/realmain.c b/unit-tests/test-cases/weak-external-reloc/realmain.c
new file mode 100644 (file)
index 0000000..6870f5a
--- /dev/null
@@ -0,0 +1,39 @@
+
+
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+// pfoo is in libfoo.dylib
+// libfoo.dylib also has weak foo[]
+// pfoo should be rebound to point into the foo[] in main
+int foo[] = { 5, 6, 7, 8 };
+extern int* pfoo;
+
+// libfoo.dylib has a weak bar[]
+// libbar.dylib has a strong bar[]
+// at build  time linker  only sees weak bar in libfoo.dylib
+// at runtime, dyld uses strong bar in libbar.dylib
+extern int bar[];
+int* pbar = &bar[1];
+
+// there is only one stuff, but it is weak
+// so we are testing the case when stuff is not overridden
+int __attribute__((weak)) stuff[] = { 1, 2, 3, 4, 5 };
+int* pstuff = &stuff[3];
+
+
+void realmain()
+{
+       if ( *pfoo != 7 )
+               FAIL("weak-external-reloc, pfoo=%d", *pfoo);
+       else if ( *pbar != 21 ) 
+               FAIL("weak-external-reloc, pbar=%d", *pbar);
+       else if ( *pstuff != 4 ) 
+               FAIL("weak-external-reloc, pstuffr=%d", *pstuff);
+       else
+               PASS("weak-external-reloc");
+}
+
+
diff --git a/unit-tests/test-cases/weak-in-dylib/Makefile b/unit-tests/test-cases/weak-in-dylib/Makefile
new file mode 100644 (file)
index 0000000..cd54661
--- /dev/null
@@ -0,0 +1,21 @@
+
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+all-check: all check
+
+check:
+       ./main
+
+all: main
+
+main: main.c libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libfoo.dylib 
+
+libfoo.dylib: foo.c  
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o libfoo.dylib foo.c  
+
+clean:
+       ${RM} ${RMFLAGS} *~ main  libfoo.dylib 
+
diff --git a/unit-tests/test-cases/weak-in-dylib/foo.c b/unit-tests/test-cases/weak-in-dylib/foo.c
new file mode 100644 (file)
index 0000000..ec6f836
--- /dev/null
@@ -0,0 +1,7 @@
+
+
+
+
+
+int __attribute__((weak)) foo[] = { 1, 2, 3, 4 };
+
diff --git a/unit-tests/test-cases/weak-in-dylib/main.c b/unit-tests/test-cases/weak-in-dylib/main.c
new file mode 100644 (file)
index 0000000..358e0f7
--- /dev/null
@@ -0,0 +1,22 @@
+
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+// libfoo.dylib has a weak foo[]
+extern int foo[];
+
+int* pfoo3 = &foo[3];
+
+int main()
+{
+       if ( *pfoo3 != 4 )
+               FAIL("weak-in-dylib, pfoo3=%d", *pfoo3);
+       else if ( foo[2] != 3 ) 
+               FAIL("weak-in-dylib, foo[2]=%d", foo[2]);
+       else
+               PASS("weak-in-dyliby");
+       return 0;
+}
+
diff --git a/unit-tests/test-cases/weak-lazy-slidable/Makefile b/unit-tests/test-cases/weak-lazy-slidable/Makefile
new file mode 100644 (file)
index 0000000..274962b
--- /dev/null
@@ -0,0 +1,31 @@
+
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+all-check: all check
+
+check:
+       ./main
+
+all: main
+
+main: main.c libfoo.dylib  libother.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libother.dylib libfoo.dylib 
+
+libother.dylib: foo.c  
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o libother.dylib other.c
+
+libfoo.dylib: foo.c  libbar.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o libfoo.dylib foo.c  libbar.dylib
+
+libbar.dylib: bar.c libbar3.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o libbar.dylib bar.c  libbar3.dylib
+
+libbar3.dylib: bar3.c 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o libbar3.dylib bar3.c 
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main  libfoo.dylib libbar.dylib libbar3.dylib libother.dylib
+
diff --git a/unit-tests/test-cases/weak-lazy-slidable/bar.c b/unit-tests/test-cases/weak-lazy-slidable/bar.c
new file mode 100644 (file)
index 0000000..e52bf11
--- /dev/null
@@ -0,0 +1,12 @@
+
+
+#include <stdbool.h> 
+
+bool bar1()
+{
+       return true;
+}
+
+__attribute__((weak)) void junk()
+{
+}
diff --git a/unit-tests/test-cases/weak-lazy-slidable/bar3.c b/unit-tests/test-cases/weak-lazy-slidable/bar3.c
new file mode 100644 (file)
index 0000000..0f27868
--- /dev/null
@@ -0,0 +1,9 @@
+
+
+#include <stdbool.h> 
+
+__attribute__((weak)) bool bar1()
+{
+       return false;
+}
+
diff --git a/unit-tests/test-cases/weak-lazy-slidable/foo.c b/unit-tests/test-cases/weak-lazy-slidable/foo.c
new file mode 100644 (file)
index 0000000..7e3c8a5
--- /dev/null
@@ -0,0 +1,29 @@
+#include <stdbool.h> 
+
+
+
+extern bool bar1();
+
+
+__attribute__((weak)) bool bar1()
+{
+       return false;
+}
+
+__attribute__((weak)) bool bar2()
+{
+       return true;
+}
+
+
+bool foo1()
+{
+       return bar1();
+}
+
+bool foo2()
+{
+       return bar2();
+}
+
+
diff --git a/unit-tests/test-cases/weak-lazy-slidable/main.c b/unit-tests/test-cases/weak-lazy-slidable/main.c
new file mode 100644 (file)
index 0000000..a91ef85
--- /dev/null
@@ -0,0 +1,24 @@
+
+
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <stdbool.h> 
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+extern bool foo1();
+extern bool foo2();
+
+
+int main()
+{
+       if ( foo1() && foo2() ) 
+               PASS("weak-lazy-slidable");
+       else
+               FAIL("weak-lazy-slidable");
+                       
+       return EXIT_SUCCESS;
+}
+
+
diff --git a/unit-tests/test-cases/weak-lazy-slidable/other.c b/unit-tests/test-cases/weak-lazy-slidable/other.c
new file mode 100644 (file)
index 0000000..0c04195
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdbool.h>
+
+bool bar2()
+{
+       return false;
+}
+
index b4eb71ca1c3fc74e20e6b4deadff5a109d2c6347..1d1863e400d51af58ebd74879af967a91d8ab11f 100644 (file)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2005-2008 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
-       cd absent/  && ../${TESTROOT}/bin/exit-zero-pass.pl "pass message" "fail message" ./main
-       cd present/ && ../${TESTROOT}/bin/exit-zero-pass.pl "pass message" "fail message" ./main
+all-check: all check
+
+check:
+       cd absent/  && ../${TESTROOT}/bin/exit-zero-pass.pl "weak-library" "weak-library" ./main
+       cd present/ && ../${TESTROOT}/bin/exit-zero-pass.pl "weak-library" "weak-library" ./main
 
 all: foo.c main.c
        ${CC} -dynamiclib -prebind -seg1addr 400000 -o libfoo.dylib foo.c
        mkdir -p absent/
-       export MACOSX_DEPLOYMENT_TARGET=10.2 && ${CC} -prebind -I${TESTROOT}/include -L. -Wl,-weak-lfoo -o absent/main main.c
+       ${CC} -prebind -I${TESTROOT}/include -L. -Wl,-weak-lfoo -o absent/main main.c
        mkdir -p present/
-       export MACOSX_DEPLOYMENT_TARGET=10.2 && ${CC} -prebind -I${TESTROOT}/include -L. -Wl,-weak-lfoo -o present/main main.c
+       ${CC} -prebind -I${TESTROOT}/include -L. -Wl,-weak-lfoo -o present/main main.c
        mv libfoo.dylib present/
 
 clean:
diff --git a/unit-tests/test-cases/weak-non-lazy/Makefile b/unit-tests/test-cases/weak-non-lazy/Makefile
new file mode 100644 (file)
index 0000000..c3d1b70
--- /dev/null
@@ -0,0 +1,30 @@
+
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+all-check: all check
+
+check:
+       ./main
+
+all: main
+
+main: main.c librealmain.dylib 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c librealmain.dylib 
+
+librealmain.dylib: realmain.c  libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o librealmain.dylib realmain.c libfoo.dylib
+
+libfoo.dylib: foo.c  libbar.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o libfoo.dylib foo.c  libbar.dylib
+
+libbar.dylib: bar.c libbaz.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o libbar.dylib bar.c  libbaz.dylib
+
+libbaz.dylib: baz.c 
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -dynamiclib -o libbaz.dylib baz.c 
+
+clean:
+       ${RM} ${RMFLAGS} *~ main  libfoo.dylib libbar.dylib libbaz.dylib librealmain.dylib
+
diff --git a/unit-tests/test-cases/weak-non-lazy/bar.c b/unit-tests/test-cases/weak-non-lazy/bar.c
new file mode 100644 (file)
index 0000000..9db55bd
--- /dev/null
@@ -0,0 +1,6 @@
+
+
+int bar[] = { 20, 21, 22, 23 };
+
+// needs something weak to join coalescing fun
+int __attribute__((weak)) junk = 5;
diff --git a/unit-tests/test-cases/weak-non-lazy/baz.c b/unit-tests/test-cases/weak-non-lazy/baz.c
new file mode 100644 (file)
index 0000000..411ae68
--- /dev/null
@@ -0,0 +1,9 @@
+
+
+
+
+
+int __attribute__((weak)) bar[] = { 30, 31, 32, 33 };
+
+
+
diff --git a/unit-tests/test-cases/weak-non-lazy/foo.c b/unit-tests/test-cases/weak-non-lazy/foo.c
new file mode 100644 (file)
index 0000000..a212684
--- /dev/null
@@ -0,0 +1,15 @@
+
+
+
+
+
+int __attribute__((weak)) foo[] = { 1, 2, 3, 4 };
+int __attribute__((weak)) bar[] = { 10, 11, 12, 13 };
+
+int* getfoo()
+{
+       return foo;
+}
+
+
+
diff --git a/unit-tests/test-cases/weak-non-lazy/main.c b/unit-tests/test-cases/weak-non-lazy/main.c
new file mode 100644 (file)
index 0000000..523b7be
--- /dev/null
@@ -0,0 +1,12 @@
+
+
+// put test code in a dylib so that is slides
+extern void realmain();
+
+int main()
+{
+       realmain();
+       return 0;
+}
+
+
diff --git a/unit-tests/test-cases/weak-non-lazy/realmain.c b/unit-tests/test-cases/weak-non-lazy/realmain.c
new file mode 100644 (file)
index 0000000..ca4a6f2
--- /dev/null
@@ -0,0 +1,36 @@
+
+
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+// getfoo() is in libfoo.dylib and uses a non-lazy pointer to reference foo
+// libfoo.dylib also has weak foo[]
+// getfoo() should be rebound to point into the foo[] in main
+int foo[] = { 5, 6, 7, 8 };
+extern int* getfoo();
+
+// libfoo.dylib has a weak bar[]
+// libbar.dylib has a strong bar[]
+// at build time linker only sees weak bar in libfoo.dylib
+// at runtime, dyld uses strong bar in libbar.dylib
+extern int bar[];
+
+
+int __attribute__((weak)) stuff[] = { 1, 2, 3, 4, 5 };
+
+
+void realmain()
+{
+       if ( getfoo()[2] != 7 )
+               FAIL("weak-non-lazy, getfoo()[2]=%d", getfoo()[2]);
+       else if ( bar[1] != 21 ) 
+               FAIL("weak-non-lazy, bar[1]=%d", bar[1]);
+       else if ( stuff[3] != 4 ) 
+               FAIL("weak-external-reloc, pstuffr=%d", stuff[3]);
+       else
+               PASS("weak-non-lazy");
+}
+
+
index 26f8617bc15971dc5853cb606bf93c5ffef85c56..8d7799fdb77981959eb0ad0c40d41d2f8130e630 100644 (file)
@@ -23,8 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
+all-check: all check
 
-run: all
+check:
        ./main
 
 all: main
index dcce76ef9aee78c48661ef3859e0ec4f2d933666..984ee82a0504df8f1a7cf41186a9ada9198747e1 100644 (file)
@@ -33,3 +33,10 @@ int __attribute__((weak)) foo()
 {
        return myfunc();
 }
+
+int (*myfuncproc)() = &myfunc;
+
+int  bar()
+{
+       return (*myfuncproc)();
+}
index 372c29aa877000fa7760b941e838796f645aec1b..8010cc0efa2acee5e560ade3a1430e47d2c85790 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2008 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 
 #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
 
-// foo is defined in libfoo.dylib
-// it calls myfunc() 
+// foo is defined in libfoo.dylib it calls myfunc() 
 extern int foo();
-
-// add this so WEAK_DEFINES is set, so dyld searchs this image
-int __attribute__((weak)) junk = 2;
+// bar is defined in libfoo.dylib it calls myfunc() 
+extern int bar();
 
 int main()
 {
-       if ( foo() == 10 )
+       if ( (foo() == 10) && (bar() == 10) )
                PASS("weak-override");
        else
                FAIL("weak-override");
index ba1d7aaf805b4da5efe8b0902855ff538894f0f3..dfd56ce6fd9eac64ee24ccaf0f22507910e9be79 100644 (file)
@@ -1,4 +1,4 @@
-##
+#
 # Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+all-check: all check
+
+check:
        (export DYLD_IMAGE_SUFFIX=_missing  && ./main) || echo "FAIL \"weak-symbol-flat\""
         ./main 1
 
-all : main libfoo.dylib libfoo_missing.dylib
+all: main libfoo.dylib libfoo_missing.dylib
 
 libfoo.dylib : foo.c 
        ${CC} -dynamiclib -DSYMBOL_PRESENT -o libfoo.dylib foo.c
@@ -36,7 +38,7 @@ libfoo_missing.dylib : foo.c
        ${CC} -dynamiclib -o libfoo_missing.dylib foo.c -install_name libfoo.dylib
 
 main: main.c libfoo.dylib
-       ${CC} -I${TESTROOT}/include -mmacosx-version-min=10.2 -L. -lfoo -o main  main.c -flat_namespace
+       ${CC} -I${TESTROOT}/include -L. -lfoo -o main  main.c -flat_namespace
 
 clean:
        ${RM} ${RMFLAGS} *~ libfoo.dylib libfoo_missing.dylib main
index e24ee5229faf4563fc2361a7bd2a60ecf5488d49..f2d1cec86be467812113eb8dc66bef88c03126b3 100644 (file)
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-run: all
+
+all-check: all check
+
+check:
        export DYLD_IMAGE_SUFFIX=_missing && ${TESTROOT}/bin/exit-zero-pass.pl "weak-symbol" "weak-symbol" ./main
 
 all: foo.c main.c
        ${CC} foo.c -dynamiclib -o libfoo.dylib  -DSYMBOL_PRESENT 
        ${CC} foo.c -dynamiclib -o libfoo_missing.dylib -install_name libfoo.dylib
-       export MACOSX_DEPLOYMENT_TARGET=10.2 && ${CC} -I${TESTROOT}/include -L. -lfoo main.c -o main  
+       ${CC} -I${TESTROOT}/include -L. -lfoo main.c -o main  
 
 clean:
        ${RM} ${RMFLAGS} *~ libfoo.dylib libfoo_missing.dylib main
diff --git a/unit-tests/test-cases/weak_import/Makefile b/unit-tests/test-cases/weak_import/Makefile
new file mode 100644 (file)
index 0000000..7833962
--- /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
+
+#
+# Test the weak_import attribute works
+#
+
+all-check: all check
+
+check:
+       ./main
+       export DYLD_IMAGE_SUFFIX=_some  && ./main missing
+
+all: main libfoo_some.dylib
+
+
+main : main.c libfoo.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c libfoo.dylib
+
+libfoo.dylib : foo.c
+       ${CC} ${CCFLAGS} foo.c -DALL_SYMBOLS=1 -dynamiclib -o libfoo.dylib 
+
+libfoo_some.dylib : foo.c
+       ${CC} ${CCFLAGS} foo.c  -dynamiclib -o libfoo_some.dylib  -install_name libfoo.dylib
+
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libfoo.dylib libfoo_some.dylib
diff --git a/unit-tests/test-cases/weak_import/foo.c b/unit-tests/test-cases/weak_import/foo.c
new file mode 100644 (file)
index 0000000..8f50835
--- /dev/null
@@ -0,0 +1,19 @@
+
+
+#include "foo.h"
+
+void func1() {}
+void func3() {}
+int data1 = 0;
+int data3;
+int data5 = 0;
+
+#if ALL_SYMBOLS
+void func2() {}
+void func4() {}
+
+int data2 = 0; // weak_import initialized
+int data4;             // weak_import uninitialized
+int data6 = 0; // weak_import 
+#endif
+
diff --git a/unit-tests/test-cases/weak_import/foo.h b/unit-tests/test-cases/weak_import/foo.h
new file mode 100644 (file)
index 0000000..f455515
--- /dev/null
@@ -0,0 +1,16 @@
+
+
+extern void func1();
+extern void func2() __attribute__((weak_import));
+extern void func3();
+extern void func4() __attribute__((weak_import));
+
+extern int data1;
+extern int data2 __attribute__((weak_import));
+extern int data3;
+extern int data4 __attribute__((weak_import));
+extern int data5;
+extern int data6 __attribute__((weak_import));
+
+
+
diff --git a/unit-tests/test-cases/weak_import/main.c b/unit-tests/test-cases/weak_import/main.c
new file mode 100644 (file)
index 0000000..a777a52
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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 <stdbool.h>
+#include <mach-o/dyld.h>
+
+#include "test.h" // PASS(), FAIL()
+
+#include "foo.h"
+
+
+int* pdata5 = &data5;
+int* pdata6 = &data6;
+
+
+int main(int argc, const char* argv[])
+{
+       if ( argc > 1 ) {
+               // this weak case where the even symbol names are missing at runtime
+               func1();
+               func3();
+               data1 = data3;
+               if ( (&func2 == NULL) && (&func4 == NULL) && (&data2 == NULL) && (&data4 == NULL) && (pdata6 == NULL) )
+                       PASS("weak_import");
+               else
+                       FAIL("weak_import");
+       }
+       else {
+               // this is the regular case where all symbols exist at runtime
+               func1();
+               func2();
+               func3();
+               func4();
+               data1 = data2 + data3 + data4;
+               PASS("weak_import");
+       }
+       return 0;
+}
+
index 513cd755f21322c9f3cccdfbd51018ebaee9fa77..f0380c7c52d70845cd9124cc39e1158b9646ed7b 100644 (file)
@@ -23,8 +23,9 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
+all-check: all check
 
-run: all
+check:
        ./main 
 
 all: main
index 9d8b5cb3141c31dd532b690eb5ba5c2b85afe670..297c76037390681d8b67333b633de5b04f38cb40 100644 (file)
@@ -25,7 +25,10 @@ include ${TESTROOT}/include/common.makefile
 
 SHELL = bash # use bash shell so we can redirect just stderr
 
-run: all
+
+all-check: all check
+
+check:
        export DYLD_PRINT_SEGMENTS=1 && ./main  2> segments.log
        grep __FOOBAR segments.log > /dev/null || echo "PASS zero-length-segment"
        (grep __FOOBAR segments.log > /dev/null && echo "FAIL zero-length-segment") || /usr/bin/true